Konsolidieren und Anhängen von Datums- und Stundenspalten basierend auf der Zeitstempelspalte

Konsolidieren und Anhängen von Datums- und Stundenspalten basierend auf der Zeitstempelspalte

Ich habe eine CSV-Datei mit Beispieldateneinträgen wie folgt:

Timestamp,data1,data2
2018 07 16 13:00:00,23,45
2018 07 16 13:10:00,23,45
2018 07 16 13:20:00,23,45
2018 07 16 13:30:00,23,45
2018 07 16 13:50:00,23,45
2018 07 16 14:20:00,23,45
2018 07 16 14:40:00,23,45
2018 07 16 14:50:00,23,45
2018 07 16 15:10:00,23,45
2018 07 16 17:50:00,23,45
2018 07 16 18:10:00,23,45
2018 07 17 10:10:00,23,45
2018 07 18 13:20:00,23,45
2018 07 19 13:30:00,23,45

Ich möchte zwei weitere Spalten erstellen, Date& Hour. Die DateSpalte enthält das Datum und die HourSpalte enthält alle Stunden, zu denen die Daten erfasst wurden. Basierend auf den obigen Daten möchte ich beispielsweise die folgende Ausgabe haben (dieselbe Datei, nur mit zwei zusätzlichen Spalten):

Date,Hour
2018 07 16,13
2018 07 16,14
2018 07 16,15
2018 07 16,17
2018 07 16,18
2018 07 17,10
2018 07 18,13
2018 07 19,13

Wenn es beispielsweise am 16.07.2018 Einträge zu Stunde 13 gibt (egal ob 1 oder viele), listen Sie das entsprechende Datum und die Stunde 13 nur einmal auf und fahren Sie mit den Einträgen mit einer anderen Stunde fort, bis sich das Datum ändert und der Vorgang wiederholt wird.

Bitte beachten Sie, dass die Datei viele Einträge (über 100.000) für viele Tage enthält, wobei die Anzahl der in einer Stunde erfassten Daten wie oben unterschiedlich ist. Wie kann ich dieses Problem lösen? Ich hoffe, meine Erklärung ist klar genug.

Antwort1

Verwendung von awk:

awk 'BEGIN{ OFS=FS="," }
  NR==1{ print "Date", "Hour"; next }
  {
    $0=substr($1, 1, 10) FS substr($1, 12, 2)
    if ($0 == prev) next  # skip to next record if record equals prev
    prev=$0               # remember record
  }
  1                       # print record
' file

Somit besteht der Datumsstring aus den ersten 10 Zeichen beginnend an Position 1 des ersten Feldes und die Stunde wird aus 2 Zeichen beginnend an Position 12 extrahiert.

Beide Werte plus ein Feldtrennzeichen ( FS) werden dem Datensatz ( $0) zugewiesen und ausgedruckt, wenn der vorher gespeicherte Datensatz anders ist.

Antwort2

sortund uniqkann Ihnen das in Ihrer Frage gezeigte Ausgabebeispiel geben.

$ sed -e 's/Timestamp.*/Date,Hour/; s/ \(..\):.*/,\1/' file.csv  | uniq
Date,Hour
2018 07 16,13
2018 07 16,14
2018 07 16,15
2018 07 16,17
2018 07 16,18
2018 07 17,10
2018 07 18,13
2018 07 19,13

Sie sagten jedoch auch, dass Sie diese beiden neuen Felder an die aktuellen Eingabezeilen anhängen möchten. Das macht für mich nicht viel Sinn, denn dann hätten Sie das Datum und die Stunde in jeder Zeile doppelt (sie stehen bereits am Anfang jeder Zeile im Feld „Zeitstempel“).

Das Folgende ist nicht genau das, was Sie verlangt haben, ist meiner Meinung nach aber eine Verbesserung.

Anstatt Datum und Stunde an das Ende jeder Zeile anzuhängen, wird einfach seddas vorhandene Zeitstempelfeld in Datums- und Stundenfelder umgewandelt. Anschließend uniqwerden doppelte Zeilen entfernt.

$ sed -e 's/Timestamp/Date,Hour/; s/ \(..\):[^,]*,/,\1,/' file.csv  | uniq
Date,Hour,data1,data2
2018 07 16,13,23,45
2018 07 16,14,23,45
2018 07 16,15,23,45
2018 07 16,17,23,45
2018 07 16,18,23,45
2018 07 17,10,23,45
2018 07 18,13,23,45
2018 07 19,13,23,45

Dies setzt voraus, dass die Eingabedatei bereits in der Zeitstempelreihenfolge vorliegt.

HINWEIS: Wenn die Werte für data1oder data2variieren können, sind die Ausgabezeilen nicht eindeutig und die Zeile wird gedruckt. Dies liegt daran, dass uniqdie gesamte Zeile mit der vorherigen Zeile verglichen wird ( uniqkann so eingestellt werden, dass Felder übersprungen werden, erkennt aber nur Leerzeichen als Feldtrennzeichen und kann nicht so eingestellt werden, dass Kommas verwendet werden, noch kann es so eingestellt werden, dass nur die ersten beiden Felder verwendet werden). Wenn Sie das möchten, funktioniert es so, wie es ist.

Andernfalls müssten Sie zur Überprüfung auf Eindeutigkeit awk„oder“ perloder etwas anderes anstelle von verwenden uniq. Im Folgenden werden beispielsweise awknur die ersten beiden durch Kommas getrennten Felder (also Datum und Stunde) verglichen:

$ sed -e 's/Timestamp/Date,Hour/; s/ \(..\):[^,]*,/,\1,/' file.csv  |
    awk -F, 'prev != $1$2 {print; prev=$1$2}'

sedWenn Sie die Ausgabe von jedoch in weiterleiten möchten awk, können Sie auch awkallein verwenden, da awk alles kann, was sedkann – hierfür sind die Funktionen sub(), gsub(), und von awk gensub()da. zB:

$ awk -F, -v OFS=, '{ sub(/Timestamp/,"Date,Hour");
                       $1 = gensub(/ ([0-9]+):.*/,",\\1",1,$1)
                    };
                    prev != $1$2 {print; prev=$1$2}' file.csv

oder mit perl:

$ perl -lne 's/Timestamp/Date,Hour/;
             s/ (\d\d):.*?,/,$1,/;
             ($current) = (m/^[^,]+,\d\d|^Date),/);
             if ($prev ne $current) {print ; $prev = $current}' file.csv

verwandte Informationen