タイムスタンプを挿入し、CSVファイルの空のフィールドを置き換えます。

タイムスタンプを挿入し、CSVファイルの空のフィールドを置き換えます。

次の要素を含むCSVファイルがあります。

timestamp,      data1,  data2,  data3,  data4,  data5
2015-03-16 00:00:00,    3,  3,  4,  2,  5
2015-03-16 00:10:00,    4,  7,  8,  9,  3
2015-03-16 00:20:00,    1,  23, ,   5,  4
2015-03-16 00:30:00,    3,  2,  46, 7,  6
2015-03-16 00:40:00,    4,  5,  6,  8,  4
2015-03-16 00:50:00,    2,  ,   4,  ,   2
2015-03-16 01:00:00,    22, 1,  3,  4,  3
2015-03-16 01:50:00,    3,  ,   7,  8,  89
2015-03-16 02:00:00,    44, 5,  6,  7,  
2015-03-16 02:10:00,    3,  2,  1,  2,  2
2015-03-16 02:20:00,    4,  ,   ,   3,  3
2015-03-16 03:30:00,    5,  6,  7,  4,  3

NaN欠落しているタイムスタンプを追加し、データが存在しないデータフィールドを次のように入力したいと思います。

timestamp,      data1,  data2,  data3,  data4,  data5
2015-03-16 00:00:00,    3,  3,  4,  2,  5
2015-03-16 00:10:00,    4,  7,  8,  9,  3
2015-03-16 00:20:00,    1,  23, NaN,    5,  4
2015-03-16 00:30:00,    3,  2,  46, 7,  6
2015-03-16 00:40:00,    4,  5,  6,  8,  4
2015-03-16 00:50:00,    2,  NaN,    4,  NaN,    2
2015-03-16 01:00:00,    22, 1,  3,  4,  3
2015-03-16 01:10:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 01:20:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 01:30:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 01:40:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 01:50:00,    3,  NaN,    7,  8,  89
2015-03-16 02:00:00,    44, 5,  6,  7,  NaN
2015-03-16 02:10:00,    3,  2,  1,  2,  2
2015-03-16 02:20:00,    4,  NaN,    NaN,    3,  3
2015-03-16 02:30:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 02:40:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 02:50:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 03:00:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 03:10:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 03:20:00,    NaN,    NaN,    NaN,    NaN,    NaN
2015-03-16 03:30:00,    5,  6,  7,  4,  3

どうすればいいですか?この現象は一日ではなく数日間続くことに注意してください。単純化のために、一日分のデータを使用した。私はCygwinを使用しています。ありがとうございます。

答え1

タイムスタンプ解析を実際にサポートする実装がなく、CSV解析以外の解析のサポートがないawkため、代わりに以下のMillerを使用しています。awkシンプルCSV(組み込み区切り文字または改行なし)。

使用ミラーmlr)はCSVを解析し、スペースをクリーンアップし、欠落したタイムスタンプを生成し、最後に欠落している値を文字列に置き換えますNaN

mlr --csv \
    clean-whitespace then \
    put 't1 = strptime($timestamp,"%F %T");
         NR > 1 {
             while (@t + 600 != t1) {
                 @t += 600;
                 timestamp = strftime(@t,"%F %T");
                 emit timestamp
             }
         }
         @t = t1' then \
    unsparsify then \
    put 'for (k,v in $*) { is_empty(v) { $[k] = "NaN" } }' file

これclean-whitespaceにより、すべてのフィールドからすべての横方向空間が削除され、すべての連続した内部空間が単一の空間に圧縮されます。

2つのput式の最初のものは、欠落しているタイムスタンプを生成します。これは「現在の時間」(Unix時間を使用)を追跡し、入力から読み取られたタイム@tスタンプに対応するまで600秒(10分)単位で進行しますt1。各ステップでは、タイムスタンプがファイルと同じ形式で出力されます。これを行うには、各入力タイムスタンプが10分間隔で発生すると仮定します。

最初の式で作成された新しいレコードには、を除くすべてのフィールドが欠落してputいるため、不足しているフィールドの追加をtimestamp使用します。unsparsify

2番目putの式はすべてのフィールドを繰り返し、各空のフィールドをstringに設定しますNaN

質問のデータを考慮すると、出力は次のようになります。

timestamp,data1,data2,data3,data4,data5
2015-03-16 00:00:00,3,3,4,2,5
2015-03-16 00:10:00,4,7,8,9,3
2015-03-16 00:20:00,1,23,NaN,5,4
2015-03-16 00:30:00,3,2,46,7,6
2015-03-16 00:40:00,4,5,6,8,4
2015-03-16 00:50:00,2,NaN,4,NaN,2
2015-03-16 01:00:00,22,1,3,4,3
2015-03-16 01:10:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 01:20:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 01:30:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 01:40:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 01:50:00,3,NaN,7,8,89
2015-03-16 02:00:00,44,5,6,7,NaN
2015-03-16 02:10:00,3,2,1,2,2
2015-03-16 02:20:00,4,NaN,NaN,3,3
2015-03-16 02:30:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 02:40:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 02:50:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 03:00:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 03:10:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 03:20:00,NaN,NaN,NaN,NaN,NaN
2015-03-16 03:30:00,5,6,7,4,3

答え2

mktime()GNU awkを使用して時間関数(および)strftime()を実行します。gensub()\s

$ cat tst.awk
BEGIN { FS=OFS="," }
{ gsub(/\s*,\s*/,",") }
NR == 1 { print; next }
NR == 2 {
    dfltData = gensub(/[^,]/,"","g")
    prevSecs = mktime(gensub(/[- :]/," ","g",$1))
}
{
    currTime = $1
    currData = $0
    while ( prevTime < currTime ) {
        prevTime = strftime("%F %T",prevSecs += 600)
        if ( prevTime < currTime ) {
            $0 = dfltData
            $1 = prevTime
            prt()
        }
    }
    $0 = currData
    prt()
}

function prt() {
    $0 = gensub(/,(,|$)/,",Nan\\1","g") # this needs 2 passes
    print gensub(/,(,|$)/,",Nan\\1","g")
}

$ awk -f tst.awk file
timestamp,data1,data2,data3,data4,data5
2015-03-16 00:00:00,3,3,4,2,5
2015-03-16 00:10:00,4,7,8,9,3
2015-03-16 00:20:00,1,23,Nan,5,4
2015-03-16 00:30:00,3,2,46,7,6
2015-03-16 00:40:00,4,5,6,8,4
2015-03-16 00:50:00,2,Nan,4,Nan,2
2015-03-16 01:00:00,22,1,3,4,3
2015-03-16 01:10:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 01:20:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 01:30:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 01:40:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 01:50:00,3,Nan,7,8,89
2015-03-16 02:00:00,44,5,6,7,Nan
2015-03-16 02:10:00,3,2,1,2,2
2015-03-16 02:20:00,4,Nan,Nan,3,3
2015-03-16 02:30:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 02:40:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 02:50:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 03:00:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 03:10:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 03:20:00,Nan,Nan,Nan,Nan,Nan
2015-03-16 03:30:00,5,6,7,4,3

関連情報