
Existe uma maneira eficiente de analisar um arquivo como:
2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
para:
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
O padrão é sempre |||
; - então começa CSQ
e termina com o quinto campo - porém esse campo nem sempre é, missense variant
mas também pode ser algo diferente como kdjdud
.
Existem muitas linhas (mais de 60k) no arquivo e eu precisaria extrair esta tabela tab deli conforme mostrado acima - existe uma solução Python, Perl ou AWK (ou outra coisa) para isso?
Responder1
Vamos usar sed
:
sed -r 's/.*\|\|\|;(CSQ[^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|.*/\1\t\2\t\3\t\4\t\5/' file.txt
python
não é rápido na manipulação de arquivos muito grandes, isso seria muito mais rápido que python
.
Exemplo:
% cat file.txt
2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
% sed -r 's/.*\|\|\|;(CSQ[^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|.*/\1\t\2\t\3\t\4\t\5/' file.txt
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
Responder2
Usando Perl:
perl -F'\|\|\|' -lane '$, = "\t"; @f = split(/;|\|/, $F[1]); shift(@f); splice(@f, 5); print(@f)' file
-F'\|\|\|'
: define o separador do campo de entrada como|||
;-l
: permite o processamento automático de finalização de linha. Tem dois efeitos separados. Primeiro, ele mastiga automaticamente $/ (o separador de registro de entrada) quando usado com -n ou -p. Segundo, ele atribui $\ (o separador de registro de saída) para ter o valor de octnum para que qualquer instrução de impressão tenha esse separador adicionado novamente. Se octnum for omitido, define $\ como o valor atual de $/.-a
: ativa o modo de divisão automática quando usado com -n ou -p. Um comando de divisão implícito para o array @F é feito como a primeira coisa dentro do loop while implícito produzido por -n ou -p.n
: faz com que o Perl assuma o seguinte loop em torno do seu programa, o que o faz iterar sobre os argumentos do nome do arquivo, como sed -n ou awk:LINE: while (<>) { ... # your program goes here }
-e
: pode ser usado para inserir uma linha de programa.$, = "\t"; @f = split(/;|\|/, $F[1]); shift(@f); splice(@f, 5); print(@f)
: define o separador do campo de saída como\t
, divide o segundo campo da linha atual em;
ou|
, remove o primeiro campo vazio e imprime os campos restantes.
% cat file
2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
% perl -F'\|\|\|' -lane '$, = "\t"; @f = split(/;|\|/, $F[1]); shift(@f); splice(@f, 5); print(@f)' file
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
%
Responder3
Isso deve funcionar para você:
cut -d"|" -f4,5,6,7,8 filename.txt | sed 's/;//g' | sed 's/|/\t/g'
Exemplo:
$ echo "2 41620 . T G 100 PASS AC=3;AF=0.000599042;AN=5008;NS=2504;DP=18872;EAS_AF=0;AMR_AF=0;AFR_AF=0;EUR_AF=0;SAS_AF=0.0031;AA=.|||;CSQ=G|ENSG00000184731|ENST00000327669|Transcript|missense_variant|954|954|318|K/N|aaA/aaC|||-1|tolerated(0.47)|benign(0)||||;GENCODE=ENST00000327669
" | cut -d"|" -f4,5,6,7,8 | sed 's/;//g' | sed 's/|/\t/g'
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
Explicação
cut -d"|" -f4,5,6,7,8 filename.txt #-> split the line at | and return fields 4 to 8
| sed 's/;//g' #-> remove the ;
| sed 's/|/\t/g' #-> replace | with tab
Responder4
Solução Python
#!/usr/bin/env python
import re,sys
with open(sys.argv[1]) as fd:
for line in fd:
pattern=[ x for x in re.split('\|\|\||;',line)
if 'CSQ' in x]
if pattern:
print(" ".join(pattern[0].split("|")[0:5]))
TESTE
Com a linha original do OP colada 3 vezes e ligeiramente editada eminput.txt
$ ./extract_pattern.py input.txt
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
CSQ=G ENSG00000184731 ENST00000327669 Transcript random_variant
CSQ=G ENSG00000184731 ENST00000327669 Transcript other_variant
Explicação
O script abre o arquivo fornecido na linha de comando como argumento ( sys.argv[1]
) e lê o arquivo linha por linha. Primeiro usamos re.split()
a função para dividir cada linha em vários delimitadores - 3 barras verticais ou ;
, o que permite que os dados relevantes sejam contidos em uma string. Em seguida, encontramos aquela string (que contém CSQ
). Se encontrarmos, a string é dividida novamente em lista de strings, agora apenas usando .split()
a função que usa barra vertical como delimitador. A lista resultante é dividida para pegar os primeiros 5 elementos (a [0:5]
parte) e reunida em uma nova string usando espaço como delimitador.