如何在Pandas DataFrame中生成状态列并规避SettingWithCopy警告
问题描述
我需要给DataFrame添加状态列,规则如下:
- 所有大于3的值标记为"Fail"
- 介于1和3之间的值标记为"Caution"
- 其余标记为"Pass"
当前代码运行时触发SettingWithCopyWarning警告,虽然用lambda列表推导式规避了警告,但希望用Pandas原生方法实现需求。
触发警告的代码
import pandas as pd values = range(6) df = pd.DataFrame({"Values":values, "Caution limit": [1]*len(values), "Fail limit": [3]*len(values)}) df["Status"] = "Pass" df["Status"][df["Caution limit"] < df["Values"]] = "Caution" df["Status"][df["Fail limit"] < df["Values"]] = "Fail"
警告信息
C:\.....py:5: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df["Status"][df["Caution limit"] < df["Values"]] = "Caution" C:\.....py:6: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df["Status"][df["Fail limit"] < df["Values"]] = "Fail"
非原生Pandas的lambda替代方法
update_status = lambda value, caution, failed: ["Fail" if f<v else "Caution" if c<v else "Pass" for v,c,f in zip(value, caution, failed)] df["Status"] = update_status(df["Values"],df["Caution limit"],df["Fail limit"])
Pandas原生解决方案
方案1:使用loc索引消除警告
原代码的警告源于链式索引df["Status"][...]可能操作的是DataFrame的副本,改用loc可以直接对原DataFrame进行赋值操作,彻底避免警告:
import pandas as pd values = range(6) df = pd.DataFrame({"Values":values, "Caution limit": [1]*len(values), "Fail limit": [3]*len(values)}) df["Status"] = "Pass" # 先设置Caution,再设置Fail(Fail优先级更高) df.loc[df["Caution limit"] < df["Values"], "Status"] = "Caution" df.loc[df["Fail limit"] < df["Values"], "Status"] = "Fail"
方案2:使用numpy.select实现多条件映射
这是Pandas兼容的向量化方法,适合多分支条件场景,一次性生成状态列,代码更简洁:
import pandas as pd import numpy as np values = range(6) df = pd.DataFrame({"Values":values, "Caution limit": [1]*len(values), "Fail limit": [3]*len(values)}) # 定义条件列表和对应结果 conditions = [ df["Fail limit"] < df["Values"], df["Caution limit"] < df["Values"], True # 匹配所有剩余情况 ] choices = [ "Fail", "Caution", "Pass" ] df["Status"] = np.select(conditions, choices)
方案3:使用pd.cut按数值区间划分
如果阈值是固定数值(如本例的1和3),可以直接用pd.cut按区间映射状态,代码最简洁:
import pandas as pd values = range(6) df = pd.DataFrame({"Values":values, "Caution limit": [1]*len(values), "Fail limit": [3]*len(values)}) df["Status"] = pd.cut( df["Values"], bins=[-float("inf"), 1, 3, float("inf")], labels=["Pass", "Caution", "Fail"], include_lowest=True # 确保等于1的值被归入Pass区间 )
内容的提问来源于stack exchange,提问作者Gооd_Mаn
相关产品推荐
相关产品推荐

