データに存在しない日付を無理やり作り出して、値を埋める方法

前回、チャートの「値がない場合の処理」という設定を使って、データラングリングをせずに、割引率が変更されるまで同じ値で推移するラインチャートを作りました。

しかし実際には、データに存在しない日付のデータをデータラングリングをして生成したいといった場合があります。例えば、そうやってできたデータをもとに時系列予測や機械学習のモデルを作る必要があったり、別のデータと結合する必要があったり、といった時などです。

ここでの問題は、ここのデータには割引率が変更された日のデータしかなく、期間内のそれ以外の日のデータがないということです。そこで、このデータの期間である10月1日から12月10日までの全ての日付を用意する必要があります。

では、どうやってこのデータに存在しない日付のデータを作ることができるのでしょうか。

今回はその問題を解決するべく、データに存在しない日付を無理やり作り出して、値を埋めていきたいと思います。

日付データをComplete関数とseq.Date関数を使用して入力する

実は2つのRの関数を組み合わせることで、比較的シンプルにこの問題を解決することができます。

1つは’tidyr’パッケージの’complete’という関数。もう1つは’base R’パッケージの’seq.Date’という関数です。

そして、以下のようなRコマンドを作り、それを実行することになります。

complete(Date = seq.Date(<start_date>, <end_date>, by=<date_unit>))

まず、seq.Date関数は、最初の引数と2番目の引数に指定された期間の日付データを作ります。実際のデータから動的に最初の日と最後の日をとってきたいので、今回はmin関数とmax関数を使います。

さらに、どういう単位で日付データを作りたいのかを指定することができます。これが3番目のby=という引数です。今回は「日」の単位でデータを生成したいので、「day」を指定することになります。

complete(Date = seq.Date(min(Date), max(Date), by="day"))

カスタムRコマンドのステップを使う

それでは、上記のRコマンドを実際にExploratoryの中から実行してみましょう。

右側のデータラングリングのステップの上部にある「+ (プラス)」ボタンを押して、「カスタムRコマンド」というメニューを選びます。

そして、上記のRコマンドを以下のようにコピペして、実行します。

これで、2017年10月1日から2017年12月10日までのすべての日付が入力されました。

しかし、問題が1つあります。 新しく生成された日付のProduct列はNAになっていて、製品AかBかの区別がつきません。本来であれば、それぞれの製品ごとに日付が新しく生成されるべきです。

実はその場合は、先ほどのcompleteというコマンドに、このProductという列名を追加することで解決できます。

complete(Date = seq.Date(min(Date), max(Date), by="day"), Product)

実際のRコマンドはこのようになります。

これは、Date列とProduct列の値の全ての組み合わせに対して行を入力してくれます。Dateは、2017年10月1日から2017年12月10日までのすべての値です。Productの値はAとBです。つまり、10月1日から12月10日までの日付に対してProductのAとBが組み合わされた行ができるというわけです。

欠損値を埋める

それでは、Discount Rateの欠損値(NA)をどうやって埋めるのでしょうか。

前述したように、新しい割引率が設定されるまで、割引率は毎日同じになると予想されます。

そのため、各欠損値(NA)の前日の値をコピーしたいです。

ExploratoryではUIで欠損値(NA)を処理することができます。

Discount Rateのメニューから「欠損値(NA)を扱う」を押し、「欠損値(NA)を前か後ろの行の値で埋める」を選択してください。

ダイアログが表示されるので、欠損値を…で埋めるに「前の値」を選び、実行します。

これでDiscount Rateに、値が欠損値(NA)の場合に前の値で埋めることができました。

以下のように割引率の変化を可視化することができます。

でもちょっとおかしいですね…

AとBのレートが同じまたは類似の日に変化していることに気付くでしょう。

このチャートを見ると、Aの最初の割引率が変更されたのは10月16日です。しかし、元の日付を見ると、Aの割引率の変更は10月23日まで起こりませんでした。

では一体何が起きているのでしょうか?

この「欠損値を前の行で埋める」は、単に前の値をコピーするだけです。

そのため、10月15日に割引率が変更されたBの値0.2が、10月16日のAとBの両方にコピーされたことを意味します。

前:

後:

ここでやりたいのは、AとBのそれぞれの割引率はそれぞれのグループ内の前の値で埋めることです。

実はこれは「グループ化」というステップを使って、そのデータフレームをAとBにグループ化しておいた後に、先ほどの「欠損値を前後の行で埋める」というステップを実行することで実現することができます。

それではやってみましょう!

「グループ化」を使って欠損値をそれぞれのグループ内で埋める

「欠損値を前後の行の値で埋める」というステップの前に「グループ化」のステップを入れたいので、まずは現在選択れさているステップを先ほどcomplete関数を使った「カスタムRコマンド」というステップに移します。

次に、Product列の列ヘッダーメニューから「グループ化」を選んで、データフレームをグループ化します。

そうすることで、欠損値の処理のステップの前にグループ化のステップを作成することができました。

次に、右側の「欠損値を前後の行の値で埋める」のステップをクリックしてステップを移動すると、欠損値がそれぞれのグループ内で前の値を使って埋められました。

先ほど作成したチャートを開くとこのようになります。

AとBの割引率が変更された日のみ増減が表示されています。

まとめ

今回は、complete関数とSeq.Date関数を使用することで、データに存在しない日付を作り出すことができました。

カスタムRコマンドを使用して、データを手動で作成する方法を知っておくのも便利です。

ぜひ活用してみてください!