Listar todas as strings únicas em uma coluna específica

1

Eu não sei o que eu tenho no meu enorme arquivo vcf.gz que se parece com isso

CHROM       POS         ALT     12345       
1           345632      T       0/1:4,4:8:99:105,0,106
4           032184      C       1/1:46,9:55:99:99,0,1222
6           843290      A       0/1:67,20:87:99:336,0,1641
7           743290      C       0/1:37,20:57:99:336,0,2641
8           329283      T       0/2:99:21:253,0,290:11,10
9           789320      C       2/2:99:21:253,0,290:11,10

Eu gostaria de extrair todos os valores exclusivos na 4ª coluna antes do ":". Isso é neste caso:

0/1
1/1
0/2
2/2

Você tem alguma sugestão?

    
por Sanna 24.11.2016 / 14:15

5 respostas

3

Com awk , verificando se a quarta coluna está no formato correto:

awk 'match($4, /^[0-9]+\/[0-9]+:/) {
       c = substr($4, RSTART, RLENGTH-1)
       if (!seen[c]++) print c
     }'
    
por 24.11.2016 / 14:48
0

Vamos supor que as linhas que começam com uma letra sejam comentários ou sejam ignoradas.

zcat vcf.gz | awk \
   'BEGIN {
        RS = "[\t\v\f ]*(\r\n|\n\r|\r|\n)" ;
        FS = "[\t\v\f ]+"
    }

    /^[A-Za-z]/ {
        next
    }

    NF >= 4 {
        key = $4 ;
        sub(/:.*$/, "", key) ;
        seen[key]++
    }

    END {
        for (key in seen)
            printf "%s\n", key
    }'

Você pode escrever o comando inteiro em uma linha (remova o \ no final da primeira linha, por exemplo), porque eu adicionei todos os pontos-e-vírgulas necessários para fazer isso.

A regra BEGIN configura o suporte universal de nova linha. Todos os espaços em branco no final das linhas são ignorados, e qualquer formulário de nova linha (CR, LF, CRLF, LFCR) é aceito como uma nova linha. Qualquer número de tabulações ou espaços são tratados como separadores de campos.

A regra /^[A-Za-z]/ se aplica a todas as linhas que começam com uma letra. O next faz com que eles sejam ignorados.

A próxima regra se aplica a todos os registros (linhas) com pelo menos quatro campos. O quarto campo é copiado para a variável key , então tudo após os primeiros dois pontos (incluindo os dois pontos) é removido. Usamos o valor resultante como uma chave para o array associativo seen . O valor que atribuímos não importa realmente, mas aqui, seen[key] conterá o número de vezes que cada valor foi referido (1 ou mais).

A regra END é executada após toda a entrada ter sido processada. Aqui, o loop itera sobre as chaves de seen[] array (em uma ordem não especificada) e apenas imprime as chaves.

Se você quiser manter o pedido nos dados ou usar uma ordem específica para as chaves, o snippet acima precisa de pequenas modificações.

    
por 24.11.2016 / 14:48
0

Se perl estiver bem:

$ perl -lane '($k) = $F[3] =~ m/^([^:]+)/; print $k if !$seen{$k}++ && $. > 1' ip.txt 
0/1
1/1
0/2
2/2
  • ($k) = $F[3] =~ m/^([^:]+)/ get string antes de : da quarta coluna
  • Em seguida, imprima se for único e não primeira linha (para evitar cabeçalho)


Se o padrão antes de : tiver que ser necessariamente do padrão digits/digits , altere a correspondência para m|^(\d+/\d+):|

    
por 24.11.2016 / 15:06
0

Como um one-liner

gzip -dc input.gz | grep -E "^[0-9]" | cut -f 1 -d : | sort -k 4 -u | awk ' { print $4 } '

Explicação:

* gzip -dc             # decompress and write to standard output   
* grep -E "^[0-9]"     # only look at lines starting with a digit  
* cut -f 1 -d:         # remove the text following the colon  
* sort -k4 -u          # sort on the forth field - uniquely  
* awk ' { print $4 } ' # print the fourth field (that we sorted on)
    
por 24.11.2016 / 15:07
0

Eu usaria:

grep -o -P '.{1}/.{1}' file

No seu caso:

zcat vcf.gz | grep -o -P '.{1}/.{1}' 

Editar: para apenas uma ocorrência, adicione uniq no final da linha:

zcat vcf.gz | grep -o -P './.' | uniq

ou se você quiser em ordem:

zcat vcf.gz | grep -o -P './.' | sort -u

    
por 24.11.2016 / 14:42