3

次の構造のテキストファイルがあります

ID,operator,a,b,c,d,true
WCBP12236,J1,75.7,80.6,65.9,83.2,82.1
WCBP12236,J2,76.3,79.6,61.7,81.9,82.1
WCBP12236,S1,77.2,81.5,69.4,84.1,82.1
WCBP12236,S2,68.0,68.0,53.2,68.5,82.1
WCBP12234,J1,63.7,67.7,72.2,71.6,75.3
WCBP12234,J2,68.6,68.4,41.4,68.9,75.3
WCBP12234,S1,81.8,82.7,67.0,87.5,75.3
WCBP12234,S2,66.6,67.9,53.0,70.7,75.3
WCBP12238,J1,78.6,79.0,56.2,82.1,84.1
WCBP12239,J2,66.6,72.9,79.5,76.6,82.1
WCBP12239,S1,86.6,87.8,23.0,23.0,82.1
WCBP12239,S2,86.0,86.9,62.3,89.7,82.1
WCBP12239,J1,70.9,71.3,66.0,73.7,82.1
WCBP12238,J2,75.1,75.2,54.3,76.4,84.1
WCBP12238,S1,65.9,66.0,40.2,66.5,84.1
WCBP12238,S2,72.7,73.2,52.6,73.9,84.1

それぞれIDが、オペレーターによって数回分析されるデータセットに対応します。つまりJ1、 とJ2は、演算子 J による 1 回目と 2 回目の試行です。測定abcおよびは、dわずかに異なる 4 つのアルゴリズムを使用して、真の値が列にある値を測定します。true

私がやりたいことは、J1vs J2S1vs S2、およびJ1vsの結果を比較する 3 つの新しいテキスト ファイルを作成することS1です。J1vsの出力例J2:

ID,operator,a1,a2,b1,b2,c1,c2,d1,d2,true
WCBP12236,75.7,76.3,80.6,79.6,65.9,61.7,83.2,81.9,82.1
WCBP12234,63.7,68.6,67.7,68.4,72.2,41.4,71.6,68.9,75.3

などのa1測定値aはどこですか。J1

S1vsの別の例S2:

ID,operator,a1,a2,b1,b2,c1,c2,d1,d2,true
WCBP12236,77.2,68.0,81.5,68.0,69.4,53.2,84.1,68.5,82.1
WCBP12234,81.8,66.6,82.7,67.9,67.0,53,87.5,70.7,75.3

ID は英数字順ではなく、同じ ID に対してオペレーターがクラスター化されることもありません。Linux ツールまたは perl/python などのスクリプト言語を使用して、このタスクにどのようにアプローチするのが最善かはわかりません。

Linux を使用した最初の試みは、すぐにレンガの壁にぶつかりました

最初にすべての一意の ID を検索します (並べ替え済み)

awk -F, '/^WCBP/ {print $1}' file | uniq | sort -k 1.5n > unique_ids

これらの ID をループして、 , を並べ替えJ1ますJ2

foreach i (`more unique_ids`)
    grep $i test.txt | egrep 'J[1-2]' | sort -t',' -k2
end

これにより、ソートされたデータが得られます

WCBP12234,J1,63.7,67.7,72.2,71.6,75.3
WCBP12234,J2,68.6,68.4,41.4,68.9,80.4
WCBP12236,J1,75.7,80.6,65.9,83.2,82.1
WCBP12236,J2,76.3,79.6,61.7,81.9,82.1
WCBP12238,J1,78.6,79.0,56.2,82.1,82.1
WCBP12238,J2,75.1,75.2,54.3,76.4,82.1
WCBP12239,J1,70.9,71.3,66.0,73.7,75.3
WCBP12239,J2,66.6,72.9,79.5,76.6,75.3

このデータを再配置して目的の構造を取得する方法がわかりません。ループ内に追加のパイプを追加してみawkましたforeachawk 'BEGIN {RS="\n\n"} {print $1, $3,$10,$4,$11,$5,$12,$6,$13,$7}'

何か案は?awk適切なスクリプト言語を使用したほうがよいかもしれませんが、これはを使用してより簡単な方法で実行できると確信しています。

4

3 に答える 3

4

Perl csv モジュールText::CSVを使用してフィールドを抽出し、ID がメイン キー、2 番目のフィールドがセカンダリ キー、すべてのフィールドが値として格納されるハッシュに格納できます。その後、必要な比較を行うのは簡単です。行の元の順序を保持したい場合は、最初のループ内で配列を使用できます。

use strict;
use warnings;
use Text::CSV;

my %data;
my $csv = Text::CSV->new({
            binary => 1,      # safety precaution
            eol    => $/,     # important when using $csv->print()
    });
while ( my $row = $csv->getline(*ARGV) ) {
    my ($id, $J) = @$row;   # first two fields
    $data{$id}{$J} = $row;  # store line
}
于 2013-06-24T10:10:34.833 に答える
1

TLP のように Text::CSV を使用しませんでした。必要に応じて可能ですが、この例では、フィールドにコンマが埋め込まれていないため、「,」で単純に分割したと考えました。また、最後の値の特殊なケースがソリューションを複雑にしていると考えたため、両方の演算子の真のフィールドが (1 だけではなく) リストされています。

#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw/ mesh /;

my %data;

while (<DATA>) {
    chomp;
    my ($id, $op, @vals) = split /,/;
    $data{$id}{$op} = \@vals;
}

my @ops = ([qw/J1 J2/], [qw/S1 S2/], [qw/J1 S1/]);

for my $id (sort keys %data) {
    for my $comb (@ops) {
        open my $fh, ">>", "@$comb.txt" or die $!;
        my $a1 = $data{$id}{ $comb->[0] };
        my $a2 = $data{$id}{ $comb->[1] };
        print $fh join(",", $id, mesh(@$a1, @$a2)), "\n";
        close $fh or die $!;
    }   
}

__DATA__
WCBP12236,J1,75.7,80.6,65.9,83.2,82.1
WCBP12236,J2,76.3,79.6,61.7,81.9,82.1
WCBP12236,S1,77.2,81.5,69.4,84.1,82.1
WCBP12236,S2,68.0,68.0,53.2,68.5,82.1
WCBP12234,J1,63.7,67.7,72.2,71.6,75.3
WCBP12234,J2,68.6,68.4,41.4,68.9,75.3
WCBP12234,S1,81.8,82.7,67.0,87.5,75.3
WCBP12234,S2,66.6,67.9,53.0,70.7,75.3
WCBP12239,J1,78.6,79.0,56.2,82.1,82.1
WCBP12239,J2,66.6,72.9,79.5,76.6,82.1
WCBP12239,S1,86.6,87.8,23.0,23.0,82.1
WCBP12239,S2,86.0,86.9,62.3,89.7,82.1
WCBP12238,J1,70.9,71.3,66.0,73.7,84.1
WCBP12238,J2,75.1,75.2,54.3,76.4,84.1
WCBP12238,S1,65.9,66.0,40.2,66.5,84.1
WCBP12238,S2,72.7,73.2,52.6,73.9,84.1

生成される出力ファイルは以下のとおりです

J1 J2.txt

WCBP12234,63.7,68.6,67.7,68.4,72.2,41.4,71.6,68.9,75.3,75.3
WCBP12236,75.7,76.3,80.6,79.6,65.9,61.7,83.2,81.9,82.1,82.1
WCBP12238,70.9,75.1,71.3,75.2,66.0,54.3,73.7,76.4,84.1,84.1
WCBP12239,78.6,66.6,79.0,72.9,56.2,79.5,82.1,76.6,82.1,82.1

S1 S2.txt

WCBP12234,81.8,66.6,82.7,67.9,67.0,53.0,87.5,70.7,75.3,75.3
WCBP12236,77.2,68.0,81.5,68.0,69.4,53.2,84.1,68.5,82.1,82.1
WCBP12238,65.9,72.7,66.0,73.2,40.2,52.6,66.5,73.9,84.1,84.1
WCBP12239,86.6,86.0,87.8,86.9,23.0,62.3,23.0,89.7,82.1,82.1

J1 S1.txt

WCBP12234,63.7,81.8,67.7,82.7,72.2,67.0,71.6,87.5,75.3,75.3
WCBP12236,75.7,77.2,80.6,81.5,65.9,69.4,83.2,84.1,82.1,82.1
WCBP12238,70.9,65.9,71.3,66.0,66.0,40.2,73.7,66.5,84.1,84.1
WCBP12239,78.6,86.6,79.0,87.8,56.2,23.0,82.1,23.0,82.1,82.1

更新:真の値を 1 つだけ取得するには、for ループを次のように記述できます。

for my $id (sort keys %data) {
    for my $comb (@ops) {
        local $" = '';
        open my $fh, ">>", "@$comb.txt" or die $!;
        my $a1 = $data{$id}{ $comb->[0] };
        my $a2 = $data{$id}{ $comb->[1] };
        pop @$a2;
        my @mesh = grep defined, mesh(@$a1, @$a2);
        print $fh join(",", $id, @mesh), "\n";
        close $fh or die $!;
    }   
}

更新: grep expr のテスト用に「定義済み」を追加しました。それは適切な方法です(「$_」をテストするだけでなく、これはおそらく0であり、grepによってリストから誤って除外される可能性があります)。

于 2013-06-24T19:04:22.467 に答える