Разбор таблицы текстовых файлов и агрегирование информации

У меня длинный текстовый файл со следующими столбцами, с разделителями-пробелами:

Id Pos Ref Var Cn SF:R1 SR He Ho NC cm|371443199 22 GAR Pass:8 0 1 0 0 cm|371443199 25 CAM Pass:13 0 0 1 0 cm|371443199 22 GAR Pass:8 0 1 0 0 cm|367079424 17 CGS Pass:19 0 0 1 0 cm|371443198 17 GAR Pass:18 0 1 0 0 cm|367079424 17 GAR Pass:18 0 0 1 0 

Я хочу создать таблицу, в которой перечислены все уникальные идентификаторы, а также счетчики для:

  • Сколько раз этот идентификатор
  • Сколько из этих строк проходило (столбец 6)
  • Сколько из них имели значение He (столбец 8)
  • Сколько из них имели значение Ho (столбец 9)

В этом случае:

 Id CountId Countpass CountHe CountHO cm|371443199 3 3 2 1 cm|367079424 2 2 0 2 

Как я могу начать создавать эту таблицу?

Вот решение в awk которое использует 4 массива для подсчета 4-х частей необходимой вам информации. Результат от awk затем подается в column который хорошо выравнивает столбцы. (Обратите внимание, что это также можно было сделать в awk используя printf .)

 awk 'NR>1 { id[$1]++ if($6 ~ /Pass/) pass[$1]++ if($8 ~ /1/) he[$1]++ if($9 ~ /1/) ho[$1]++ } END { print "Id CountId Countpass CountHe CountHO" for(i in id) print i" "id[i]" "(pass[i]?pass[i]:0)" "(he[i]?he[i]:0)" "(ho[i]?ho[i]:0) }' input.txt | column -t 

Вывод:

 Id CountId Countpass CountHe CountHO cm|371443198 1 1 1 0 cm|371443199 3 3 2 1 cm|367079424 2 2 0 2 

Один из способов использования perl предполагающий infile имеет содержание вашего вопроса (идентификаторы не обязательно будут в том же порядке на выходе, потому что я использую хэш для их сохранения):

Содержание script.pl :

 use strict; use warnings; my (%data); while ( <> ) { ## Omit header. next if $. == 1; ## Remove last '\n'. chomp; ## Split line in spaces. my @f = split; ## If this ID exists, get previously values and add values of this ## line to them. Otherwise, begin to count now. my @counts = exists $data{ $f[0] } ? @{ $data{ $f[0] } } : (); $counts[0]++; $counts[1]++ if substr( $f[5], 0, 4 ) eq q|Pass|; $counts[2] += $f[7]; $counts[3] += $f[8]; splice @{ $data{ $f[0] } }, 0, @{ $data{ $f[0] } }, @counts; } ## Format output. my $print_format = qq|%-15s %-10s %-12s %-10s %-10s\n|; ## Print header. printf $print_format, qw|Id CountId CountPass CountHe CountHo|; ## For every ID saved in the hash print acumulated values. for my $id ( keys %data ) { printf $print_format, $id, @{ $data{ $id } }; } 

Запустите его так:

 perl script.pl infile 

Со следующим выходом:

 Id CountId CountPass CountHe CountHo cm|371443198 1 1 1 0 cm|371443199 3 3 2 1 cm|367079424 2 2 0 2