
Есть ли эффективный способ анализа файла типа:
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
к:
CSQ=G ENSG00000184731 ENST00000327669 Transcript missense_variant
Паттерн всегда |||
; - затем он начинается с CSQ
пятого поля и заканчивается им - однако это поле не всегда missense variant
, а может быть и чем-то другим, например kdjdud
.
В файле много (более 60 тыс.) строк, и мне нужно извлечь эту таблицу вкладок, как показано выше. Есть ли для этого решение на Python, Perl или AWK (или что-то еще)?
решение1
Давайте используем sed
:
sed -r 's/.*\|\|\|;(CSQ[^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|.*/\1\t\2\t\3\t\4\t\5/' file.txt
python
не быстр при работе с очень большими файлами, это было бы намного быстрее, чем python
.
Пример:
% 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
решение2
Использование Perl:
perl -F'\|\|\|' -lane '$, = "\t"; @f = split(/;|\|/, $F[1]); shift(@f); splice(@f, 5); print(@f)' file
-F'\|\|\|'
: устанавливает разделитель полей ввода на|||
;-l
: включает автоматическую обработку конца строки. Имеет два отдельных эффекта. Во-первых, он автоматически уничтожает $/ (разделитель входных записей) при использовании с -n или -p. Во-вторых, он присваивает $\ (разделитель выходных записей) значение octnum, так что любые операторы печати будут иметь этот разделитель, добавленный обратно. Если octnum опущен, устанавливает $\ в текущее значение $/.-a
: включает режим авторазделения при использовании с -n или -p. Неявная команда разделения массива @F выполняется как первое действие внутри неявного цикла while, созданного с помощью -n или -p.n
: заставляет Perl предполагать следующий цикл вокруг вашей программы, что заставляет ее перебирать аргументы имен файлов, что-то вроде sed -n или awk:LINE: while (<>) { ... # your program goes here }
-e
: может использоваться для ввода одной строки программы.$, = "\t"; @f = split(/;|\|/, $F[1]); shift(@f); splice(@f, 5); print(@f)
: устанавливает разделитель выходных полей на\t
, разбивает второе поле текущей строки на;
или|
, удаляет первое пустое поле и печатает оставшиеся поля.
% 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
%
решение3
Это должно вам подойти:
cut -d"|" -f4,5,6,7,8 filename.txt | sed 's/;//g' | sed 's/|/\t/g'
Пример:
$ 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
Объяснение
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
решение4
Решение на 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]))
ТЕСТ
С оригинальной строкой OP, перепечатанной 3 раза и слегка отредактированной вinput.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
Объяснение
Скрипт открывает файл, указанный в командной строке как аргумент ( sys.argv[1]
), и считывает файл построчно. Сначала мы используем re.split()
функцию для разбиения каждой строки на несколько разделителей - 3 вертикальные черты или ;
, что позволяет соответствующим данным содержаться в одной строке. Затем мы находим ту одну строку (которая содержит CSQ
). Если мы ее находим, строка снова разбивается на список строк, теперь только с помощью .split()
функции, использующей вертикальную черту в качестве разделителя. Полученный список разрезается, чтобы взять первые 5 элементов ( [0:5]
часть) и снова объединяется в новую строку, используя пробел в качестве разделителя.