如何用 pandas DataFrame 中的前一个或下一个值替换 NaN?
How to replace NaNs by preceding or next values in pandas DataFrame?
假设我有一个包含一些 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 并直接设置值,但是有没有一种简单的(最好是无循环的)方法来实现这一点?
您可以在 DataFrame 上使用 fillna
方法并将该方法指定为 ffill
(向前填充):
>>> 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
这个方法...
propagate[s] last valid observation forward to next valid
反其道而行之,还有一个bfill
方法。
此方法不会就地修改 DataFrame - 您需要将返回的 DataFrame 重新绑定到变量或指定 inplace=True
:
df.fillna(method='ffill', inplace=True)
您可以使用 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
,让事情变得更简单。
我在尝试此解决方案时注意到的一件事是,如果您在数组的开头或结尾处有 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
现在有了自己的方法 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
接受的答案是完美的。我有一个相关但略有不同的情况,我必须向前填补,但只能在小组内。如果有人有同样的需求,请知道 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
在我的例子中,我们有来自不同设备的时间序列,但有些设备在一段时间内无法发送任何值。所以我们应该为每个设备和时间段创建 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
只有一栏版本
- 用最后一个有效值
填充NAN
df[column_name].fillna(method='ffill', inplace=True)
- 用下一个有效值
填充NAN
df[column_name].fillna(method='backfill', inplace=True)
只是同意 ffill
方法,但一个额外的信息是您可以使用关键字参数 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
1 NaN NaN 6
2 NaN NaN 9
>>> df[1].fillna(method='ffill', inplace=True)
>>> df
0 1 2
0 1.0 2.0 3
1 NaN 2.0 6
2 NaN 2.0 9
现在使用 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
您可以使用 fillna
删除或替换 NaN 值。
NaN 删除
import pandas as pd
df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
df.fillna(method='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
NaN 替换
df.fillna(0) # 0 means What Value you want to replace
0 1 2
0 1.0 2.0 3.0
1 4.0 0.0 0.0
2 0.0 0.0 9.0
假设我有一个包含一些 NaN
s:
>>> 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 并直接设置值,但是有没有一种简单的(最好是无循环的)方法来实现这一点?
您可以在 DataFrame 上使用 fillna
方法并将该方法指定为 ffill
(向前填充):
>>> 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
这个方法...
propagate[s] last valid observation forward to next valid
反其道而行之,还有一个bfill
方法。
此方法不会就地修改 DataFrame - 您需要将返回的 DataFrame 重新绑定到变量或指定 inplace=True
:
df.fillna(method='ffill', inplace=True)
您可以使用 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
,让事情变得更简单。
我在尝试此解决方案时注意到的一件事是,如果您在数组的开头或结尾处有 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
现在有了自己的方法 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
接受的答案是完美的。我有一个相关但略有不同的情况,我必须向前填补,但只能在小组内。如果有人有同样的需求,请知道 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
在我的例子中,我们有来自不同设备的时间序列,但有些设备在一段时间内无法发送任何值。所以我们应该为每个设备和时间段创建 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
只有一栏版本
- 用最后一个有效值 填充NAN
df[column_name].fillna(method='ffill', inplace=True)
- 用下一个有效值 填充NAN
df[column_name].fillna(method='backfill', inplace=True)
只是同意 ffill
方法,但一个额外的信息是您可以使用关键字参数 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
1 NaN NaN 6
2 NaN NaN 9
>>> df[1].fillna(method='ffill', inplace=True)
>>> df
0 1 2
0 1.0 2.0 3
1 NaN 2.0 6
2 NaN 2.0 9
现在使用 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
您可以使用 fillna
删除或替换 NaN 值。
NaN 删除
import pandas as pd
df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
df.fillna(method='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
NaN 替换
df.fillna(0) # 0 means What Value you want to replace
0 1 2
0 1.0 2.0 3.0
1 4.0 0.0 0.0
2 0.0 0.0 9.0