#bash #csv #awk #compare
#bash #csv #awk #Сравнить
Вопрос:
У меня есть папка с разделителями табуляции .tsv файлы, подобные этому:
Файл Sample_1.tsv:
Gene Center Start End Strand Ref Sample ID_Sample HGVps Other_Columns
AAA . 111111 111111 T C Test p.A123B NA
AAA . 111112 111112 C A Test p.C456D NA
BBB . 222222 222222 A T Test p.E789F NA
CCC . 333331 333331 G C Test p.G10H NA
CCC . 333332 333332 A T Test p.I11J NA
CCC . 333333 333333 T C Test p.K12L NA
И у меня в другой папке есть несколько файлов для каждого гена (позже называемых Genes.tsv).
Файл AAA.tsv для гена AAA:
Coordinates Some_col_1 Change Some_col_2 Consequence Other_Columns
chr1:111111-111111 NA chr1:g.111111T>C NA Ms AAA A123B NA
Файл BBB.tsv для гена BBB:
Coordinates Some_col_1 Change Some_col_2 Consequence Other_Columns
chr2:222222-222222 NA chr2:g.222222A>T NA Syn BBB E789F NA
Файл CCC.tsv для гена CCC:
Coordinates Some_col_1 Change Some_col_2 Consequence Other_Columns
chr3:333332-333332 NA chr3:g.333332A>T NA Nns CCC I11J NA
chr3:333339-333339 NA chr3:g.333339T>C NA Syn CCC K12L NA
и т.д. для других генов.
Обратите внимание, что в столбце «Последствия» есть три элемента, разделенных пробелами, включая имя интересующего меня гена и код HGVps.
Я привел здесь эти упрощенные таблицы в качестве примера, но на самом деле у меня больше столбцов. Правильный номер столбца см. На следующих изображениях:
Изображение-1: Sample_1.tsv_with_correct_column_numbers (ПРИМЕЧАНИЕ: желтым цветом выделены строки, которые я хочу сохранить.)
Изображение-2: Genes.tsv_with_correct_column_numbers (ПРИМЕЧАНИЕ: зеленым цветом выделены элементы, общие с Sample_1.)
В принципе, я хочу сохранить в новом файле все строки Sample_1.tsv, столбцы которых присутствуют в других файлах Genes.tsv. Критерием является либо совпадение столбцов Genes Start End Ref Sample, либо столбец HVps, только если другие столбцы не совпадают.
Что я хочу получить:
Gene Center Start End Strand Ref Sample ID_Sample HGVps Other_Columns
AAA . 111111 111111 T C Test p.A123B NA
BBB . 222222 222222 A T Test p.E789F NA
CCC . 333332 333332 A T Test p.I11J NA
CCC . 333333 333333 T C Test p.K12L NA
Я думаю, что можно использовать bash / awk / grep для выбора интересующих строк.
Я точно не знаю, как это сделать, но я предполагаю, что способ действий должен быть примерно таким:
Create a new file called Sample_1_ok.tsv
Add column names in Sample_1_ok.tsv
If Gene Start End Ref Sample columns from Sample_1.tsv are the same in Genes.tsv files:
Append Sample_1.tsv line in Sample_1_ok.tsv
Else if HGVps column from Sample_1.tsv is the same in Genes.tsv files:
Append Sample_1.tsv line in Sample_1_ok.tsv
Есть ли у вас какие-либо советы о том, как действовать дальше?
Большое спасибо!
Комментарии:
1. сколько
<gene>.tsv
файлов вы хотите обработать? не могли бы вы предоставить некоторые подробности о том, какие значения соответствуют именам столбцов в<gene>.tsv
файлах (например, есть 3-кратные копии111111
inAAA.tsv
…, которые являютсяStart
и которые являютсяEnd
)? вы тестировали какой-либо код, и если да, не могли бы вы поделиться им? первой идеей было быawk
…<gene>.fsv
преобразовать файлы в массив, а затем обработатьSample_1.fsv
для сопоставления в массиве; если файлов «слишком много»<gene>.fsv
, возможно, переформатировать<gene>.fsv
данные в один файл с тем же форматомSample_1.fsv
, что и данные, а затемcomm
2. У меня ~ 50
<gene>.tsv
файлов. Для детализации столбцов<gene>.tsv
файлов столбецCoordinates
соответствуетchr#:Start-End coordinates
. Поскольку это однобуквенная мутация,Start
иEnd
они часто совпадают (но это не всегда так, вот почему я хочу различать две координаты). ВChange
столбце я хочу получить только две заглавные буквы непосредственно перед и после>
символа. Первая из этих двух букв соответствуетRef
, а втораяSample
— . По крайней мере, столбецConsequence
содержит имяGene
(AAA, BBB, CCC, …) иHGVps
.3. @markp-fuso Используя awk match, я извлек интересующие столбцы из
<gene>.tsv
:awk -F't' -v OFS='t' 'match($1, /([0-9] )-([0-9] )/, a) amp;amp; match($3, /(.)>(.)/, b) amp;amp; match($5, /([A-Z] ) ([A-Z][0-9] [A-Z])/, c) {print c[1],a[1],a[2],b[1],b[2],c[2]}' <gene>.tsv > <gene_filtered>.tsv
Итак, следующим шагом будет сравнениеSample_1.tsv
и эти новые таблицы?4. fwiw, я бы рекомендовал перенести ваш
awk
код в вопрос; облегчает другим понимание вопроса, если им не нужно копаться в комментариях, пытаясь собрать все воедино5. @markp-fuso Хорошо, я запомню вашу рекомендацию по коду.
Ответ №1:
Одно (несколько подробное) awk
решение:
awk '
/Consequence/ { gfmt=1 ; next } # header record of a "<gene>.tsv" file so flag as needing to parse based on a g(ene) file format; skip to next line of input
/ID_Sample/ { gfmt=0 } # header record of "Sample_1.tsv" file so clear g(ene) file format flag; continue to process this line of input
# gfmt==1 => parse data based on the g(ene) file format
gfmt { gene=$6 # parse out gene name
split($1,a,/[:-]/) # parse out start and end values
gstart=a[2]
gend=a[3]
split($3,a,">") # parse out ref and sample values
gref=substr(a[1],length(a[1]),1) # assumes ref is always a single character
gsample=a[2]
hgvps="p."$7 # parse out HGVps and prefix with "p."; assumes prefix is always "p."
garray[gene,gstart,gend,gref,gsample] # use fields as multidimensional index; to be used for testing a match based on gene data
hgarray[gene,hgvps] # use fields as multidimentional index; to be used for testing a match based on HGVps
}
# gfmt==0 => parse data based on Sample_1.tsv file format
! gfmt { if ( FNR==1 ) { print $0 ; next } # print header record; skip to next line of input
gene=$1 # parse out gene values;
gstart=$3 # could use field numbers in the
gend=$4 # follow-on "if" logic but wanted
gref=$6 # to give names to fields
gsample=$7 # as form of documentation
hgvps=$9
# if we have an index match in either array then print the current line to stdout
if ( (gene,gstart,gend,gref,gsample) in garray || (gene,hgvps) in hgarray )
{ print $0 }
}
' *.tsv xx/Sample_1.tsv
Примечания:
- удалите комментарии к коду declutter.
- OP может поменять местами
awk/match
код для синтаксического анализа<gene>.tsv
столбцов - приведенный выше код запускается из каталога, в котором
<gene>.tsv
находятся файлы - приведенный выше код предполагает, что все
<gene>.tsv
файлы должны быть обработаны (отсюда'*.tsv'
) Sample_1.tsv
файл является последним файлом, отправленным вawk
; в этом случае мойSample_1.tsv
файл находится в отдельном подкаталоге
Выполнение приведенного выше против AAA.tsv
, BBB.tsv
, CCC.tsv
и xx/Sample_1.tsv
генерирует следующий вывод:
Gene Center Start End Strand Ref Sample ID_Sample HGVps Other_Columns
AAA . 111111 111111 T C Test p.A123B NA
BBB . 222222 222222 A T Test p.E789F NA
CCC . 333332 333332 A T Test p.I11J NA
CCC . 333333 333333 T C Test p.K12L NA
Ответ №2:
Спасибо за ваш ответ и за то, что показали мне интересный способ сравнения двух файлов с разной структурой. Это отлично сработало для моих примеров таблиц.
Как вы упомянули, я изменил имена столбцов в awk/match
коде, чтобы различать <gene>.tsv
и Sample_1.tsv
файлы. И это сработало.
Трудная часть кода, с которой я сталкиваюсь с моими реальными данными, заключалась в выборе имени гена и кода hgvps, которые присутствовали в одной ячейке и разделялись пробелом. Я предпочел использовать дополнительное awk match
выражение для их выбора. Я также awk -F't'
добавил параметр в начале.
Вот мои модификации скрипта (все они присутствуют в первой части):
awk -F't' '
/Consequence/ { gfmt=1 ; next }
/ID_Sample/ { gfmt=0 }
# gfmt==1 => parse data based on the g(ene) file format
gfmt==1 { match($5, / ([A-Z0-9]{2,})/, a)
gene=a[1]
print gene
split($1,a,/[:-]/)
gstart=a[2]
gend=a[3]
split($3,a,">")
gref=substr(a[1],length(a[1]),1)
gsample=a[2]
match($5, /([A-Z][0-9] [A-Z])/, a)
hgvps="p," a[1]
garray[gene,gstart,gend,gref,gsample]
hgarray[gene,hgvps]
}
# gfmt==0 => parse data based on Sample_1.tsv file format
gfmt==0 { if ( FNR==1 ) { print $0 ; next }
gene=$1
gstart=$3
gend=$4
gref=$6
gsample=$7
hgvps=$9
if ( (gene,gstart,gend,gref,gsample) in garray || (gene,hgvps) in hgarray )
{ print $0 }
}
' *.tsv xx/Sample_1.tsv
Еще раз спасибо за вашу помощь!