Desconstruir uma linha em duas linhas com base em colunas específicas

1

Eu tenho um arquivo .tsv ( batch_1.catalog.tags.tsv ) consistindo de 1.965.056 linhas de 14 colunas . Eu quero dividir alguns deles em duas linhas .

A primeira linha : começa com um sinal maior que (>) seguido por 8 das 14 colunas
A segunda linha : somente coluna 10

>column3(a number) column4(numbers and letters) column5(a number) column6(- or +) column11(0 or 1) column12(0 or 1) column13(0 or 1) column14(0 or 1)       
column10(string with As,Ts,Gs,Cs, and sometimes Ns)    

Aqui está um exemplo da sexta linha do arquivo .tsv , conforme especificado pela terceira coluna:

0   1   6   gi|586799556|ref|NW_006530744.1|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    0   0   0   0    

Isso é o que eu gostaria:

>6 gi|586799556|ref|NW_006530744.1| 141 +  0 0 0 0        
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    

No entanto, só quero fazer isso com linhas no arquivo tsv (batch_1.catalog.tags.tsv) que tenham um número de terceira coluna que corresponda aos números em um arquivo de texto diferente (whitelist.txt) .

No exemplo acima, o arquivo whitelist.txt conteria o número 6, embora haja mais de 8000 linhas com diferentes números de terceira coluna (ou seja, IDs). O whitelist.txt inclui números de até 6 dígitos.

Eu tenho tentado uma abordagem alternativa. Recebi o código abaixo para usar a lista de permissões para retirar a coluna 10 do arquivo .tsv . No entanto, o grep continuou por 10 horas e não fez nada (vazio cat.fa file).

cat whitelist.txt | while read line; do zgrep "^0    1       $line   " batch_1.catalog.tags.tsv.gz; done | cut -f 3,10 | sed -E -e's/^([0-9]+)       ([ACGTN]+)$/>Z/' | tr "Z" "\n" > cat.fa    

Ambas as soluções abaixo usando awk ou perl funcionam perfeitamente. Os IDs também são impressos em ordem, embora não estejam em ordem na lista de permissões. A solução perl imprime as linhas delimitadas por tabulações enquanto awk as imprime delimitadas por espaços.

    
por Age87 07.05.2017 / 04:34

2 respostas

2
Solução

awk :

Supondo um fragmento de teste do arquivo batch_1.catalog.tags.tsv :

0   1   6   gi|586799556|ref|NW_006530744.1|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    0   0   0   0
1   2   7   hi|686711556|ref|NW_006530744.2|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   1   0   1
2   2   8   hi|686711556|ref|NW_006530744.2|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   1   1   1
3   3   9   th|776711556|ref|NW_006530744.2|    141 +   consensus   1   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   0   1   1

E um fragmento de teste do arquivo whitelight.txt :

6
7
9

O comando:

awk 'NR==FNR{ a[$0]++; next }{ if ($3 in a) { 
     $0=">"$3 FS $4 FS $5 FS $6 FS $11 FS $12 FS $13 FS $14 RS $10; print}}' whitelist.txt batch_1.catalog.tags.tsv > cat.fa

Conteúdo final de cat.fa :

>6 gi|586799556|ref|NW_006530744.1| 141 + 0 0 0 0
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC
>7 hi|686711556|ref|NW_006530744.2| 141 + 1 1 0 1
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC
>9 th|776711556|ref|NW_006530744.2| 141 + 1 0 1 1
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC

Detalhes :

NR==FNR - executa a ação para o primeiro arquivo, por exemplo, whitelight.txt

a[$0]++; - acumulando números do arquivo whitelight.txt

if ($3 in a) - permite ação se um valor da 3ª coluna do 2º arquivo corresponder a qualquer um dos números acumulados

RS - separador de registros do awk, padrão para o caractere de nova linha

    
por 07.05.2017 / 09:25
4
perl -F'\t+' -lane '
   @ARGV and $h{$F[0]}++,next;
   print ">", join("\t", @F[2..5,-4..-1]), $\, $F[9] if exists $h{$F[2]};
' whitelist.txt batch_1.catalog.tags.tsv

Assumindo que seu arquivo é separado por TAB.

Note que se seu arquivo pode ter janelas ou terminações de linha mac então é prudente primeiro convertê-los em finais de linha unix ("\ n") através dos utilitários dos2unix, etc. Por muitas vezes tem sido visto que o código fornecido não funciona no final do OP devido a razões como essas.

Funcionamentos

  • Observe quando Perl está processando o primeiro argumento (nesse caso, whitelight.txt , então @ARGV contém batch_1.catalog.tsv file, ou seja, @ARGV = 1 = > @ARGV é avaliado como TRUE no contexto booleano.
  • @ARGV and $h{$F[0]}++,next deve ser interpretado como: quando estivermos processando o arquivo whitelight, inclua o primeiro campo ( $F[0] ) desse arquivo no hash %h e, em seguida, vá imediatamente para a próxima linha.
  • Quaisquer linhas abaixo delas processarão o arquivo TSV, já que @ARGV não contém nada, então a contagem é zero.
  • Apenas os registros do arquivo TSV devem ser obtidos para que o terceiro campo $F[2] seja uma chave no %h hash.
  • Após a decisão de imprimir um registro TSV, o formato da impressão é: (Nota: O OFS padrão para uma impressão é NULL )
  • ">" , $F[2] significando que o terceiro campo é precedido por >
  • campos 4,5,6 = > @F[3..5] será separado e unido por TAB.
  • últimos 4 campos = > @F[-4..-1] será separado e unido por TAB.
  • O décimo campo $F[9] será precedido por uma nova linha, que é fornecida pelo $\ = ORS = \n devido à Perl option -l .
por 07.05.2017 / 04:58