CSVファイル(7億行以上)を読み取るにはUnixコマンドが必要です。例は次のとおりです。
A, 10
B, 11
C, 12
A, 10
B, 12
D, 10
A, 12
C, 12
このコマンドは、最初の列の発生回数を計算し、2 番目の列の個々の発生回数を計算し、最初の列の項目別に出力をグループ化します。出力は次のとおりです。
A, 3, 2
B, 2, 2
C, 2, 1
D, 1, 1
答え1
出力の最初の 2 つの列を取得するには、次のようにします。
$ cut -d, -f1 <file | sort | uniq -c | awk -vOFS=, '{ print $2, $1 }'
A,3
B,2
C,2
D,1
元のファイルの最初の列を抽出してソートし、重複する項目数を計算します。最後にawk
列を変更し、その間にカンマを挿入します。
最後の列に
$ sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }'
2
2
1
1
これにより、元のデータがソートされ、重複したデータが削除されます。次に、最初の列と重複回数を抽出します。それ計算されます。最後に、数だけawk
抽出されます。
以下を使用bash
して組み合わせますpaste
。
$ paste -d, <( cut -d, -f1 <file | sort | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
<( sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1
データを事前に並べ替えると、この速度がやや短くなり、はるかに高速になる可能性があります。
$ sort -o file file
$ paste -d, <( cut -d, -f1 <file | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
<( uniq <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1
答え2
私はPerl one-linerを使ってこの問題を解決できることを確認したかったので、それを理解することができました。
$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
END { print "$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n" for sort keys %lcnt }' \
file
A, 3, 2
B, 2, 2
C, 2, 1
D, 1, 1
崩れる
ファイルを繰り返し
この文は非常に複雑に見えますが、一度分解すると実際には非常に簡単です。 Perlの主なメカニズムは次のとおりです。
$ perl -F, -ane '...; END { ... }' file
これはPerlにファイルをfile
インポートし、それを繰り返しながら-F,
区切り文字を使用して自動的に分割し、完了したらEND {..}
ブロックを一度実行して終了するように指示します。
たとえば、
$ perl -F, -ane 'print "arg1: $F[0] arg2: $F[1]"; END { print "DONE\n" }' file
arg1: A arg2: 10
arg1: B arg2: 11
arg1: C arg2: 12
arg1: A arg2: 10
arg1: B arg2: 12
arg1: D arg2: 10
arg1: A arg2: 12
arg1: C arg2: 12
DONE
メモ:Perlの自動分割機能は自動的に列を配列に配置します。ここでは、要素1と2、&を@F
使用しています。$F[0]
$F[1]
物を数える
次のことは、入力の個々のビットを計算することです。そのためにPerlのハッシュ機能を活用します。私たちは2、を使用し%lcnt
ます%ccnt
。
メモ:Perlで最も迷惑なものの1つは、ハッシュを定義するときとハッシュにアクセスするときにシンボルを切り替えることです。アクセスするとからに切り替わりますが、%lcnt
別の$lcnt["A"]
方向に切り替わります。
$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++;
%lcnt
- 最初の列の文字数%ccnt
- 2番目の列の数にアクセスするための2つの座標の2Dハッシュが含まれています。
メモ:このように物事を数えることは、私たちが数字を数えるだけでユニークな機能を実行できるようにします。
%lcnt
たとえば、ハッシュの内容を確認してみましょう。
$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
END { print "key: $_\n" for sort keys %lcnt }' file
key: A
key: B
key: C
key: D
各ハッシュを表示するには:
$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
END { print "key: $_ val: $lcnt{$_}\n" for sort keys %lcnt }' file
key: A val: 3
key: B val: 2
key: C val: 2
key: D val: 1
メモ:$lcnt{$F[0]}++
ここでは、すべての努力が完了したことを見ることができます計算ファイルを繰り返し、各文字をハッシュに追加します%lcnt
。
これは終わりです。
パズルの最後の部分は、収集されたすべての情報を便利な方法で表示することです。これを行うには、以下で使用しますEND {...}
。
print "$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n" for sort keys %lcnt
その後、キーリストを繰り返して%lcnt
次の行を印刷します。
$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n"
上記の構造を確認するのが難しい場合、より一般的な構造は次のとおりです。
A, 3, 2
^--- (keys %{ $ccnt{$_} }) ## count of unique columns for each character ($_)
^------ $lcnt{$_} ## count of each character
^--------- $_ ## character
これにより、文字($_
)、その文字の数値($lcnt{$_}
)、および2番目の列の各文字の固有値の数を含む行が作成されます。
引用する
答え3
入力データを含むsqlite3
コマンドラインから小さなスクリプトを実行します。input.csv
sqlite3 -batch <<EOF
.mode csv
CREATE TABLE data (letter TEXT, number INTEGER);
.import input.csv data
SELECT letter, COUNT(*) AS lcount, COUNT(DISTINCT number) AS dcount
FROM data
GROUP BY letter ;
EOF
これは次のように動作します
$ bash query.sqlite
A,3,2
B,2,2
C,2,1
D,1,1
答え4
datamash -t, -s -g 1 count 1 countunique 2 < input.txt
入力する
A, 10
B, 11
C, 12
A, 10
B, 12
D, 10
A, 12
C, 12
出力
A,3,2
B,2,2
C,2,1
D,1,1