Объединить и добавить столбцы «Дата» и «Час» на основе столбца «Отметка времени»

Объединить и добавить столбцы «Дата» и «Час» на основе столбца «Отметка времени»

У меня есть CSV-файл с примерами записей данных, как показано ниже:

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

Я хотел бы создать еще 2 столбца, Date& Hour. DateСтолбец будет содержать дату, а Hourстолбец будет содержать все часы, в которые были получены данные. Например, на основе данных выше я хотел бы получить следующий вывод (тот же файл, просто добавлены 2 дополнительных столбца):

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

Например, если есть записи для 13-го часа (независимо от того, одна или несколько) 16 июля 2018 г., укажите соответствующую дату и 13-й час только один раз и переходите к записям с другим часом, пока дата не изменится, и процесс повторяется.

Обратите внимание, что файл содержит много записей (100000+) за многие дни, с различным количеством данных, полученных за час, как указано выше. Как мне решить эту проблему? Надеюсь, мое объяснение достаточно понятно.

решение1

С использованием 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

Таким образом, строка даты состоит из первых 10 символов, начиная с позиции 1 первого поля, а час извлекается из 2 символов, начиная с позиции 12.

Оба значения плюс разделитель полей ( FS) присваиваются записи ( $0) и печатаются, если предыдущая запомненная запись отличается.

решение2

sortи uniqмогу предоставить вам пример вывода, показанный в вашем вопросе.

$ 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

Однако вы также сказали, что хотите, чтобы эти два новых поля были добавлены к текущим строкам ввода. Для меня это не имеет особого смысла, потому что тогда вы получите дублирование даты и часа в каждой строке (они уже находятся в начале каждой строки в поле Timestamp).

Нижеследующее — не совсем то, что вы просили, но, на мой взгляд, это улучшение.

Вместо добавления даты и часа в конец каждой строки, он просто sedпреобразует существующее поле метки времени в поля даты и часа. Затем uniqиспользуется для избавления от дубликатов строк.

$ 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

Это предполагает, что входной файл уже отсортирован по времени.

ПРИМЕЧАНИЕ: если значения для data1или data2могут различаться, выходные строки не будут уникальными, и строка будет напечатана. Это происходит потому, что uniqсравнивает всю строку с предыдущей строкой ( uniqможно сделать так, чтобы пропускались поля, но распознает только пробелы как разделители полей и нельзя сделать так, чтобы использовались запятые, и нельзя сделать так, чтобы использовались только первые два поля). Если это то, что вам нужно, то это будет работать как есть.

В противном случае вам придется использовать awkили perlили что-то другое вместо uniqдля проверки уникальности. Например, следующий пример использует awkдля сравнения только первые два поля, разделенные запятыми (например, дату и час):

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

Но если вы собираетесь направить вывод sedв awk, вы можете просто использовать его awkотдельно, так как awk может делать все, что sedможет делать — для этого и предназначены функции , и awk. sub()Например gsub():gensub()

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

или с 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

Связанный контент