4

次の表で表すことができるコンピューター シミュレーションによって生成された経時的なデータ セットがあります (「var」は変数です)。

time subject var1 var2 var3
t1   subjectA  ...
t2   subjectB  ...

subject   name
subjectA  nameA
subjectB  nameB

ただし、生成されたファイルは、次のような形式でデータ ファイルを書き込みます。

time t1 
  description
subjectA nameA
  var1 var2 var3
subjectB nameB
  var1 var2 var3
time t2
  description
subjectA nameA
  var1 var2 var3
subjectB nameB
  var1 var2 var3
...(and so on)

(python) スクリプトを使用してこの出力データをフラット テキスト ファイルに処理し、R、python、SQL、または awk/grep にインポートして情報を抽出できるようにしました。単一のクエリ (データがテーブルに変換された後の SQL 表記) を以下に示します。

SELECT var1, var2, var3 FROM datatable WHERE subject='subjectB'

これらのデータ ファイルはそれぞれ最大 100 MB になる可能性があり (私は何百ものファイルを持っています)、フラット テキスト ファイルの作成には時間がかかり、冗長な情報で追加のハード ドライブ領域を占有するため、より効率的なソリューションがあるのではないかと考えています。理想的には、余分なフラット テキスト ファイルを作成せずに、元のデータ セットを直接操作して、必要な情報を抽出することです...そのようなタスクのためのより簡単な awk/perl ソリューションはありますか? 私は Python でのテキスト処理にはかなり精通していますが、awk のスキルは初歩的で、perl の実用的な知識はありません。これらまたは他のドメイン固有のツールがより良いソリューションを提供できるかどうか疑問に思います。

ありがとう!

追記: うわー、みんなありがとう!みんなの答えを選べなくてごめんなさい @FM: ありがとう。私の Python スクリプトは、フィルター処理のステップを除いたコードに似ています。しかし、あなたの組織はクリーンです。@PP: 私はすでに grep に習熟していると思っていましたが、明らかにそうではありません! これは非常に役に立ちます...しかし、「時間」を出力に混在させると、greppingが難しくなると思います(私の例では、可能な抽出シナリオとして含めることができませんでした!それは私の悪いことです)。@ Ghostdog74: これは素晴らしいことです...しかし、「subjectA」を取得するために行を変更するのは簡単ではありませんでした. @weismat: よく言われます。@S.Lott:これは非常にエレガントで柔軟です-私はpython(ic)ソリューションを求めていませんでしたが、これは解析、フィルター、

繰り返しますが、私は皆さんに感謝しています - どうもありがとう。

4

5 に答える 5

4

これが Python ジェネレーターのすべてです。

def read_as_flat( someFile ):
    line_iter= iter(someFile)
    time_header= None
    for line in line_iter:
        words = line.split()
        if words[0] == 'time':
            time_header = [ words[1:] ] # the "time" line
            description= line_iter.next()
            time_header.append( description )
        elif words[0] in subjectNameSet:
            data = line_iter.next()
            yield time_header + data

これは、標準の Python イテレータのように使用できます。

for time, description, var1, var2, var3 in read_as_flat( someFile ):
    etc.
于 2010-02-15T13:14:27.217 に答える
2

最良のオプションは、コンピューター シミュレーションを変更して長方形の出力を生成することです。それができないと仮定すると、ここに1つのアプローチがあります:

R、SQL などでデータを使用できるようにするには、何らかの方法で階層型から長方形に変換する必要があります。ファイル全体を四角形のデータ セットに変換できるパーサーを既にお持ちの場合は、ほぼ完了です。次のステップは、不要なデータ レコードを除外できるように、パーサーに柔軟性を追加することです。ファイル コンバーターの代わりに、データ抽出ユーティリティがあります。

以下の例は Perl ですが、Python でも同じことができます。一般的な考え方は、(a) 解析、(b) フィルタリング、および (c) 出力の間の明確な分離を維持することです。そうすれば、柔軟な環境が得られ、差し迫ったデータ処理のニーズに応じて、さまざまなフィルタリングまたは出力方法を簡単に追加できます。柔軟性を高めるために、(コマンド ラインまたは構成ファイルから) パラメーターを受け入れるようにフィルター処理方法を設定することもできます。

use strict;
use warnings;

read_file($ARGV[0], \&check_record);

sub read_file {
    my ($file_name, $check_record) = @_;
    open(my $file_handle, '<', $file_name) or die $!;
    # A data structure to hold an entire record.
    my $rec = {
        time => '',
        desc => '',
        subj => '',
        name => '',
        vars => [],
    };
    # A code reference to get the next line and do some cleanup.
    my $get_line = sub {
        my $line = <$file_handle>;
        return unless defined $line;
        chomp $line;
        $line =~ s/^\s+//;
        return $line;
    };
    # Start parsing the data file.
    while ( my $line = $get_line->() ){
        if ($line =~ /^time (\w+)/){
            $rec->{time} = $1;
            $rec->{desc} = $get_line->();
        }
        else {
            ($rec->{subj}, $rec->{name}) = $line =~ /(\w+) +(\w+)/;
            $rec->{vars} = [ split / +/, $get_line->() ];

            # OK, we have a complete record. Now invoke our filtering
            # code to decide whether to export record to rectangular format.
            $check_record->($rec);
        }
    }
}

sub check_record {
    my $rec = shift;
    # Just an illustration. You'll want to parameterize this, most likely.
    write_output($rec)
        if  $rec->{subj} eq 'subjectB'
        and $rec->{time} eq 't1'
    ;
}

sub write_output {
    my $rec = shift;
    print join("\t", 
        $rec->{time}, $rec->{subj}, $rec->{name},
        @{$rec->{vars}},
    ), "\n";
}
于 2010-02-15T12:43:56.760 に答える
2

特定のサブジェクトに一致するときに var1、var2、var3 だけが必要な場合は、次のコマンドを試すことができます。


  grep -A 1 'subjectB'

-A 1コマンド ライン引数は、一致した行とその次の 1 行を出力するように grep に指示します (この場合、変数は件名の後の行に表示されます) 。

オプションを使用して-E、grep で正規表現を検索し、件名の検索を行頭 (例: grep -A 1 -E '^subjectB') にアンカーすることができます。

最後に、出力は必要な件名行と変数行で構成されます。件名を非表示にすることができます。


  grep -A 1 'subjectB' |grep -v 'subjectB'

そして、変数行を処理したいかもしれません:


  grep -A 1 'subjectB' |grep -v 'subjectB' |perl -pe 's/ /,/g'

于 2010-02-15T07:58:50.980 に答える
1

あなたが怠け者で十分な RAM を持っているなら、すぐに必要になる限り、ファイル システムの代わりに RAM ディスクで作業します。
現在のアルゴリズムを別の言語に再コーディングするだけであれば、Perl や awk が Python よりも高速になるとは思いません。

于 2010-02-15T08:16:46.907 に答える
1
awk '/time/{f=0}/subjectB/{f=1;next}f' file
于 2010-02-15T09:03:48.957 に答える