在类的方法中,我使用以下语句:
self.__datacontainer.iloc[-1]['c'] = value
这样做我得到一个 “ SettingWithCopyWarning: 试图在DataFrame的切片副本上设置一个值”
现在我试图重现此错误并编写以下简单代码:
import pandas, numpy
df = pandas.DataFrame(numpy.random.randn(5,3),columns=list('ABC'))
df.iloc[-1]['C'] = 3
我没有错误。为什么我在第一条语句而不是第二条语句中出现错误?
答案 0 :(得分:2)
因此,在没有问题操作上下文的情况下很难回答这个问题,但是the pandas documentation很好地覆盖了这一点。
>>> df[['C']].iloc[0] = 2 # This is a problem
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
基本上可以归结为-如果只能使用单个操作来完成索引操作,则不要将它们链接在一起。
>>> df.loc[0, 'C'] = 2 # This is ok
您收到的警告是因为您未能在要尝试修改的原始数据框中设置值-相反,您已将其复制并设置了一些内容到副本中(通常发生这种情况)对我来说,我什至没有该副本的引用,它只是被垃圾收集,因此警告非常有帮助)
答案 1 :(得分:2)
链索引
正如documentation和此站点上的其他几个答案([1],[2])所建议的那样,链索引被认为是不好的做法,应避免使用。
因为似乎没有一种优美的方式来使用基于整数位置的索引(即.iloc
)而不违反链索引的规则(从熊猫{{1 }}),建议您尽可能使用基于标签的索引(即v0.23.4
)进行分配。
但是,如果您绝对需要按行号访问数据,则可以
.loc
或
df.iloc[-1, df.columns.get_loc('c')] = 42
熊猫的行为异常
根据我的理解,当您试图人为地再现错误时,绝对可以期待警告。
到目前为止,我发现它取决于数据帧的构造方式
df.iloc[[-1, 1], df.columns.get_indexer(['a', 'c'])] = 42
df = pd.DataFrame({'a': [4, 5, 6], 'c': [3, 2, 1]})
df.iloc[-1]['c'] = 42 # no warning
df = pd.DataFrame({'a': ['x', 'y', 'z'], 'c': ['t', 'u', 'v']})
df.iloc[-1]['c'] = 'f' # no warning
在分配链[3]时,熊猫(至少df = pd.DataFrame({'a': ['x', 'y', 'z'], 'c': [3, 2, 1]})
df.iloc[-1]['c'] = 42 # SettingWithCopyWarning: ...
)似乎对混合类型和单一类型数据帧的处理方式不同
v0.23.4
这对我来说确实很奇怪,尽管我不确定这是否是不可预期的。
但是,有一个旧的bug具有类似的行为。
更新
根据developers,上述行为是可以预期的。
答案 2 :(得分:2)
不要专注于警告。警告只是一个指示,有时甚至不会出现when you expect it should。有时您会注意到它occurs inconsistently。相反,只需避免chained indexing或通常使用可能是副本的方式。
您希望通过行整数位置和列标签建立索引。鉴于熊猫具有通过整数位置或标签(但不能同时 )进行索引的功能,所以这是不自然的混合。
在这种情况下,您可以通过单个iat
调用对行和列使用整数位置索引:
df.iat[-1, df.columns.get_loc('C')] = 3
或者,如果您的索引标签得到了保证唯一,则可以使用at
:
df.at[df.index[-1], 'C'] = 3