Egi*_*ila 3 python copy dataframe pandas
在类的方法中,我使用以下语句:
self.__datacontainer.iloc[-1]['c'] = value
Run Code Online (Sandbox Code Playgroud)
这样做我得到一个“SettingWithCopyWarning:一个值正试图在来自 DataFrame 的切片的副本上设置”
现在我尝试重现此错误并编写以下简单代码:
import pandas, numpy
df = pandas.DataFrame(numpy.random.randn(5,3),columns=list('ABC'))
df.iloc[-1]['C'] = 3
Run Code Online (Sandbox Code Playgroud)
在那里我没有错误。为什么我在第一个语句中出现错误而不是在第二个语句中?
链索引
正如本网站([1]、[2])上的文档和其他几个答案所暗示的那样,链索引被认为是不好的做法,应该避免。
由于似乎没有一种优雅的方式使用基于整数位置的索引(即.iloc)而不违反链索引规则(从 pandas 开始)进行分配v0.23.4,因此建议在任何时候使用基于标签的索引(即.loc)进行分配可能的。
但是,如果您绝对需要按行号访问数据,则可以
df.iloc[-1, df.columns.get_loc('c')] = 42
Run Code Online (Sandbox Code Playgroud)
或者
df.iloc[[-1, 1], df.columns.get_indexer(['a', 'c'])] = 42
Run Code Online (Sandbox Code Playgroud)
熊猫行为古怪
根据我的理解,您在尝试人为重现错误时期望警告是绝对正确的。
到目前为止我发现它取决于数据帧的构造方式
df = pd.DataFrame({'a': [4, 5, 6], 'c': [3, 2, 1]})
df.iloc[-1]['c'] = 42 # no warning
Run Code Online (Sandbox Code Playgroud)
df = pd.DataFrame({'a': ['x', 'y', 'z'], 'c': ['t', 'u', 'v']})
df.iloc[-1]['c'] = 'f' # no warning
Run Code Online (Sandbox Code Playgroud)
df = pd.DataFrame({'a': ['x', 'y', 'z'], 'c': [3, 2, 1]})
df.iloc[-1]['c'] = 42 # SettingWithCopyWarning: ...
Run Code Online (Sandbox Code Playgroud)
在v0.23.4链分配方面,pandas(至少)似乎以不同的方式处理混合类型和单一类型的数据帧[3]
Run Code Online (Sandbox Code Playgroud)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
这对我来说真的很奇怪,尽管我不确定这是否出乎意料。
但是,有一个具有类似行为的旧错误。
更新
根据开发人员的说法,上述行为是预期的。
不要专注于警告。警告只是一个指示,有时它甚至不会在您期望的时候出现。有时您会注意到它的出现不一致。相反,只需避免链接索引或通常使用可能是副本的内容。
您希望按行整数位置和列标签进行索引。这是一种不自然的组合,因为 Pandas 具有按整数位置或标签索引的功能,但不能同时进行。
在这种情况下,您可以通过一次调用对行和列使用整数位置索引iat:
df.iat[-1, df.columns.get_loc('C')] = 3
Run Code Online (Sandbox Code Playgroud)
或者,如果您的索引标签保证是唯一的,您可以使用at:
df.at[df.index[-1], 'C'] = 3
Run Code Online (Sandbox Code Playgroud)
因此,如果没有围绕您的问题操作的上下文,很难回答这个问题,但是pandas 文档很好地涵盖了这一点。
>>> 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
Run Code Online (Sandbox Code Playgroud)
基本上它归结为 - 如果您只能使用单个操作来完成索引操作,请不要将索引操作链接在一起。
>>> df.loc[0, 'C'] = 2 # This is ok
Run Code Online (Sandbox Code Playgroud)
您收到的警告是因为您未能在可能试图修改的原始数据框中设置一个值 - 相反,您已复制它并将某些内容设置到副本中(通常当我遇到这种情况时,我甚至没有对副本的引用,它只是被垃圾收集,所以警告非常有帮助)