web-dev-qa-db-ja.com

テキストファイルのN番目の列を合計する最速の方法

8つの列と数百万行のCSVファイル(フィールド区切り文字は実際にコンマ)があります。これがサンプルです:

1000024447,38111220,201705,181359,0,12,1,3090
1064458324,38009543,201507,9,0,1,1,1298
1064458324,38009543,201508,9,0,2,1,90017

与えられた列のすべての数の合計と読み取られた行数を印刷する最も速い方法は何ですか?何がそれを速くするのか説明できますか?

7
Elifarley

GNUデータマッシュ

$ datamash -t, count 3 sum 3 < file
3,604720

いくつかのテスト

$ time gawk -F',' '{ sum += $3 } END{ print sum, NR }' longfile
604720000000 3000000

real    0m2.851s
user    0m2.784s
sys     0m0.068s

$ time mawk -F',' '{ sum += $3 } END{ print sum, NR }' longfile
6.0472e+11 3000000

real    0m0.967s
user    0m0.920s
sys     0m0.048s

$ time Perl -F, -nle '$sum += $F[2] }{ print "$.,$sum"' longfile
3000000,604720000000

real    0m3.394s
user    0m3.364s
sys     0m0.036s

$ time { cut -d, -f3 <longfile |paste -s -d+ - |bc ; }
604720000000

real    0m1.679s
user    0m1.416s
sys     0m0.248s

$ time datamash -t, count 3 sum 3 < longfile
3000000,604720000000

real    0m0.815s
user    0m0.716s
sys     0m0.036s

したがって、mawkdatamashが一群のピックのようです。

12
steeldriver

Awkは、テキストファイルを処理するための高速でパフォーマンスの高いツールです。

awk -F',' '{ sum += $3 }
           END{ printf "Sum of 3rd field: %d. Total number of lines: %d\n", sum, NR }' file

出力例:

Sum of 3rd field: 604720. Total number of lines: 3

概念上の注意
これらのすべての非awk代替は、そのような「理想的な」数値列に対してのみ高速に実行できることに注意する必要があります。わずかに複雑な形式(例:計算前にいくつかの追加情報を削除することで<1064458324:a,<38009543:b,<201507:c,<9:d,<0:e,<1:f,<1:g,1298)が必要になるだけで、これらの速度の利点はすべて失われます(それらの一部は機能しないことは言うまでもありません)必要な処理を実行できるようにします)。

6
RomanPerekhrest

cutを使用してフィールドを抽出し、pasteを使用して数値の間に+記号を挿入し、bcを使用してそれらを合計することができます。 wcを使用して行を数えることができます。

ただし、何百万行を超えるパフォーマンスになるかはわかりません。しかし、パフォーマンスの黄金律は、推測ではありませんが、測定することです。ソリューションをプロファイルして、必要なパフォーマンスが得られるかどうかを確認し、変更によってパフォーマンスが向上するか低下するか、およびその程度を判断する必要があります。

以下は、特定のフィールドを合計して行数を出力するソリューションです。

echo -n "Sum: "
cut -d, -f3 <file |paste -s -d+ |bc
echo -n "Lines: "
wc -l <file

出力:

Sum: 604720
Lines: 3

フィールドは-f#パラメータによってcutに指定されます。ここではcut -f3です。

1
David Conrad