Consolidar e anexar colunas de data e hora com base na coluna carimbo de data/hora

Consolidar e anexar colunas de data e hora com base na coluna carimbo de data/hora

Eu tenho um arquivo csv com entradas de dados de amostra da seguinte forma:

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

O que eu gostaria de fazer é criar outras 2 colunas, Date& Hour. A Datecoluna conterá a data e Hourtodas as horas em que os dados foram capturados. Por exemplo, com base nos dados acima, gostaria de ter a seguinte saída (mesmo arquivo, apenas adicionando 2 colunas extras):

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 exemplo, se houver entradas na hora 13 (seja 1 ou muitas) em 2018 07 16, liste a data e hora 13 correspondentes apenas uma vez e passe para entradas com horas diferentes até a data mudar. e o processo se repete.

Observe que o arquivo tem muitas entradas (100.000+) para muitos dias, com número variável de dados capturados em uma hora, conforme acima. Como posso resolver esse problema? Espero que minha explicação seja clara o suficiente.

Responder1

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

Assim, a string de data consiste nos primeiros 10 caracteres começando na posição 1 do primeiro campo e a hora é extraída de 2 caracteres começando na posição 12.

Ambos os valores mais um separador de campo ( FS) são atribuídos ao registro ( $0) e impressos se o registro anterior lembrado for diferente.

Responder2

sorte uniqpode fornecer o exemplo de saída mostrado na sua pergunta.

$ 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

No entanto, você também disse que queria esses dois novos campos anexados às linhas de entrada atuais. Isso não faz muito sentido para mim, porque aí você acabaria com a Data e a Hora duplicadas em cada linha (elas já estão no início de cada linha no campo Timestamp).

O seguinte não é exatamente o que você pediu, mas é, na IMO, uma melhoria.

Em vez de anexar Data e Hora ao final de cada linha, ele apenas sedtransforma o campo Timestamp existente em campos Data e Hora. Em seguida, uniqé usado para eliminar linhas 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

Isso pressupõe que o arquivo de entrada já esteja na ordem do carimbo de data/hora.

NOTA: se os valores para data1ou data2puderem variar, as linhas de saída não serão exclusivas e a linha será impressa. Isso ocorre porque uniqcompara a linha inteira com a linha anterior ( uniqpode ser feito para pular campos, mas reconhece apenas espaços em branco como um separador de campo e não pode ser usado para usar vírgulas, nem pode ser usado para usar apenas os dois primeiros campos) . Se é isso que você quer, então funcionará como está.

Caso contrário, você precisará usar awkor perlou algo em vez de uniqverificar a exclusividade. por exemplo, os seguintes usos awkpara comparar apenas os dois primeiros campos separados por vírgula (ou seja, Data e Hora):

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

Mas se você for canalizar a saída para sedinto awk, você pode muito bem usar awksozinho, já que o awk pode fazer tudo o que sedpode fazer - é para isso que servem as funções sub(), gsub()e gensub()do awk. por exemplo

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

ou com 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

informação relacionada