Фильтрация результатов взрыва по значению, но только если уникальная

Я работаю над конвейером, который в какой-то момент генерирует сотни различных файлов в следующем формате (я пишу X в полях, которые меня не интересуют):

 id1   X   X   X   X   X   X   X   X   X  evalue1   X
 id2   X   X   X   X   X   X   X   X   X  evalue2   X     
 ...

Я должен отфильтровать этот файл, чтобы для каждого идентификатора получить лучший результат на основе значения (чем меньше, тем лучше), но не учитывать этот идентификатор, если наилучшее значение повторяется с тем же идентификатором.

Например, если входной файл:

 id1   X   X   X   X   X   X   X   X   X  3e-07   X
 id1   X   X   X   X   X   X   X   X   X  3e-04   X
 id2   X   X   X   X   X   X   X   X   X  3e-07   X     
 id3   X   X   X   X   X   X   X   X   X  3e-04   X     
 id3   X   X   X   X   X   X   X   X   X  3e-04   X     
 id3   X   X   X   X   X   X   X   X   X  1e-02   X     

Ожидаемый результат будет:

 id1   X   X   X   X   X   X   X   X   X  3e-07   X
 id2   X   X   X   X   X   X   X   X   X  3e-07   X     

Между двумя попаданиями для id1 худшее удаляется, и, поскольку id3 лучшее значение не является уникальным, идентификатор не сохраняется.

Я попробовал инструмент командной строки tunning blast, но ближайший вариант - установить максимальное количество попаданий равным 1, но тогда в выводе остаются случаи, подобные id3. Поэтому моим решением был скрипт на python, но количество файлов делает процесс действительно трудоемким.

Есть ли способ отфильтровать эти файлы с помощью инструментов bash (awk?), Чтобы быть достаточно эффективным?

Каждый файл имеет уникальные идентификаторы, поэтому один и тот же идентификатор не может присутствовать в нескольких файлах.

заранее спасибо

Обновление 1:

Вот пример файла:

 D00733:159:CA65UANXX:8:1104:7340:77245  gi|13507739|ref|NC_000912.1|    100.00  24      0       0       1       24      529212  529189  3e-07   44.6
 D00733:159:CA65UANXX:8:2303:18019:72377 gi|13507739|ref|NC_000912.1|    100.00  20      0       0       1       20      622755  622736  2e-05   37.4
 D00733:159:CA65UANXX:8:2103:11030:25200 gi|13507739|ref|NC_000912.1|    95.24   21      1       0       1       21      321813  321833  3e-04   33.7
 D00733:159:CA65UANXX:8:2103:11030:25200 gi|13507739|ref|NC_000912.1|    95.24   21      1       0       1       21      495963  495943  3e-04   33.7
 D00733:159:CA65UANXX:8:2103:11030:25200 gi|13507739|ref|NC_000912.1|    95.00   20      1       0       2       21      613871  613852  0.001   31.9

После использования решения, предложенного @karafka, получается:

 D00733:159:CA65UANXX:8:2303:18019:72377 gi|13507739|ref|NC_000912.1|   100.00  20  0   0   1   20  622755  622736  2e-05   37.4
 D00733:159:CA65UANXX:8:2103:11030:25200 gi|13507739|ref|NC_000912.1|   95.00   20  1   0   2   21  613871  613852  0.001   31.9
 D00733:159:CA65UANXX:8:1104:7340:77245  gi|13507739|ref|NC_000912.1|   100.00  24  0   0   1   24  529212  529189  3e-07   44.6

Похоже, что для последнего идентификатора берется как минимум 0,001.

Я использую GNU Awk 3.1.5

Обновление 2:

Принудительное преобразование чисел не решает проблему в awk 3.1.5, единственное решение: обновите awk до>= 3.1.8

1 ответ

Решение

awk в помощь!

awk '!($1 in min) || $11<min[$1] {min[$1]=$11; line[$1]=$0} 
     END {for(k in line) print line[k]}' file

 id1   X   X   X   X   X   X   X   X   X  3e-07   X
 id2   X   X   X   X   X   X   X   X   X  3e-07   X
 id3   X   X   X   X   X   X   X   X   X  3e-04   X

this doesn't depend on the order of the entries, but also output order not guaranteed.

Другое решение с sort помощь

sort -k1,1 -k11g file | awk '!a[$1]++'

 id1   X   X   X   X   X   X   X   X   X  3e-07   X
 id2   X   X   X   X   X   X   X   X   X  3e-07   X
 id3   X   X   X   X   X   X   X   X   X  3e-04   X

to print only if the minimum is unique

awk '!($1 in min) || $11<=min[$1] {min[$1]=$11; line[$1]=$0; c[$1,$11]++}
    END {for(k in line) if(c[k,min[k]]==1) print line[k]}' file

 id1   X   X   X   X   X   X   X   X   X  3e-07   X
 id2   X   X   X   X   X   X   X   X   X  3e-07   X

to enforce numerical conversion you can add 0 to value ($11). Например

... $11+0<=min[$1] {min[$1]=$11+0; line[$1]=$0; c[$1,$11+0]++}...
Другие вопросы по тегам