根据条件从行检索数据

时间:2012-01-04 13:27:17

标签: python perl bash shell

我有一个10列200行的制表符分隔文件:

a  b  1  0  1  1 0  1  0  0
c  d  0  0  0  1 1  1  1  0
e  f  1  0  1  0 0  1  0  0

等等,提取数据的条件是,“如果从第3列到最后一列,0的计数大于4,则不应考虑该行”

上述设定的答案将是:

a  b  1  0  1  1 0  1  0  0
c  d  0  0  0  1 1  1  1  0

请帮助,我尝试过但失败了。

shell,python或PERL中的所有内容都可以。

谢谢。

9 个答案:

答案 0 :(得分:2)

import csv

fin = open("text.txt","rb")
r = csv.reader(fin,delimiter="\t")
for line in r:
    if (sum(1 if x=='0' else 0 for x in line[3:]) < 4):
        print line
fin.close()

答案 1 :(得分:1)

如果awk可以接受,请尝试:

awk '{
  c = x
  for (i = f - 1; ++i <= NF;)
    $i == 0 && c++
  }
c > l' l=4 f=3 infile

鉴于您的文件格式,这也可能有效:

awk '{ r = $0 }
  gsub(/0/, x, r) > l
  ' l=4 infile

答案 2 :(得分:1)

这是一个用Perl编写的例子。请注意,您说“不会考虑超过4个零”,实际上只会在示例输出中考虑超过4个零的行。

use strict;
use warnings;

while ( <DATA> ) {
    chomp;
    my ( $id1, $id2, @remaining_columns ) = split;
    my @zeros = grep { $_ == 0 } @remaining_columns;
    if ( @zeros > 4 ) {
        print "$_\n";
    }
}

__DATA__
a  b  1  0  1  1 0  1  0  0
c  d  0  0  0  1 1  1  1  0
e  f  1  0  1  0 0  1  0  0

答案 3 :(得分:1)

这是忽略任何非数字的东西.....

line = "a b 2 1 2 2 3 2 3 2"

if (sum(map(int,filter(str.isdigit,line.split(" "))))) < 4:
    print line

答案 4 :(得分:1)

基于当前示例(第1列和第2列中没有0)。

AWK:

awk '{x=$0;gsub(/[^0]/,"",x);}length(x)>4' yourFile

试验:

kent$  echo "a  b  1  0  1  1 0  1  0  0
c  d  0  0  0  1 1  1  1  0
e  f  1  0  1  0 0  1  0  0
"|awk '{x=$0;gsub(/[^0]/,"",x);}length(x)>4' 

输出:

e  f  1  0  1  0 0  1  0  0

我也感到困惑,你想要的那些行号为0&gt; 4或&lt; 4 ???

答案 5 :(得分:1)

(稍微)惯用的Perl。

#!/usr/bin/perl

use strict;
use warnings;

while (<DATA>) {
  my (undef, undef, @cols) = split;
  print if (grep $_ == 0, @cols) > 4
}

__DATA__
a  b  1  0  1  1 0  1  0  0
c  d  0  0  0  1 1  1  1  0
e  f  1  0  1  0 0  1  0  0

答案 6 :(得分:1)

我不确定我是否正确理解规格,但您可以根据需要进行调整:

perl -ane 'print if 4 < grep 0 == $_, @F[2..$#F]'

答案 7 :(得分:1)

就像Jan Hartung所说的那样,你对问题的描述与所需的输出不匹配,但如果你想要超过4个零的行,这将会:

perl -ane 'print if grep(/^0$/,@F) > 4' data.tsv

我假设第一列和第二列永远不会包含1或0。如果情况并非如此,请改用grep(/^0$/, @F[2..9])

答案 8 :(得分:1)

这是使用List :: MoreUtils的不同Perl解决方案。

use strict;
use warnings;
use List::MoreUtils qw/true/;

while (my $line = <DATA>) {
    my ($ch1, $ch2, @arr) = split /\s+/, $line;
    print $line if ((true {$_ == 0} @arr) > 4);
}

__DATA__
a  b  1  0  1  1 0  1  0  0
c  d  0  0  0  1 1  1  1  0
e  f  1  0  1  0 0  1  0  0