pandas – fillna、interpolate で欠損値を補間する方法

pandas – fillna、interpolate で欠損値を補間する方法

概要

fillna、interpolate で NaN の値を補間する方法について紹介します。

Advertisement

pandas.Series.interpolate

pandas.Series.interpolate() は、指定した方法で Series の値が NaN の要素を補間します。

Series.interpolate(self, method='linear', axis=0, limit=None, inplace=False, limit_direction='forward', limit_area=None, downcast=None, **kwargs)
引数
名前 デフォルト値
method str ‘linear’
補間方法
axis {0 or ‘index’, 1 or ‘columns’, None} None
補間する軸の方向
limit int, optional
連続する NaN は何個まで補間するかを1以上の整数で指定します。
inplace bool False
inplace で処理を行うかどうか
limit_direction {‘forward’, ‘backward’, ‘both’} ‘forward’
補間する方向
limit_area {None, ‘inside’, ‘outside’} None
補間対象の領域
downcast optional, ‘infer’ or None, defaults to None
downcast=”infer” の場合は、補間した結果、ダウンキャスト可能な場合はキャストします。(例: float -> int)
**kwargs
補間を行う関数に渡すキーワード引数

返り値
名前 説明
Series or None 補間した結果。inplace=True の場合は None。

limit_direction, limit – 補間する方向を設定する

limit_direction で補間を行う方向を指定します。

  • “forward”: 先頭 (最初の NaN でない要素) から末尾にかけて補間を行います。
  • “backward”: 末尾 (最初の NaN でない要素) から先頭にかけて補間を行います。
  • “both”: 「末尾 (最初の NaN でない要素) から先頭」と「末尾 (最初の NaN でない要素) から先頭」の両方向で補間を行います。

limit_direction

limit は、limit_direction 方向に補間する際に、連続する NaN は何個まで補間するか指定します。 例えば、3つ NaN が連続するとき、limit=2 の場合は2個の NaN まで補間します。

limit

limit_direction="both" の場合、以下のように両方向に補間されます。

limit

In [1]:
import pandas as pd
from IPython.display import display

s1 = pd.Series(
    [None, None, 0.0, None, None, 0.84, None, None, 1.82, None, None, 0.42, None, None]
)

data = {"original": s1}
for limit_dir in ["forward", "backward", "both"]:
    s2 = s1.interpolate(method="linear", limit=1, limit_direction=limit_dir)
    data[limit_dir] = s2

pd.concat(data, axis=1).T
0 1 2 3 4 5 6 7 8 9 10 11 12 13
original NaN NaN 0.0 NaN NaN 0.84 NaN NaN 1.82 NaN NaN 0.42 NaN NaN
forward NaN NaN 0.0 0.28 NaN 0.84 1.166667 NaN 1.82 1.353333 NaN 0.42 0.42 NaN
backward NaN 0.0 0.0 NaN 0.56 0.84 NaN 1.493333 1.82 NaN 0.886667 0.42 NaN NaN
both NaN 0.0 0.0 0.28 0.56 0.84 1.166667 1.493333 1.82 1.353333 0.886667 0.42 0.42 NaN

元の Series で値がある点を黒、補間された点を青で描画すると、以下のようになります。

limit_area – 補間対象の領域を設定する

limit_area は、補間対象の領域を指定します。

  • None: すべての NaN を補間対象とします。
  • "inside": 値に囲まれた NaN だけ補間対象とします。
  • "outside": 値に囲まれていない NaN だけ補間対象とします。

limit_area

In [2]:
s1 = pd.Series(
    [None, None, 0.0, None, None, 0.84, None, None, 1.82, None, None, 0.42, None, None]
)

data = {"original": s1}
for limit_area in [None, "inside", "outside"]:
    s2 = s1.interpolate(method="linear", limit_area=limit_area)
    data[limit_area] = s2

pd.concat(data, axis=1).T
0 1 2 3 4 5 6 7 8 9 10 11 12 13
original NaN NaN 0.0 NaN NaN 0.84 NaN NaN 1.82 NaN NaN 0.42 NaN NaN
NaN NaN NaN 0.0 0.28 0.56 0.84 1.166667 1.493333 1.82 1.353333 0.886667 0.42 0.42 0.42
inside NaN NaN 0.0 0.28 0.56 0.84 1.166667 1.493333 1.82 1.353333 0.886667 0.42 NaN NaN
outside NaN NaN 0.0 NaN NaN 0.84 NaN NaN 1.82 NaN NaN 0.42 0.42 0.42

元の Series で値がある点を黒、補間された点を青で描画すると、以下のようになります。 灰色の領域にある NaN は値に囲まれていないので outside、緑色の領域にある NaN は値に囲まれているので inside になります。

method – 補間方法を設定する

method で補間方法を指定できます。

  • splinepolynomial は、order 引数で次元数を指定する必要があります。
  • 値に囲まれていない NaN を補間する方法と値に囲まれている NaN のみ補間する方法があります。スプライン補間のように区間ごとに補間する方法は値に囲まれている NaN しか補間できません。
method 内容 外挿の可否 備考
linear 線形補間
index / values インデックスを考慮した線形補間
barycentric 重心補間
krogh Krogh 補間
pchip 区分的3次エルミート補間
spline スプライン補間 order 引数の指定が必要
nearest 最近傍補間
zero 0次スプライン補間
slinear 1次スプライン補間
quadratic 2次スプライン補間
cubic 3次スプライン補間
polynomial 多項式補間 order 引数の指定が必要
piecewise_polynomial 区間ごとに多項式補間
akima 秋間補間
from_derivatives バーンスタイン基底の多項式による補間
Advertisement

downcast – ダウンキャストが可能の場合はダウンキャストする

downcast="infer" の場合は、補間した結果、ダウンキャストが可能な場合はキャストします。

In [3]:
# NaN 以外はすべて整数だが、NaN が含まれているので型は float
s1 = pd.Series([0, None, None, 1, None, None, 2])
print(s1.dtype)

# NaN が補間されたことによりすべての値が整数になった
s2 = s1.interpolate(method="nearest", downcast="infer")
print(s2.dtype)
float64
int64

pandas.DataFrame.interpolate

pandas.DataFrame.interpolate() は、指定した方法で DataFrame の値が NaN の要素を補間します。行または列ごとに補間を行う事以外は Sereis.interpolate() と使い方は同じです。

In [4]:
df = pd.DataFrame(
    {"A": [0, 0, 0, 0], "B": [None, None, None, None], "C": [1, 1, 1, 1],}, dtype=float
)

# 列ごとに補間する
df.interpolate(axis=1, limit_direction="both")
A B C
0 0.0 0.5 1.0
1 0.0 0.5 1.0
2 0.0 0.5 1.0
3 0.0 0.5 1.0

axis – 補間を行う軸の方向

  • axis=0: 列ごとに補間する
  • axis=1: 行ごとに補間する
In [5]:
df = pd.DataFrame(
    {"A": [0, None, None, 1], "B": [0, None, None, 1], "C": [0, None, None, 1],},
    dtype=float,
)
display(df)

# 列ごとに補間する
display(df.interpolate(axis=0, limit_direction="both"))
A B C
0 0.0 0.0 0.0
1 NaN NaN NaN
2 NaN NaN NaN
3 1.0 1.0 1.0
A B C
0 0.000000 0.000000 0.000000
1 0.333333 0.333333 0.333333
2 0.666667 0.666667 0.666667
3 1.000000 1.000000 1.000000
In [6]:
df = pd.DataFrame(
    {"A": [0, 0, 0, 0], "B": [None, None, None, None], "C": [1, 1, 1, 1],}, dtype=float
)
display(df)

# 行ごとに補間する
display(df.interpolate(axis=1, limit_direction="both"))
A B C
0 0.0 NaN 1.0
1 0.0 NaN 1.0
2 0.0 NaN 1.0
3 0.0 NaN 1.0
A B C
0 0.0 0.5 1.0
1 0.0 0.5 1.0
2 0.0 0.5 1.0
3 0.0 0.5 1.0

pandas.Series.fillna

pandas.Series.fillna() は、Series の値が NaN の要素を指定した方法で埋めます。

Series.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None) → Union[ForwardRef(‘Series’), NoneType]
引数
名前 デフォルト値
value scalar, dict, Series, or DataFrame
補間する値
method {‘backfill’, ‘bfill’, ‘pad’, ‘ffill’, None} None
補間する方法
axis {0 or ‘index’}
補間する軸の方向
inplace bool False
inplace で処理を行うかどうか
limit int None
連続する NaN は何個まで補間するかを1以上の整数で指定します。
downcast dict is None
downcast=”infer” の場合は、補間した結果、ダウンキャスト可能な場合はキャストします。(例: float -> int)

返り値
名前 説明
Series or None 補間した結果
Advertisement

value – 指定した値で埋める

value を指定した場合、NaN はその値で置換されます。

In [7]:
s1 = pd.Series([None, None, 1, None, None, 2, None, None])
s2 = s1.fillna(0)
print(s2)
0    0.0
1    0.0
2    1.0
3    0.0
4    0.0
5    2.0
6    0.0
7    0.0
dtype: float64

dict を指定した場合、NaN のインデックスと同じ dict のキーの値で置換します。 Series を指定した場合、NaN のインデックスと同じ Series のインデックスの値で置換します。 対応するものが存在しない NaN はそのままになります。

In [8]:
s1 = pd.Series([None, None, 1, None, None, 2, None, None])
value = pd.Series([10, 20, 30, 40], index=[0, 1, 3, 6])
s2 = s1.fillna(value)
print(s2)
0    10.0
1    20.0
2     1.0
3    30.0
4     NaN
5     2.0
6    40.0
7     NaN
dtype: float64

method – 指定した方法で埋める

value の代わりに method を指定した場合、以下の方法で補間します。

  • “backfill” / “bfill”: 直前の NaN 以外の値で置換します。
  • “pad” / “ffill”: 直後の NaN 以外の値で置換します。

method

In [9]:
s1 = pd.Series([None, None, 0.0, None, None, 0.84, None, None])

data = {"original": s1}
methods = ["backfill", "bfill", "pad", "ffill"]
for method in methods:
    s2 = s1.fillna(method=method)
    method = f'method="{method}"'
    data[method] = s2

pd.concat(data, axis=1).T
0 1 2 3 4 5 6 7
original NaN NaN 0.0 NaN NaN 0.84 NaN NaN
method=”backfill” 0.0 0.0 0.0 0.84 0.84 0.84 NaN NaN
method=”bfill” 0.0 0.0 0.0 0.84 0.84 0.84 NaN NaN
method=”pad” NaN NaN 0.0 0.00 0.00 0.84 0.84 0.84
method=”ffill” NaN NaN 0.0 0.00 0.00 0.84 0.84 0.84

downcast – ダウンキャストが可能の場合はダウンキャストする

downcast="infer" の場合は、補間した結果、ダウンキャストが可能な場合はキャストします。

In [10]:
# NaN 以外はすべて整数だが、NaN が含まれているので型は float
s1 = pd.Series([0, None, None, 1, None, None, 2])
print(s1.dtype)

# NaN が補間されたことによりすべての値が整数になった
s2 = s1.fillna(0, downcast="infer")
print(s2.dtype)
float64
int64

pandas.DataFrame.fillna

pandas.DataFrame.fillna() は、DataFrame の値が NaN の要素を指定した方法で埋めます。行または列ごとに埋める事以外は Sereis.fillna() と使い方は同じです。

In [11]:
df = pd.DataFrame(
    [
        [1, 1, 1, 1, 1],
        [None, None, None, None, None],
        [2, 2, 2, 2, 2],
        [None, None, None, None, None],
        [3, 3, 3, 3, 3],
    ],
    index=["a", "b", "c", "d", "e"],
    columns=["A", "B", "C", "D", "E"],
    dtype=float,
)
display(df)

# 列ごとに埋める
display(df.fillna(method="ffill", axis=0))
A B C D E
a 1.0 1.0 1.0 1.0 1.0
b NaN NaN NaN NaN NaN
c 2.0 2.0 2.0 2.0 2.0
d NaN NaN NaN NaN NaN
e 3.0 3.0 3.0 3.0 3.0
A B C D E
a 1.0 1.0 1.0 1.0 1.0
b 1.0 1.0 1.0 1.0 1.0
c 2.0 2.0 2.0 2.0 2.0
d 2.0 2.0 2.0 2.0 2.0
e 3.0 3.0 3.0 3.0 3.0
In [12]:
df = pd.DataFrame(
    [
        [1, None, 2, None, 3],
        [1, None, 2, None, 3],
        [1, None, 2, None, 3],
        [1, None, 2, None, 3],
        [1, None, 2, None, 3],
    ],
    index=["a", "b", "c", "d", "e"],
    columns=["A", "B", "C", "D", "E"],
    dtype=float,
)
display(df)

# 行ごとに埋める
display(df.fillna(method="ffill", axis=1))
A B C D E
a 1.0 NaN 2.0 NaN 3.0
b 1.0 NaN 2.0 NaN 3.0
c 1.0 NaN 2.0 NaN 3.0
d 1.0 NaN 2.0 NaN 3.0
e 1.0 NaN 2.0 NaN 3.0
A B C D E
a 1.0 1.0 2.0 2.0 3.0
b 1.0 1.0 2.0 2.0 3.0
c 1.0 1.0 2.0 2.0 3.0
d 1.0 1.0 2.0 2.0 3.0
e 1.0 1.0 2.0 2.0 3.0