Der schnellste Weg, um die N-te Spalte in einer Textdatei zu summieren

7

Ich habe eine CSV-Datei (in der das Feldtrennzeichen tatsächlich ein Komma ist) mit 8 Spalten und einigen Millionen Zeilen. Hier ist ein Beispiel:

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

Was ist der schnellste Weg, um die Summe aller Zahlen in einer bestimmten Spalte sowie die Anzahl der gelesenen Zeilen zu drucken? Können Sie erklären, was es schneller macht?

Elifarley
quelle
Vergessen Sie nicht, dass sed auch hinzufügen kann! unix.stackexchange.com/questions/36949/addition-with-sed
Jeff Schaller
Meinen Sie buchstäblich am schnellsten wie in der Leistung? Oder am schnellsten im laufenden Betrieb tippen, dh am einfachsten? (Am schnellsten für den Programmierer oder am schnellsten für den Computer?) Wie lang ist Ihre Datei?
Wildcard
Gute Frage. Ich habe darüber nachgedacht, wie schnell es laufen kann. Es geht um ein paar Millionen Zeilen.
Elifarley

Antworten:

12

GNU Datamash

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

Einige Tests

$ 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

Also mawkund datamashscheinen die Wahl zu sein.

Steeldriver
quelle
Um fair zu sein, würde ich vorschlagen, den printfFunktionsaufruf in den oben genannten awkTimings zu überspringen, da die anderen Tools keine textformatierte Ausgabe liefern (sie können nicht). Justawk -F',' '{ sum += $3 } END{ print sum, NR }' file
RomanPerekhrest
@ RomanPerekhrest aktualisiert
steeldriver
Vielleicht möchten Sie auch versuchen, mit dieser -MOption zu gaffen, basierend auf Sundeeps Kommentar zu Romans Antwort. Dies ist eine ausgezeichnete Antwort. Vielen Dank, dass Sie mich mit datamash bekannt gemacht haben.
David Conrad
1
Mit LC_ALL = C gibt gawk vergleichbare Timings zu mawk. mawk unterstützt keine Multi-Byte-Zeichen.
Stéphane Chazelas
6

Awk ist ein schnelles und performantes Tool zur Verarbeitung von Textdateien.

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

Beispielausgabe:

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

Konzeptioneller Hinweis :
Ich muss beachten, dass all diese Nicht- awkAlternativen nur für solche "idealen" numerischen Spalten schneller ausgeführt werden können. Es kostet Sie nur, ein etwas komplexeres Format zu haben (z. B. mit einigen zusätzlichen Informationen, die vor der Berechnung entfernt werden müssen <1064458324:a,<38009543:b,<201507:c,<9:d,<0:e,<1:f,<1:g,1298), und all diese Geschwindigkeitsvorteile verschwinden (ganz zu schweigen davon, dass einige von ihnen nicht in der Lage sind, das Format auszuführen benötigte Verarbeitung).

RomanPerekhrest
quelle
Was ist der numerische Bereich von ganzen Zahlen in Awk? Wenn OP "einige Millionen Zeilen" hat, läuft es dann über?
David Conrad
1
@ DavidConrad Gawk hat gnu.org/software/gawk/manual/html_node/… , keine Ahnung über andere Versionen
Sundeep
@Sundeep Ausgezeichnet! Das wusste ich nicht, danke.
David Conrad
1

Sie können cutdas Feld extrahieren, Zeichen zwischen die Zahlen pasteeinfügen +und bcsie summieren. Sie können verwenden, wcum die Zeilen zu zählen.

Ich bin mir jedoch nicht sicher, wie hoch die Leistung über Millionen von Zeilen sein würde. Aber die goldene Regel der Leistung ist, nicht zu raten, zu messen. Sie müssen jede Lösung profilieren, um festzustellen, ob sie die von Ihnen benötigte Leistung bietet, und um festzustellen, ob und um wie viel Änderungen die Leistung erhöhen oder verringern.

Hier ist eine Lösung, die ein bestimmtes Feld summiert und die Anzahl der Zeilen druckt:

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

Ausgabe:

Sum: 604720
Lines: 3

Das Feld wird durch den angegebenen -f#Parameter auf cut, hier cut -f3.

David Conrad
quelle