Удаление строк, содержащих NA в каждом столбце

8

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

gene    v1  v2  v3  v4
g1  NA  NA  NA  NA
g2  NA  NA  2   3
g3  NA  NA  NA  NA
g4  1   2   3   2

Количество полей в каждой строке фиксировано и одинаково. Я хочу удалить эти строки из вышеуказанного файла, где все поля для каждой строки от столбца 2 до последнего является NA. Тогда вывод должен выглядеть так:

gene    v1  v2  v3  v4
g2  NA  NA  2   3
g4  1   2   3   2 
user3138373
источник
Если поля, отличные от NA, всегда являются неотрицательными целыми числами, регулярное выражение, столь же простое, как и \s\dразличие между «хорошими» и «плохими» строками.
Роман Одайский
если вы занимаетесь биоинформатикой, почему бы просто не использовать R
qwr
Поскольку я использую инструменты командной строки для создания этого файла, и я предпочту решение awk или perl, если мне не нужно сохранять файл для открытия в R. Конечно, в R вы можете удалить это с is.na проверкой, если я думаю
user3138373

Ответы:

16

С awk:

awk '{ for (i=2;i<=NF;i++) if ($i!="NA"){ print; break } }' file

Переберите поля, начинающиеся со второго поля, и напечатайте строку, если NAнайдено не содержащее поле . Тогда разорви петлю.

Фредди
источник
10

Использование GNU sed

sed -e '/g[0-9]\+\(\s*NA\s*\)\+$/d' filename

Краткое объяснение:

g[0-9]\+\(\s*NA\s*\)\+$это совпадение с регулярным выражением, gза которым следует хотя бы одна цифра, затем любое число NAs с необязательными пробелами между до конца строки.

sed -e '/<regex>/d' удаляет все совпадающие строки <regex>

Более стандартное регулярное выражение с тем же значением будет:

sed -Ee '/g[0-9]+([[:space:]]*NA[[:space:]]*)+$/d' filename
Эйке
источник
4
Обратите внимание, что \+и \sявляются нестандартными регулярными выражениями и будут соответствовать простым +или sв большинстве sedверсий. Используйте \{1,\}вместо \+и [[:space:]]вместо \sиметь переносимый код.
Филиппос
9

С allпомощью модуля Perl List :: Util:

$ perl -MList::Util=all -alne 'shift @F; print unless all { $_ eq "NA" } @F' file
gene  v1  v2  v3  v4
g2    NA  NA  2   3
g4    1   2   3   2
steeldriver
источник
9

С grep:

egrep -v -x 'g[0-9]+([[:blank:]]+NA)*[[:blank:]]*' filename

Это заставляет grep не отображать -vстроки ( ), где -xсовпадает вся строка ( ):

  • строчная буква g в первом столбце, за которой следуют одна или несколько цифр
  • любое количество экземпляров пробела с последующим NA
  • необязательный конечный пробел
Джим Л.
источник
1
+1, но отметим также , что количество полей фиксировано, так что вы могли бы использовать {4}вместо *после NAгруппы, и вы можете изменить первый [[:blank:]]*в , [[:blank:]]+чтобы сделать пробельные разделители обязательным. Несмотря на это, я никогда не понимал, почему все настаивают на том, чтобы вытащить awkбазуку для решения этих простых задач фильтрации, которые grepлегко решаются .
Кевин
Спасибо за отзыв, @Kevin. Я включил ваше первое предложение, но оставляю другое, *чтобы это решение одинаково хорошо работало для любого произвольного числа NAстолбцов, если они все являются NA.
Джим Л.
2

Вы можете попробовать:

$ grep -P '\t(?!NA(\t|$))' file

$ sed -e 'h;s/\tNA//g;/\t/!d;g' file

$ perl -MList::MoreUtils=any -F'\t' -lane 'print if any { ! /^NA$/ } @F[1..$#F]' file 
Ракеш Шарма
источник