最初の列として計算し、2番目の列で固有値を計算し、最初の列に出力をグループ化しますか?

最初の列として計算し、2番目の列で固有値を計算し、最初の列に出力をグループ化しますか?

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

関連情報