Consolidar y agregar columnas de fecha y hora según la columna de marca de tiempo

Consolidar y agregar columnas de fecha y hora según la columna de marca de tiempo

Tengo un archivo csv con entradas de datos de muestra de la siguiente manera:

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

Lo que me gustaría hacer es crear otras 2 columnas, Date& Hour. La Datecolumna contendrá la fecha y la Hourcolumna contendrá todas las horas en las que se capturaron los datos. Por ejemplo, según los datos anteriores, me gustaría obtener el siguiente resultado (mismo archivo, solo agregando 2 columnas adicionales):

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

Por ejemplo, si hay entradas en la hora 13 (ya sea 1 o muchas) el 16 de julio de 2018, indique la fecha correspondiente y la hora 13 solo una vez y continúe con las entradas con horas diferentes hasta que cambie la fecha. y el proceso se repite.

Tenga en cuenta que el archivo tiene muchas entradas (más de 100000) durante muchos días, con una cantidad variable de datos capturados en una hora como se indicó anteriormente. ¿Cómo puedo solucionar este problema? Espero que mi explicación sea lo suficientemente clara.

Respuesta1

Usando 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

Por lo tanto, la cadena de fecha consta de los primeros 10 caracteres que comienzan en la posición 1 del primer campo y la hora se extrae de 2 caracteres que comienzan en la posición 12.

Ambos valores más un separador de campo ( FS) se asignan al registro ( $0) y se imprimen si el registro recordado anterior es diferente.

Respuesta2

sorty uniqpuedo darle el ejemplo de salida que se muestra en su pregunta.

$ 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

Sin embargo, también dijo que quería que estos dos nuevos campos se agregaran a las líneas de entrada actuales. Eso no tiene mucho sentido para mí, porque entonces terminarías con la Fecha y la Hora duplicadas en cada línea (ya están al principio de cada línea en el campo Marca de tiempo).

Lo siguiente no es exactamente lo que solicitó pero, en mi opinión, es una mejora.

En lugar de agregar Fecha y Hora al final de cada línea, simplemente transforma sedel campo Marca de tiempo existente en campos de Fecha y Hora. Luego uniqse utiliza para deshacerse de líneas duplicadas.

$ 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

Esto supone que el archivo de entrada ya está en orden de marca de tiempo.

NOTA: si los valores de data1o data2pueden variar, las líneas de salida no serán únicas y se imprimirá la línea. Esto se debe a que uniqcompara toda la línea con la línea anterior ( uniqse puede hacer para omitir campos, pero solo reconoce los espacios en blanco como separador de campos y no se puede hacer que use comas, ni se puede hacer que use solo los dos primeros campos) . Si eso es lo que quieres, funcionará como está.

De lo contrario, necesitaría usar awko perlo algo en lugar de uniqverificar la unicidad. Por ejemplo, lo siguiente se utiliza awkpara comparar sólo los dos primeros campos separados por comas (es decir, Fecha y Hora):

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

Pero si va a canalizar la salida de sedinto awk, también puede usarlo awksolo, ya que awk puede hacer todo lo que sedpuede hacer; para eso están las funciones sub(), gsub()y de awk. gensub()p.ej

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

o con 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

información relacionada