Фильтрация результатов взрыва по значению, но только если уникальная
Я работаю над конвейером, который в какой-то момент генерирует сотни различных файлов в следующем формате (я пишу 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]++}...