为什么使用iloc()一种会给出SettingWithCopyWarning,而另一种却没有呢?
问题内容:
在类的方法内部,我使用以下语句:
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
那里我没有错误。为什么我在第一个语句中而不是第二个语句中出现错误?
问题答案:
链索引
正如该站点上的文档和其他几个答案([1],[2])所建议的那样,链索引被认为是不好的做法,应避免使用。
由于似乎没有一种优雅的方法来使用 基于整数位置的索引
(即.iloc
)进行分配而不违反链索引的规则(从pandas开始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
df = pd.DataFrame({'a': ['x', 'y', 'z'], 'c': [3, 2, 1]})
df.iloc[-1]['c'] = 42 # SettingWithCopyWarning: ...
在v0.23.4
链分配方面,熊猫(至少)似乎对混合类型和单一类型数据帧的处理方式不同[3]
def _check_is_chained_assignment_possible(self): """ Check if we are a view, have a cacher, and are of mixed type. If so, then force a setitem_copy check. Should be called just near setting a value Will return a boolean if it we are a view and are cached, but a single-dtype meaning that the cacher should be updated following setting. """ if self._is_view and self._is_cached: ref = self._get_cacher() if ref is not None and ref._is_mixed_type: self._check_setitem_copy(stacklevel=4, t='referant', force=True) return True elif self._is_copy: self._check_setitem_copy(stacklevel=4, t='referant') return False
尽管我不确定这是否意外,但对我来说似乎真的很奇怪。
但是,还有一个老错误,其行为与此类似。
更新
根据开发人员的预期,上述行为。