删除每一列中包含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 

如果非NA字段始终是非负整数,则正则表达式之类的简单\s\d区分“好”行和“坏”行。
罗曼·奥戴斯基

如果您在进行生物信息学研究,为什么不直接使用R
qwr

因为我在上游使用命令行工具来生成该文件,并且如果我不必保存文件以在R中打开,我将更喜欢awk或perl解决方案。当然在R中,is.na 如果我认为可以删除它,请检查一下
user3138373

Answers:


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>

具有相同含义的更标准的regexp将是:

sed -Ee '/g[0-9]+([[:space:]]*NA[[:space:]]*)+$/d' filename

4
请注意,\+\s是非标准的正则表达式,将与简单+s大多数sed版本匹配。使用\{1,\}代替\+[[:space:]]代替\s具有可移植的代码。
Philippos

9

随着all从Perl的名单::的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

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)

感谢您的反馈,@ Kevin。我纳入你的第一个建议,但我保留等*,使这个解决方案同样适用于任意数目的NA列,所以只要他们 NA。
Jim L.

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 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.