DataFrameにtimezone情報を含むdatetime64型カラムが存在すると線形補完できない問題への対処　

## はじめに
分析エンジニアがよく利用するpythonのpandasライブラリ。
分析業務を行わないソフトウェアエンジニアでも、システムを結合する際にどうしても利用しなければならない場面があります。

でも前に使ったの半年前なんですよねー。。。なんで言うこと聞いてくれないのですかDataFrameさん。

ということで今回は、とあるDataFrameに対して線形補完を行うと以下のエラーが発生しました。

1時間毎の時系列データを30分毎のデータに変換し、線形補間しようとしています。

```python
>>> df.asfreq('30min')
                                      forecasted_at  temperature      tcdc  hcdc     mcdc       lcdc       dsrf
target_datetime                                                                                                
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00      5.17942  0.000000   0.0  24.3164  24.316400        NaN
2019-11-29 00:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00      4.38748  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 01:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00      3.87086  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 02:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00      3.79156  0.000000   0.0   0.0000   0.000000        NaN
2019-11-29 03:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00      3.14681  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 04:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00      2.67394  0.878906   0.0   0.0000   0.878906    0.00000
2019-11-29 05:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00      2.86707  0.000000   0.0   0.0000   0.000000        NaN
2019-11-29 06:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00      2.38549  0.000000   0.0   0.0000   0.000000    7.96875
2019-11-29 07:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00      3.01866  0.000000   0.0   0.0000   0.000000  128.75000
2019-11-29 08:30:00+09:00                       NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00      4.64967  0.000000   0.0   0.0000   0.000000        NaN

>>> df.asfreq('30min').interpolate(method='linear')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/generic.py", line 7064, in interpolate
    **kwargs
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/internals/managers.py", line 569, in interpolate
    return self.apply("interpolate", **kwargs)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/internals/managers.py", line 438, in apply
    applied = getattr(b, f)(**kwargs)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/internals/blocks.py", line 1965, in interpolate
    values=values.fillna(value=fill_value, method=method, limit=limit),
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/arrays/datetimelike.py", line 777, in fillna
    value, method = validate_fillna_kwargs(value, method)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/util/_validators.py", line 360, in validate_fillna_kwargs
    method = clean_fill_method(method)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/missing.py", line 96, in clean_fill_method
    raise ValueError(msg)
ValueError: Invalid fill method. Expecting pad (ffill) or backfill (bfill). Got linear
```

調査を進めるとどうやらtimezone情報を持つdatetime64型のカラムを含む場合に問題が起きるようでした。

githubにも同様の内容でissueが上がっていましたが、現時点では解決していないようです。

https://github.com/pandas-dev/pandas/issues/25508

ライブラリのコアな部分の設定を上書きするとエラーを無視できるようになるというようなイメージのおまじないを使うようですが、詳しくは追っていません。
（ちなみにこのおまじないは有効でした。それはそれで気になる。。。）

ただよくわからないおまじないを使って対処するわけにはいかないので、もう少しわかりやすい対処を考えてみました。

もしより良い方法をご存知の方いらっしゃったら、是非教えて下さい。

## 検証環境

- python: 3.7.4
- pandas: 0.25.3

## 検証に利用したデータ

検証には気象予報データを利用しました。
検証に必須ではないデータも多々ありますが、より具体的なデータの例としてこちらを用いました。

```python
>>> df
                                      forecasted_at  temperature      tcdc  hcdc     mcdc       lcdc       dsrf
target_datetime                                                                                                
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00      5.17942  0.000000   0.0  24.3164  24.316400        NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00      4.38748  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00      3.87086  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00      3.79156  0.000000   0.0   0.0000   0.000000        NaN
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00      3.14681  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00      2.67394  0.878906   0.0   0.0000   0.878906    0.00000
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00      2.86707  0.000000   0.0   0.0000   0.000000        NaN
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00      2.38549  0.000000   0.0   0.0000   0.000000    7.96875
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00      3.01866  0.000000   0.0   0.0000   0.000000  128.75000
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00      4.64967  0.000000   0.0   0.0000   0.000000        NaN
```

参考までに各カラムは以下のようなデータです。

- target_datetime: 予報の対象時刻
- forecasted_at: 予報が作られた時刻
- temperature: 気温
- tcdc: 全雲量
- hcdc: 高層雲量
- mcdc: 中層雲量
- lcdc: 低層雲量
- dsrf: 日射量

```python
>>> df.index
DatetimeIndex(['2019-11-29 00:00:00+09:00', '2019-11-29 01:00:00+09:00',
               '2019-11-29 02:00:00+09:00', '2019-11-29 03:00:00+09:00',
               '2019-11-29 04:00:00+09:00', '2019-11-29 05:00:00+09:00',
               '2019-11-29 06:00:00+09:00', '2019-11-29 07:00:00+09:00',
               '2019-11-29 08:00:00+09:00', '2019-11-29 09:00:00+09:00'],
              dtype='datetime64[ns, pytz.FixedOffset(540)]', name='target_datetime', freq=None)

>>> df.dtypes
forecasted_at    datetime64[ns, pytz.FixedOffset(540)]
temperature                                    float64
tcdc                                           float64
hcdc                                           float64
mcdc                                           float64
lcdc                                           float64
dsrf                                           float64
dtype: object
```

## 失敗パターン特定

timezoneを含むカラムに問題がありそうということはわかりましたが、インデックスのデータもtimezoneを含んでいます。
まずはtimezoneを含まないカラムのみのDataFrameに対して線形補完を行ってみます。

```python
>>> df.asfreq('30min').loc[:, ['temperature']]
                           temperature
target_datetime                       
2019-11-29 00:00:00+09:00      5.17942
2019-11-29 00:30:00+09:00          NaN
2019-11-29 01:00:00+09:00      4.38748
2019-11-29 01:30:00+09:00          NaN
2019-11-29 02:00:00+09:00      3.87086
2019-11-29 02:30:00+09:00          NaN
2019-11-29 03:00:00+09:00      3.79156
2019-11-29 03:30:00+09:00          NaN
2019-11-29 04:00:00+09:00      3.14681
2019-11-29 04:30:00+09:00          NaN
2019-11-29 05:00:00+09:00      2.67394
2019-11-29 05:30:00+09:00          NaN
2019-11-29 06:00:00+09:00      2.86707
2019-11-29 06:30:00+09:00          NaN
2019-11-29 07:00:00+09:00      2.38549
2019-11-29 07:30:00+09:00          NaN
2019-11-29 08:00:00+09:00      3.01866
2019-11-29 08:30:00+09:00          NaN
2019-11-29 09:00:00+09:00      4.64967

>>> df.asfreq('30min').loc[:, ['temperature']].interpolate(method='linear')
                           temperature
target_datetime                       
2019-11-29 00:00:00+09:00     5.179420
2019-11-29 00:30:00+09:00     4.783450
2019-11-29 01:00:00+09:00     4.387480
2019-11-29 01:30:00+09:00     4.129170
2019-11-29 02:00:00+09:00     3.870860
2019-11-29 02:30:00+09:00     3.831210
2019-11-29 03:00:00+09:00     3.791560
2019-11-29 03:30:00+09:00     3.469185
2019-11-29 04:00:00+09:00     3.146810
2019-11-29 04:30:00+09:00     2.910375
2019-11-29 05:00:00+09:00     2.673940
2019-11-29 05:30:00+09:00     2.770505
2019-11-29 06:00:00+09:00     2.867070
2019-11-29 06:30:00+09:00     2.626280
2019-11-29 07:00:00+09:00     2.385490
2019-11-29 07:30:00+09:00     2.702075
2019-11-29 08:00:00+09:00     3.018660
2019-11-29 08:30:00+09:00     3.834165
2019-11-29 09:00:00+09:00     4.649670
```

問題なさそうです。やはり問題はインデックスではなく、カラムにtimezone情報が含まれていることのようです。
念のためtimezone情報を含むカラムが問題になっていることを確認します。

```python
>>> df.asfreq('30min').loc[:, ['forecasted_at']]
                                      forecasted_at
target_datetime                                    
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00
2019-11-29 00:30:00+09:00                       NaT
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00
2019-11-29 01:30:00+09:00                       NaT
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00
2019-11-29 02:30:00+09:00                       NaT
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00
2019-11-29 03:30:00+09:00                       NaT
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00
2019-11-29 04:30:00+09:00                       NaT
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00
2019-11-29 05:30:00+09:00                       NaT
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00
2019-11-29 06:30:00+09:00                       NaT
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00
2019-11-29 07:30:00+09:00                       NaT
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00
2019-11-29 08:30:00+09:00                       NaT
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00

>>> df.asfreq('30min').loc[:, ['forecasted_at']].interpolate(method='linear')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/generic.py", line 7064, in interpolate
    **kwargs
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/internals/managers.py", line 569, in interpolate
    return self.apply("interpolate", **kwargs)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/internals/managers.py", line 438, in apply
    applied = getattr(b, f)(**kwargs)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/internals/blocks.py", line 1965, in interpolate
    values=values.fillna(value=fill_value, method=method, limit=limit),
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/arrays/datetimelike.py", line 777, in fillna
    value, method = validate_fillna_kwargs(value, method)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/util/_validators.py", line 360, in validate_fillna_kwargs
    method = clean_fill_method(method)
  File "/Users/hoge/.local/share/virtualenvs/myproject-RpjxRXLN/lib/python3.7/site-packages/pandas/core/missing.py", line 96, in clean_fill_method
    raise ValueError(msg)
ValueError: Invalid fill method. Expecting pad (ffill) or backfill (bfill). Got linear
```

再現しました。

ここまでくれば何とかなりそうです。

## 解決方法

### 方法1: カラム毎に処理を分割して最後に結合する

線形補完できないカラムが混じっていることが問題なので、
線形補完できないカラムのDataFrameとできるカラムのDataFrameに分離し、できるカラムのDataFrameに対してのみ線形補完を行い、最後に結合します。

まずはどちらも補完せずに結合できることを確認します。
Indexをキーにして結合する場合はjoinメソッドを使います。

```python
>>> pd.DataFrame.join(df.loc[:, ['forecasted_at']].asfreq('30min'), df.loc[:, ['temperature', 'dsrf']].asfreq('30min'))
                                      forecasted_at  temperature       dsrf
target_datetime                                                            
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00      5.17942        NaN
2019-11-29 00:30:00+09:00                       NaT          NaN        NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00      4.38748    0.00000
2019-11-29 01:30:00+09:00                       NaT          NaN        NaN
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00      3.87086    0.00000
2019-11-29 02:30:00+09:00                       NaT          NaN        NaN
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00      3.79156        NaN
2019-11-29 03:30:00+09:00                       NaT          NaN        NaN
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00      3.14681    0.00000
2019-11-29 04:30:00+09:00                       NaT          NaN        NaN
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00      2.67394    0.00000
2019-11-29 05:30:00+09:00                       NaT          NaN        NaN
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00      2.86707        NaN
2019-11-29 06:30:00+09:00                       NaT          NaN        NaN
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00      2.38549    7.96875
2019-11-29 07:30:00+09:00                       NaT          NaN        NaN
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00      3.01866  128.75000
2019-11-29 08:30:00+09:00                       NaT          NaN        NaN
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00      4.64967        NaN
```

今度は数値カラムのDataFrame側のみ線形補完して結合します。

```python
>>> pd.DataFrame.join(df.loc[:, ['forecasted_at']].asfreq('30min'), df.loc[:, ['temperature', 'dsrf']].asfreq('30min').interpolate(method='linear'))
                                      forecasted_at  temperature        dsrf
target_datetime                                                             
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00     5.179420         NaN
2019-11-29 00:30:00+09:00                       NaT     4.783450         NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00     4.387480    0.000000
2019-11-29 01:30:00+09:00                       NaT     4.129170    0.000000
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00     3.870860    0.000000
2019-11-29 02:30:00+09:00                       NaT     3.831210    0.000000
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00     3.791560    0.000000
2019-11-29 03:30:00+09:00                       NaT     3.469185    0.000000
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00     3.146810    0.000000
2019-11-29 04:30:00+09:00                       NaT     2.910375    0.000000
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00     2.673940    0.000000
2019-11-29 05:30:00+09:00                       NaT     2.770505    1.992188
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00     2.867070    3.984375
2019-11-29 06:30:00+09:00                       NaT     2.626280    5.976562
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00     2.385490    7.968750
2019-11-29 07:30:00+09:00                       NaT     2.702075   68.359375
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00     3.018660  128.750000
2019-11-29 08:30:00+09:00                       NaT     3.834165  128.750000
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00     4.649670  128.750000
```

見事結合できました！

### 方法2: timezoneを含むdatetime64カラムからtimezone情報を削除したDataFrameを用意する

timezoneが問題なのであれば、それを削除すればいいですよね。

カラムの型変換には汎用的な処理が行えるapplyメソッドを利用しました。
(to_xxxxみたいなメソッドがあることを期待しましたがありませんでした。。。）

まずはカラム（Series）に対してapplyできることを確認します。

```python
>>> df.forecasted_at.apply(lambda d: d.replace(tzinfo=None))
target_datetime
2019-11-29 00:00:00+09:00   2019-11-29 00:00:00
2019-11-29 01:00:00+09:00   2019-11-29 00:00:00
2019-11-29 02:00:00+09:00   2019-11-29 00:00:00
2019-11-29 03:00:00+09:00   2019-11-29 03:00:00
2019-11-29 04:00:00+09:00   2019-11-29 03:00:00
2019-11-29 05:00:00+09:00   2019-11-29 03:00:00
2019-11-29 06:00:00+09:00   2019-11-29 06:00:00
2019-11-29 07:00:00+09:00   2019-11-29 06:00:00
2019-11-29 08:00:00+09:00   2019-11-29 06:00:00
2019-11-29 09:00:00+09:00   2019-11-29 09:00:00
Name: forecasted_at, dtype: datetime64[ns]
```

うまく変換できたので、カラム情報を上書きし、カラムのデータタイプを確認します。

```python
>>> df.forecasted_at = df.forecasted_at.apply(lambda d: d.replace(tzinfo=None))
>>> df.dtypes
forecasted_at    datetime64[ns]
temperature             float64
tcdc                    float64
hcdc                    float64
mcdc                    float64
lcdc                    float64
dsrf                    float64
dtype: object
```

中身をみてもtimezone情報は消えていることがわかります。

```python
>>> df.asfreq('30min')
                                forecasted_at  temperature      tcdc  hcdc     mcdc       lcdc       dsrf
target_datetime                                                                                          
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00      5.17942  0.000000   0.0  24.3164  24.316400        NaN
2019-11-29 00:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00      4.38748  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 01:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00      3.87086  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 02:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00      3.79156  0.000000   0.0   0.0000   0.000000        NaN
2019-11-29 03:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00      3.14681  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 04:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00      2.67394  0.878906   0.0   0.0000   0.878906    0.00000
2019-11-29 05:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00      2.86707  0.000000   0.0   0.0000   0.000000        NaN
2019-11-29 06:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00      2.38549  0.000000   0.0   0.0000   0.000000    7.96875
2019-11-29 07:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00      3.01866  0.000000   0.0   0.0000   0.000000  128.75000
2019-11-29 08:30:00+09:00                 NaT          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00      4.64967  0.000000   0.0   0.0000   0.000000        NaN
```

準備は整いました。線形補完します。

```python
>>> df.asfreq('30min').interpolate(method='linear')
                                forecasted_at  temperature      tcdc  hcdc     mcdc       lcdc        dsrf
target_datetime                                                                                           
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00     5.179420  0.000000   0.0  24.3164  24.316400         NaN
2019-11-29 00:30:00+09:00                 NaT     4.783450  0.000000   0.0  12.1582  12.158200         NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00     4.387480  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 01:30:00+09:00                 NaT     4.129170  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00     3.870860  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 02:30:00+09:00                 NaT     3.831210  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00     3.791560  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 03:30:00+09:00                 NaT     3.469185  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00     3.146810  0.000000   0.0   0.0000   0.000000    0.000000
2019-11-29 04:30:00+09:00                 NaT     2.910375  0.439453   0.0   0.0000   0.439453    0.000000
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00     2.673940  0.878906   0.0   0.0000   0.878906    0.000000
2019-11-29 05:30:00+09:00                 NaT     2.770505  0.439453   0.0   0.0000   0.439453    1.992188
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00     2.867070  0.000000   0.0   0.0000   0.000000    3.984375
2019-11-29 06:30:00+09:00                 NaT     2.626280  0.000000   0.0   0.0000   0.000000    5.976562
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00     2.385490  0.000000   0.0   0.0000   0.000000    7.968750
2019-11-29 07:30:00+09:00                 NaT     2.702075  0.000000   0.0   0.0000   0.000000   68.359375
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00     3.018660  0.000000   0.0   0.0000   0.000000  128.750000
2019-11-29 08:30:00+09:00                 NaT     3.834165  0.000000   0.0   0.0000   0.000000  128.750000
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00     4.649670  0.000000   0.0   0.0000   0.000000  128.750000
```

見事線形補完できました！

ただしエラーはでないもののdatetime64型は線形補完できないようです。

## おわりに
datetime64型の時刻を表す情報としてはただの数値（エポック秒）だと思うのですが線形補完できない理由があるのでしょうか。
モヤモヤしますが謎解きはまた時間のある時にしたいと思います。

## 付録

### 補完関連のメソッドの動作確認　

時刻情報のカラムに対して線形補完するのは、単なる数値カラムに対して行うよりは複雑な事情があるのかもしれません。
でも前後の値を利用して、同じ値を補完するffillやbfillなら問題ないのでは？と考えて、適用してみました。

```python
>>> df.asfreq('30min').interpolate(method='ffill')
                                      forecasted_at  temperature      tcdc  hcdc     mcdc       lcdc       dsrf
target_datetime                                                                                                
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00      5.17942  0.000000   0.0  24.3164  24.316400   24.31640
2019-11-29 00:30:00+09:00 2019-11-29 00:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00      4.38748  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 01:30:00+09:00 2019-11-29 00:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00      3.87086  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 02:30:00+09:00 2019-11-29 00:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00      3.79156  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 03:30:00+09:00 2019-11-29 03:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00      3.14681  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 04:30:00+09:00 2019-11-29 03:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00      2.67394  0.878906   0.0   0.0000   0.878906    0.00000
2019-11-29 05:30:00+09:00 2019-11-29 03:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00      2.86707  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 06:30:00+09:00 2019-11-29 06:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00      2.38549  0.000000   0.0   0.0000   0.000000    7.96875
2019-11-29 07:30:00+09:00 2019-11-29 06:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00      3.01866  0.000000   0.0   0.0000   0.000000  128.75000
2019-11-29 08:30:00+09:00 2019-11-29 06:00:00+09:00          NaN       NaN   NaN      NaN        NaN        NaN
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00      4.64967  0.000000   0.0   0.0000   0.000000    0.00000
```

forecasted_atは補完できましたが、なぜか数値カラムは補完できませんでした。

調べてみるとinterpolateメソッドとは別にパディング系のメソッドが用意されていることがわかりました。

早速その1つであるffillメソッドで補完してみます。

```python
>>> df.asfreq('30min').ffill()
                                      forecasted_at  temperature      tcdc  hcdc     mcdc       lcdc       dsrf
target_datetime                                                                                                
2019-11-29 00:00:00+09:00 2019-11-29 00:00:00+09:00      5.17942  0.000000   0.0  24.3164  24.316400        NaN
2019-11-29 00:30:00+09:00 2019-11-29 00:00:00+09:00      5.17942  0.000000   0.0  24.3164  24.316400        NaN
2019-11-29 01:00:00+09:00 2019-11-29 00:00:00+09:00      4.38748  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 01:30:00+09:00 2019-11-29 00:00:00+09:00      4.38748  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 02:00:00+09:00 2019-11-29 00:00:00+09:00      3.87086  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 02:30:00+09:00 2019-11-29 00:00:00+09:00      3.87086  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 03:00:00+09:00 2019-11-29 03:00:00+09:00      3.79156  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 03:30:00+09:00 2019-11-29 03:00:00+09:00      3.79156  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 04:00:00+09:00 2019-11-29 03:00:00+09:00      3.14681  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 04:30:00+09:00 2019-11-29 03:00:00+09:00      3.14681  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 05:00:00+09:00 2019-11-29 03:00:00+09:00      2.67394  0.878906   0.0   0.0000   0.878906    0.00000
2019-11-29 05:30:00+09:00 2019-11-29 03:00:00+09:00      2.67394  0.878906   0.0   0.0000   0.878906    0.00000
2019-11-29 06:00:00+09:00 2019-11-29 06:00:00+09:00      2.86707  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 06:30:00+09:00 2019-11-29 06:00:00+09:00      2.86707  0.000000   0.0   0.0000   0.000000    0.00000
2019-11-29 07:00:00+09:00 2019-11-29 06:00:00+09:00      2.38549  0.000000   0.0   0.0000   0.000000    7.96875
2019-11-29 07:30:00+09:00 2019-11-29 06:00:00+09:00      2.38549  0.000000   0.0   0.0000   0.000000    7.96875
2019-11-29 08:00:00+09:00 2019-11-29 06:00:00+09:00      3.01866  0.000000   0.0   0.0000   0.000000  128.75000
2019-11-29 08:30:00+09:00 2019-11-29 06:00:00+09:00      3.01866  0.000000   0.0   0.0000   0.000000  128.75000
2019-11-29 09:00:00+09:00 2019-11-29 09:00:00+09:00      4.64967  0.000000   0.0   0.0000   0.000000  128.75000
```

全てのカラムを補完できました。。。何故なんだ。。。

線形補完はできないものの、パディングしたいだけであれば、interpolateメソッドよりも有用そうです。

DataFrame初心者には理解できない挙動ですが、今掘り下げる時間はありません。

謎は深まるばかりです。