Pandas 2.2.3中如何正确使用infer_objects解决diff+fillna的类型降转警告
我在Pandas 2.2.3中尝试了以下示例:
outage_mask = pd.Series(([True]*5 + [False]*5)*5, index=pd.date_range("2025-01-01", freq="1h", periods=50)) [ts for ts in outage_mask.loc[outage_mask.diff().fillna(False)].index]
运行后出现了如下警告:
FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set
pd.set_option('future.no_silent_downcasting', True)
我搞不清楚该如何正确应用infer_objects。我猜测问题出在diff的输出因为同时包含NaN和bool类型变成了object dtype,但比如下面这种写法并没有效果:
[ts for ts in outage_mask.loc[outage_mask.diff().infer_objects(copy=False).fillna(False)].index]
我可以用一个笨拙的 workaround 来避免警告:
[ts for ts in outage_mask.loc[outage_mask.diff().astype(float).fillna(0.).astype(bool)].index]
但我想理解如何正确应用警告里提到的解决方案,应该怎么做?
其实问题的核心在于,diff()返回的结果里第一个元素是NaN,而普通布尔类型的Series混入NaN后会自动转为object dtype。你之前直接在diff()后调用infer_objects()没用,是因为此时数据里还存在NaN,而普通bool类型无法容纳NaN,infer_objects()没法把它推断成布尔类型(只有nullable布尔类型pd.BooleanDtype()支持NaN)。
下面给你两种符合警告建议的正确解决方案:
方案一:调整调用顺序,先填充再推断类型
先通过fillna(False)把NaN替换为布尔值,此时所有元素都是布尔类型,再调用infer_objects()就能正确将Series的类型转为bool,避免自动降转的警告:
# 先填充NaN,再推断类型 mask = outage_mask.diff().fillna(False).infer_objects(copy=False) [ts for ts in outage_mask.loc[mask].index]
方案二:启用未来行为选项(一劳永逸)
如果你希望整个代码都遵循Pandas未来的行为规范,可以在代码开头设置这个选项,之后再运行原代码就不会触发警告了:
pd.set_option('future.no_silent_downcasting', True) # 后续正常运行你的代码 outage_mask = pd.Series(([True]*5 + [False]*5)*5, index=pd.date_range("2025-01-01", freq="1h", periods=50)) [ts for ts in outage_mask.loc[outage_mask.diff().fillna(False)].index]
另外,还有一种更简洁的显式类型转换方式,虽然和你的workaround类似,但更直接:
mask = outage_mask.diff().fillna(False).astype(bool) [ts for ts in outage_mask.loc[mask].index]
不过警告里优先推荐使用infer_objects(),所以方案一或方案二更贴合Pandas的设计方向。
备注:内容来源于stack exchange,提问作者Thomas Arildsen

