awk は配列を前の行の配列と比較します

awk は配列を前の行の配列と比較します

ご協力いただければ幸いです。場合によっては 1 テラバイトを超えるサイズのデータ​​ ファイルから情報を抽出しています。

  • 各行の変数は空白で区切られます。
  • 各行の変数の数はファイルごとに固定されています
  • 右3列は常に自然数
  • 行は常に配列で始まる
  • 配列にはファイルごとに固定数の要素が常に含まれる
  • 配列には1~5個の要素を含めることができます
  • ソースデータファイルは適切にソートされている

以下のサンプルは、並列処理を使用しているときに、3 つの要素の配列をファイルまたはチャンク内の他のすべての配列と比較します。配列が一致すると、右から 2 番目の列が追加され、行が結合されます。右端の列と -2 列はフラッシュされます。

g@grml # zcat googlebooks-eng-us-all-3gram-20120701-zz.gz | head
Z'Z . _END_     1840    1       1
Z'Z . _END_     1847    1       1
Z'Z . _END_     1850    1       1
Z'Z . _END_     1855    1       1
Z'Z . _END_     1856    1       1
Z'Z . _END_     1857    1       1
Z'Z . _END_     1860    1       1
Z'Z . _END_     1863    1       1
Z'Z . _END_     1865    1       1
Z'Z . _END_     1869    1       1



g@grml # zcat googlebooks-eng-us-all-3gram-20120701-zz.gz | parallel -k -q --pipe awk '{a[$1" "$2" "$3] +=$(NF-1)} END{for (i in a) print i, a[i]}' | head 
Zz_NOUN _NOUN_ , 98
zz _._ _PRT_ 120
ZZ or_CONJ _NOUN_ 122
ZZ_NOUN _DET_ _VERB_ 59
zz_DET _NOUN_ . 86
ZZ is_VERB reached 42
ZZ_NUM ^ ^ 65
ZZ _NOUN_ _VERB_ 3163
ZZ ,_. " 52
ZZ / _NUM_ 275

この例では 3 要素の配列を示していますが、ここでは 1 ~ 5 要素の配列を操作しています。

awk '{a[$1] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3" "$4] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3" "$3" "$5] +=$(NF-1)} END{for (i in a) print i, a[i]}'

awk に、ファイルまたはチャンク内のすべての配列をすべての配列と一致させようとさせるのではなく、現在の配列を前の行の前の配列と比較するように指示するにはどうすればよいでしょうか。

ありがとう

サンプルソースファイル。

wget --show-progress -cq http://storage.googleapis.com/books/ngrams/books/googlebooks-eng-us-all-3gram-20120701-zz.gz -O - | zcat

答え1

コメント内のURLとして与えられた入力データはタブで区切られています。つまり、最初のタブで区切られたフィールドを他の行と比較するための「キー」として解析することができます。ない最初のフィールド内のスペースで区切られた単語を考慮する必要がありますが、最初のフィールド全体を単一のエンティティとして扱うことができます。

BEGIN { OFS = FS = "\t" }

{
    count = $(NF - 1)
    key = $1
}

key != previous {
    if (previous != "")
        print previous, sum

    sum = 0
}

{
    sum += count
    previous = key
}

END {
    if (previous != "")
        print previous, sum
}

このawkプログラムは、「count」フィールド (最後から 2 番目のフィールド) を に解析し、最初のフィールドを「キー」として使用して、後で前の行のキーと比較します。これは、ブロック (入力と出力の区切り文字を設定するだけ)countの後の最初のブロックです。BEGIN

キーが前の行のキーと異なる場合は、別の単語セットを参照していることを意味します。前の行のキーと合計を出力し、合計をリセットします。

すべての行について、この行からのカウントで合計を増分し、更新しますprevious(この行は終了したので、この行の はkey次の行の になりますprevious)。

最後に、データの最後の行の情報を出力します。

これを を使って実行しますawk -f script.awk inputfile

「ワンライナー」として:

awk -F '\t' 'BEGIN{OFS=FS} {c=$(NF-1);k=$1} k!=p {if(p!="")print p,s;s=0} {s+=c;p=k} END {if(p!="") print p,s}' file

関連情報