Bash Awk выбирает строки из файла с общими столбцами, присутствующими в нескольких других файлах

#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 in AAA.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

  

Еще раз спасибо за вашу помощь!