2012-01-04 25 views
0

我有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中的任何東西都可以。

謝謝。

+3

請告訴我們你的嘗試 - 也許你的一些代碼也會很好! – codeling 2012-01-04 13:30:34

+0

由於0的出現不是,僅限於某一列,並且它可以出現在任何列中,所以邏輯本身在那裏失敗。 :( – Angelo 2012-01-04 13:31:57

+3

aw,來吧,基本的邏輯非常簡單:讀取行,從第三個開始總結令牌;如果總和大於4,則丟棄該行,否則使用它。有問題嗎? – codeling 2012-01-04 13:36:38

回答

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

如果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 
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 
+0

我的錯......錯樣輸出 – Angelo 2012-01-04 13:43:03

1

這裏的東西,忽略任何非數字.....

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

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

oopps didn這個問題沒有正確地讀出來......認爲總數必須小於4 ...... – 2012-01-04 13:43:05

1

根據您當前例子(沒有在第一和第二列中沒有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> 4或< 4的行數???

+0

我已經在問題中進行了修正,錯誤地輸出了錯誤信息 – Angelo 2012-01-04 16:01:34

+1

然後你可以改變「>」 - >「<=」在我的awk行中 – Kent 2012-01-04 17:11:57

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 
1

我不知道我理解正確的規範,但可以調整這個需要:

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

'0 == $ _'會給非數字值帶來誤報 – TLP 2012-01-04 14:11:06

+0

@TLP:在這個例子中沒有,切換到「0」eq $ _ '或者其他什麼, – choroba 2012-01-04 14:17:03

+0

我在思考如何在問題結束時安全而簡潔地做到這一點。可以做什麼是'grep!/ \ D/&& $ _ == 0',儘管這也有缺點。 – TLP 2012-01-04 14:46:46

1

像揚哈通說,你的問題的描述不符所需的輸出,但如果你想有超過4個零的行,這會做:

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

我假定第一和第二欄不會包含1或0。如果不是這種情況,請改用grep(/^0$/, @F[2..9])

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