いくつかのNaN
sを持つDataFrameがあるとします:
>>> import pandas as pd
>>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
>>> df
0 1 2
0 1 2 3
1 4 NaN NaN
2 NaN NaN 9
私がする必要があるのは、その上の同じ列のすべてのNaN
を最初の非NaN
値に置き換えることです。最初の行にNaN
が含まれることはないと想定されています。したがって、前の例では、結果は次のようになります
0 1 2
0 1 2 3
1 4 2 3
2 4 2 9
データフレーム全体を列ごと、要素ごとにループして値を直接設定できますが、これを達成する簡単な(最適なループフリーの)方法はありますか?
DataFrameで fillna
メソッドを使用し、メソッドをffill
(forward fill)として指定できます。
>>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
>>> df.fillna(method='ffill')
0 1 2
0 1 2 3
1 4 2 3
2 4 2 9
この方法...
最後の有効な観測値を次の有効な値に伝播します
逆の方法として、bfill
メソッドもあります。
このメソッドは、DataFrameをインプレースで変更しません。返されたDataFrameを変数に再バインドするか、inplace=True
を指定する必要があります。
df.fillna(method='ffill', inplace=True)
受け入れられた答えは完璧です。関連するが、グループ内でのみ前方に記入する必要があるわずかに異なる状況がありました。誰かが同じニーズを持っている場合、fillnaがDataFrameGroupByオブジェクトで動作することを知ってください。
>>> example = pd.DataFrame({'number':[0,1,2,nan,4,nan,6,7,8,9],'name':list('aaabbbcccc')})
>>> example
name number
0 a 0.0
1 a 1.0
2 a 2.0
3 b NaN
4 b 4.0
5 b NaN
6 c 6.0
7 c 7.0
8 c 8.0
9 c 9.0
>>> example.groupby('name')['number'].fillna(method='ffill') # fill in row 5 but not row 3
0 0.0
1 1.0
2 2.0
3 NaN
4 4.0
5 4.0
6 6.0
7 7.0
8 8.0
9 9.0
Name: number, dtype: float64
pandas.DataFrame.fillna
をmethod='ffill'
オプションとともに使用できます。 'ffill'
は 'forward fill'の略で、最後の有効な観測を前方に伝播します。代替手段は'bfill'
で、同じように機能しますが、逆方向に機能します。
import pandas as pd
df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
df = df.fillna(method='ffill')
print(df)
# 0 1 2
#0 1 2 3
#1 4 2 3
#2 4 2 9
物事を簡単にするために、このための直接同義語関数 pandas.DataFrame.ffill
もあります。
この解決策を試してみたときに気づいたことの1つは、配列の最初または最後にN/Aがある場合、ffillとbfillはまったく機能しないことです。両方が必要です。
In [224]: df = pd.DataFrame([None, 1, 2, 3, None, 4, 5, 6, None])
In [225]: df.ffill()
Out[225]:
0
0 NaN
1 1.0
...
7 6.0
8 6.0
In [226]: df.bfill()
Out[226]:
0
0 1.0
1 1.0
...
7 6.0
8 NaN
In [227]: df.bfill().ffill()
Out[227]:
0
0 1.0
1 1.0
...
7 6.0
8 6.0
ffill
メソッドに同意するだけですが、もう1つの情報は、キーワード引数limit
を使用してフォワードフィルを制限できることです。
>>> import pandas as pd
>>> df = pd.DataFrame([[1, 2, 3], [None, None, 6], [None, None, 9]])
>>> df
0 1 2
0 1.0 2.0 3.0
1 NaN NaN 6.0
2 NaN NaN 9.0
>>> df[1].fillna(method='ffill', inplace=True)
>>> df
0 1 2
0 1.0 2.0 3.0
1 NaN 2.0 NaN
2 NaN 2.0 9.0
キーワード引数にlimit
が追加されました
>>> df[0].fillna(method='ffill', limit=1, inplace=True)
>>> df
0 1 2
0 1.0 2.0 3
1 1.0 2.0 6
2 NaN 2.0 9
ffill
には独自のメソッドがあります pd.DataFrame.ffill
df.ffill()
0 1 2
0 1.0 2.0 3.0
1 4.0 2.0 3.0
2 4.0 2.0 9.0
1列のみのバージョン
df[column_name].fillna(method='ffill', inplace=True)
df[column_name].fillna(method='backfill', inplace=True)
私の場合、異なるデバイスからの時系列がありますが、いくつかのデバイスはある期間中に値を送信できませんでした。したがって、すべてのデバイスと期間についてNA値を作成し、その後でfillnaを実行する必要があります。
df = pd.DataFrame([["device1", 1, 'first val of device1'], ["device2", 2, 'first val of device2'], ["device3", 3, 'first val of device3']])
df.pivot(index=1, columns=0, values=2).fillna(method='ffill').unstack().reset_index(name='value')
結果:
0 1 value
0 device1 1 first val of device1
1 device1 2 first val of device1
2 device1 3 first val of device1
3 device2 1 None
4 device2 2 first val of device2
5 device2 3 first val of device2
6 device3 1 None
7 device3 2 None
8 device3 3 first val of device3