pandasで欠損値NaNを前後の値から補間するinterpolate

pandas.DataFrame, pandas.Seriesの欠損値NaNを前後の値から補間するにはinterpolate()メソッドを使います。

pandas.DataFrame.interpolate — pandas 0.23.3 documentation pandas.Series.interpolate — pandas 0.23.3 documentation

以下の内容について説明します。

interpolate()の基本的な使い方 行 or 列を指定: 引数axis 補間する連続欠損値の最大数を指定: 引数limit 補間方向を指定: 引数limit_direction 内挿のみ or 外挿のみ or 両方を指定: 引数limit_area オブジェクト自体を更新するかを指定: 引数inplace

補間方法: 引数method 線形補間: linear, index, values スプライン補間: spline その他

時系列データの補間

欠損値NaNを削除したり特定の値で穴埋めする場合はdropna(), fillna()を使います。以下の記事を参照。

interpolate()の基本的な使い方

以下のpandas.DataFrameを例とします。

import pandas as pd

df = pd.DataFrame({'col1': [0, pd.np.nan, pd.np.nan, 3, 4],
                   'col2': [pd.np.nan, 1, 2, pd.np.nan, pd.np.nan],
                   'col3': [4, pd.np.nan, pd.np.nan, 7, 10]})

print(df)
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   NaN   1.0   NaN
# 2   NaN   2.0   NaN
# 3   3.0   NaN   7.0
# 4   4.0   NaN  10.0

デフォルトでは各列に対して線形補間を行う。下端の欠損値には同じ値が繰り返される。上端の欠損値はそのまま。

print(df.interpolate())
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   1.0   1.0   5.0
# 2   2.0   2.0   6.0
# 3   3.0   2.0   7.0
# 4   4.0   2.0  10.0

以下、引数の設定について説明します。基本的にはpandas.Seriesでも同じ。 第一引数methodで指定する補間方法については後述。

行 or 列を指定: 引数axis

引数axis=1とすると各行に対して補間される。右端の欠損値には同じ値が繰り返される。左端の欠損値はそのまま。

print(df.interpolate(axis=1))
#    col1  col2  col3
# 0   0.0   2.0   4.0
# 1   NaN   1.0   1.0
# 2   NaN   2.0   2.0
# 3   3.0   5.0   7.0
# 4   4.0   7.0  10.0

補間する連続欠損値の最大数を指定: 引数limit

欠損値が連続している場合、最大でいくつの欠損値を補間するかを引数limitで指定します。デフォルトはNoneで連続する欠損値すべてが補間される。

print(df.interpolate(limit=1))
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   1.0   1.0   5.0
# 2   NaN   2.0   NaN
# 3   3.0   2.0   7.0
# 4   4.0   NaN  10.0

補間方向を指定: 引数limit_direction

補間方向は引数limit_directionで'forward', 'backward', 'both'のいずれかを指定します。デフォルトは'forward'。

print(df.interpolate(limit=1, limit_direction='forward'))
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   1.0   1.0   5.0
# 2   NaN   2.0   NaN
# 3   3.0   2.0   7.0
# 4   4.0   NaN  10.0

print(df.interpolate(limit=1, limit_direction='backward'))
#    col1  col2  col3
# 0   0.0   1.0   4.0
# 1   NaN   1.0   NaN
# 2   2.0   2.0   6.0
# 3   3.0   NaN   7.0
# 4   4.0   NaN  10.0

print(df.interpolate(limit=1, limit_direction='both'))
#    col1  col2  col3
# 0   0.0   1.0   4.0
# 1   1.0   1.0   5.0
# 2   2.0   2.0   6.0
# 3   3.0   2.0   7.0
# 4   4.0   NaN  10.0

上述のように、デフォルトでは上端(または左端)の欠損値はそのままとなるが、limit_direction='both'とすると両方とも補間される。

print(df.interpolate(limit_direction='both'))
#    col1  col2  col3
# 0   0.0   1.0   4.0
# 1   1.0   1.0   5.0
# 2   2.0   2.0   6.0
# 3   3.0   2.0   7.0
# 4   4.0   2.0  10.0

内挿のみ or 外挿のみ or 両方を指定: 引数limit_area

補間対象領域は引数limit_areaで指定します。 'inside'だと内挿のみ、'outside'だと外挿のみ、None(デフォルト)だと両方が対象となります。外挿については上述のlimit_directionで前方(上側・左側)、後方(下側・右側)、両方を指定できます。

print(df.interpolate(limit_area='inside'))
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   1.0   1.0   5.0
# 2   2.0   2.0   6.0
# 3   3.0   NaN   7.0
# 4   4.0   NaN  10.0

print(df.interpolate(limit_area='outside'))
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   NaN   1.0   NaN
# 2   NaN   2.0   NaN
# 3   3.0   2.0   7.0
# 4   4.0   2.0  10.0

print(df.interpolate(limit_area='outside', limit_direction='both'))
#    col1  col2  col3
# 0   0.0   1.0   4.0
# 1   NaN   1.0   NaN
# 2   NaN   2.0   NaN
# 3   3.0   2.0   7.0
# 4   4.0   2.0  10.0

オブジェクト自体を更新するかを指定: 引数inplace

ほかの多くのメソッドと同様、引数inplaceでオブジェクト自体を更新するかどうかを指定できます。

df_copy = df.copy()
df_copy.interpolate(inplace=True)
print(df_copy)
#    col1  col2  col3
# 0   0.0   NaN   4.0
# 1   1.0   1.0   5.0
# 2   2.0   2.0   6.0
# 3   3.0   2.0   7.0
# 4   4.0   2.0  10.0

補間方法: 引数method

補間方法は第一引数methodに指定します。デフォルトはmethod='linear'で線形補間。

線形補間: linear, index, values

method='linear'(デフォルト)ではインデックス列が数値でも特に考慮されないが、method='index'またはmethod='values'とするとインデックス列を考慮して補間される。インデックス列をY軸、対象の列をX軸として線形補間するイメージ。 以下の例ではインデックス5の値がmethod='linear'(デフォルト)では2.0、method='index'またはmethod='values'では2.5となります。

s = pd.Series([0, pd.np.nan, pd.np.nan, pd.np.nan, 4, pd.np.nan, pd.np.nan],
              index=[0, 2, 5, 6, 8, 10, 14])
print(s)
# 0     0.0
# 2     NaN
# 5     NaN
# 6     NaN
# 8     4.0
# 10    NaN
# 14    NaN
# dtype: float64

print(s.interpolate())
# 0     0.0
# 2     1.0
# 5     2.0
# 6     3.0
# 8     4.0
# 10    4.0
# 14    4.0
# dtype: float64

print(s.interpolate('index'))
# 0     0.0
# 2     1.0
# 5     2.5
# 6     3.0
# 8     4.0
# 10    4.0
# 14    4.0
# dtype: float64

print(s.interpolate('values'))
# 0     0.0
# 2     1.0
# 5     2.5
# 6     3.0
# 8     4.0
# 10    4.0
# 14    4.0
# dtype: float64

デフォルトのmethod='linear'はインデックス列が文字列でもOKだが、method='index'またはmethod='values'だとエラーとなります。

s.index = list('abcdefg')
print(s)
# a    0.0
# b    NaN
# c    NaN
# d    NaN
# e    4.0
# f    NaN
# g    NaN
# dtype: float64

print(s.interpolate())
# a    0.0
# b    1.0
# c    2.0
# d    3.0
# e    4.0
# f    4.0
# g    4.0
# dtype: float64

# print(s.interpolate('values'))
# TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'

スプライン補間: spline

method='spline'とするとスプライン補間。同時に引数orderに次数を指定する必要があります。

s = pd.Series([0, 10, pd.np.nan, pd.np.nan, 4, pd.np.nan, pd.np.nan],
              index=[0, 2, 5, 6, 8, 10, 14])

print(s.interpolate('spline', order=2))
# 0      0.00
# 2     10.00
# 5     13.75
# 6     12.00
# 8      4.00
# 10   -10.00
# 14   -56.00
# dtype: float64

スプライン補間は常にインデックス列を考慮して補間される。

s.index = range(7)

print(s.interpolate('spline', order=2))
# 0     0.0
# 1    10.0
# 2    14.0
# 3    12.0
# 4     4.0
# 5   -10.0
# 6   -30.0
# dtype: float64

したがって、スプライン補間する場合はインデックス列が数値である必要があります。文字列だとエラー。

s.index = list('abcdefg')

# print(s.interpolate('spline', order=2))
# TypeError: unsupported operand type(s) for -: 'str' and 'str'

その他

補間方法としては、そのほか、'nearest', 'zero', 'slinear', 'quadratic', 'cubic', 'barycentric', 'krogh', 'polynomial', 'piecewise_polynomial', 'from_derivatives', 'pchip’, ‘akima'が指定可能。 上述のスプライン補間('spline')も含めて、これらはSciPyの関数のラッパー。

Interpolation (scipy.interpolate) — SciPy v1.1.0 Reference Guide

いずれの場合も上述のスプライン補間と同様にインデックスが数値である必要があります。

時系列データの補間

時系列データについては専用の補間方法としてmethod='time'が用意されています。method='time'の場合、インデックス列の日時に合わせて線形補間される。

df_nan = pd.DataFrame({'value': [1, pd.np.nan, pd.np.nan, pd.np.nan, 31]},
                      index=pd.to_datetime(['2018-01-01', '2018-01-02', '2018-01-15', '2018-01-20', '2018-01-31']))

print(df_nan)
#             value
# 2018-01-01    1.0
# 2018-01-02    NaN
# 2018-01-15    NaN
# 2018-01-20    NaN
# 2018-01-31   31.0

print(df_nan.interpolate())
#             value
# 2018-01-01    1.0
# 2018-01-02    8.5
# 2018-01-15   16.0
# 2018-01-20   23.5
# 2018-01-31   31.0

print(df_nan.interpolate('time'))
#             value
# 2018-01-01    1.0
# 2018-01-02    2.0
# 2018-01-15   15.0
# 2018-01-20   20.0
# 2018-01-31   31.0

時系列データのリサンプリングについては以下の記事を参照。

シェア

関連カテゴリー

Python pandas

pandas参考書『Python for Data Analysis, 2nd Edition』 pandas.Seriesのインデックスと値を入れ替え(スワップ) pandasで分位数・パーセンタイルを取得するquantile pandasで条件に応じて値を代入(where, mask) pandasでカテゴリ変数をダミー変数に変換(get_dummies) pandas参考書『Pythonによるデータ分析入門』の注意点 Python, pandas, seabornでヒートマップを作成 pandas.DataFrame, SeriesとNumPy配列ndarrayを相互に変換 pandas.DataFrame, Seriesを連結するconcat pandas.DataFrameを結合するmerge, join(列・インデックス基準) pandasで特定の文字列を含む行を抽出(完全一致、部分一致) pandas.DataFrame, SeriesとPython標準のリストを相互に変換 pandasで特定の条件を満たす要素数をカウント(全体、行・列ごと) pandasでExcelファイル(xlsx, xls)の書き込み(to_excel) Python, pandas, seabornでペアプロット図(散布図行列)を作成

Last Updated: 6/26/2019, 10:34:03 PM