Perl 比较单个文件中的多个列,并计算这些列中某个值的出现次数
我有一个21列的文件Perl 比较单个文件中的多个列,并计算这些列中某个值的出现次数,perl,awk,sed,grep,Perl,Awk,Sed,Grep,我有一个21列的文件 Name Grade1 Grade2 Grade3 Grade4 Grade5 .... Grade20 Zoe 60 70 NA NA NA 67 现在,我只想保留超过5个等级为NA的名字某些名称包含NA。 我知道awk可以做这项工作。但我不知道如何在不单独比较的情况下比较所有列 我试过: more input_file.txt | awk 'total
Name Grade1 Grade2 Grade3 Grade4 Grade5 .... Grade20
Zoe 60 70 NA NA NA 67
现在,我只想保留超过5个等级为NA的名字某些名称包含NA。
我知道awk可以做这项工作。但我不知道如何在不单独比较的情况下比较所有列
我试过:
more input_file.txt | awk 'total = count20[$2,$3,$4,$5,$6,$7,$8,$9,$10,
$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21]++, if (($2 == "NA" || $3 == "NA" ||
$4 == "NA" || $5 == "NA" || $6 == "NA" || $7 == "NA" || $8 == "NA" || $9 == "NA"
|| $10 == "NA" || $11 == "NA" || $12 == "NA" || $13 == "NA" || $14 == "NA" ||
$15 == "NA" || $16 == "NA" || $17 == "NA" || $18 == "NA" || $19 == "NA" ||
$20 == "NA" || $21 == "NA") && total > 4) { print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"
$6"\t"$7"\t"$8"\t"$9"\t"$10"\t"$11"\t"$12"\t"$13"\t"$14"\t"$15"\t"$16"\t"$17"\t"
$18"\t"$19"\t"$20"\t"$21 }' > test.txt
它不起作用,我不知道为什么或者如何更有效地完成它
编辑:更准确地说,想要的输出是一个文件,其中包含名称和学生的所有列,超过5列包含NA。
awk
$ awk -F'NA' 'NF>5'
假设您的名称列不包含NA作为子字符串。使用NA作为字段分隔符并对字段进行计数,如果有5个以上的字段意味着至少有5个NAs,则默认操作是打印行,因此无需指定。这将为您提供具有5个或更多NA的记录,如果您希望严格超过5个,请将阈值更改为6。
awk
拯救
$ awk -F'NA' 'NF>5'
假设您的名称列不包含NA作为子字符串。使用NA作为字段分隔符并对字段进行计数,如果有5个以上的字段意味着至少有5个NAs,则默认操作是打印行,因此无需指定。这将为您提供具有5个或更多NA的记录,如果您希望严格大于5,请将阈值更改为6。此命令将至少六次打印包含
NA的所有行:
grep -E '(NA.*){6}' infile
如果学生的名字也包含NA
,则可能会出错。要解决这个问题,您可以使用
grep -E '^[^[:blank:]]+[[:blank:]]+(NA.*){6,}' infile
仅在第一列之后计算NA
。此命令至少六次打印包含NA
的所有行:
grep -E '(NA.*){6}' infile
如果学生的名字也包含NA
,则可能会出错。要解决这个问题,您可以使用
grep -E '^[^[:blank:]]+[[:blank:]]+(NA.*){6,}' infile
它只在第一列之后计算NA。这里有一个使用awk的基本方法:
awk '{ count = 0; for (i = 2; i <= NF; ++i) if ($i == "NA") ++count } count > 5' file
awk'{count=0;for(i=2;i=5)文件
这将循环遍历每个字段并检查它是否等于“NA”。如果是,它将添加到该记录的总计数中。当计数大于5时,将打印记录。以下是使用awk执行此操作的基本方法:
awk '{ count = 0; for (i = 2; i <= NF; ++i) if ($i == "NA") ++count } count > 5' file
awk'{count=0;for(i=2;i=5)文件
这将循环遍历每个字段并检查它是否等于“NA”。如果是,它将添加到该记录的总计数中。当计数大于5时,将打印记录。它被标记为perl
,因此perl回答:
perl -ne 'print if (grep /^NA$/, split ) > 5'
其中:
- 逐行迭代
- 空格分开了吗
- greps仅为
NA
- 如果计数为
>5,则打印
它被标记为perl
,因此perl回答:
perl -ne 'print if (grep /^NA$/, split ) > 5'
其中:
- 逐行迭代
- 空格分开了吗
- greps仅为
NA
- 如果计数为
>5,则打印
带有GNU awk的单词边界:
awk -F'\\<NA\\>' 'NF>6'
对于字段之间的任何类型的空格,使用任意POSIX awk:
awk -F'[[:space:]]NA([[:space:]]|$)' 'NF>6'
GNU awk用于单词边界:
awk -F'\\<NA\\>' 'NF>6'
对于字段之间的任何类型的空格,使用任意POSIX awk:
awk -F'[[:space:]]NA([[:space:]]|$)' 'NF>6'
在Perl中,只需计算等于NA
perl -ne 'print if 5 <= grep { $_ eq "NA" } split' test.txt
perl-ne'如果在perl中打印5,只需计算等于NA
perl -ne 'print if 5 <= grep { $_ eq "NA" } split' test.txt
perl-ne'print if 5我不确定“awk
to the rescue”是一个适当的详细答案,尤其是当OP已经尝试使用awk时!我不确定“awk
to the rescue”这是一个适当详细的答案,特别是当OP已经尝试使用awk时!这是唯一一个学生“NAthalie Miller”和5个NAs不是假阳性的;)@BenjaminW。这是唯一一个…:-)。我想现在唯一的选择是它看起来最不可怕:)@TomFenech我加了$1=“”跳过第一列(这样条件就不会影响名称),但现在它不会输出名称。我是否应该添加一些内容来输出所有列?我只是从第二个字段循环,这样第一个字段就不会影响计数。此外,正在测试字段是否与“NA”完全匹配。这是唯一一个允许学生使用的字段“NAthalie Miller”和5个NAs不是假阳性;)@BenjaminW。这是唯一一个…:-)。我想现在,唯一的原因是它看起来最不吓人:)@TomFenech我加了$1=“”,跳过第一列(这样条件就不会影响名称)但是现在它不输出名称。我是否应该添加一些内容来输出所有列?我只是从第二个字段循环,这样第一个字段就不会影响计数。此外,正在测试这些字段是否与“NA”完全匹配"。我想你可以用-a
而不是调用-split
。我想你可以用-a
而不是调用split
。有没有理由更喜欢调用split
而不是使用-a
和-F
呢?@TomFenech:只是在这种情况下节省很少,而且对那些人来说也不太清楚对于的内容不完全熟悉的se。我在我的回答中添加了一个使用autosplit的版本。是否有理由更喜欢调用split
,而不是使用-a
和@F
?@TomFenech:只是在这种情况下节省很少,对于那些对的内容不完全熟悉的人来说,这就不那么清楚了。我添加了一个使用autosplit到我的答案的版本是这样的,使用您的第二种方法,使NA最多出现6次(而不是至少出现6次)?它不起作用。它只输出整个文件。在这种情况下,我只想输出包含最大6次NA的行。@snowy_squirrel啊,对。要说“6次或更少”,您可以使用与“7次或更多”相同的模式,但使用-v
:grep-vE'^[^[:blank:]+[:blank:]+[:blank:]+(N