它well known(和understandable)在分配切片时,pandas行为基本上是不可预测的。但我过去常常通过SettingWithCopy
警告来警告它。
为什么警告不会在以下两个代码段中生成,哪些技术可以减少无意中编写此类代码的可能性?
# pandas 0.18.1, python 3.5.1
import pandas as pd
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data[['a', 'b']]
data = data['a']
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
data[0] == 1
True
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data['a']
data = data['a']
new_data.loc[0] = 100 # no warning, propagates to data
data[0] == 100
True
我认为解释是当父数据帧仍可从当前上下文访问时,pandas仅生成警告。 (这将是检测算法的一个弱点,正如我之前的例子所示。)
在下一个片段中,AFAIK原来的两列DataFrame不再可访问,但pandas警告机制设法触发(幸运的是):
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data['a']
data = data[['a']]
new_data.loc[0] = 100 # warning, so we're safe
编辑:
在调查此事时,我发现另一个失踪警告案例:
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
data = data.groupby('a')
new_data = data.filter(lambda g: len(g)==1)
new_data.loc[0, 'a'] = 100 # no warning, does not propagate to data
assert data.filter(lambda g: True).loc[0, 'a'] == 1
即使几乎相同的例子确实会触发警告:
data = pd.DataFrame({'a': [1, 2, 2], 'b': ['a', 'b', 'c']})
data = data.groupby('a')
new_data = data.filter(lambda g: len(g)==1)
new_data.loc[0, 'a'] = 100 # warning, does not propagate to data
assert data.filter(lambda g: True).loc[0, 'a'] == 1
更新:我在这里回答了@firelynx的回答,因为很难将其放在评论中。
在回答中,@ firelynx说第一个代码片段没有警告,因为我占用了整个数据帧。但即使我参与其中,我仍然没有收到警告:
# pandas 0.18.1, python 3.5.1
import pandas as pd
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c'], c: range(3)})
new_data = data[['a', 'b']]
data = data['a']
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
data[0] == 1
True
答案 0 :(得分:2)
您创建的Dataframe不是视图
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
data._is_view
False
new_data也不是视图,因为您正在使用所有列
new_data = data[['a', 'b']]
new_data._is_view
False
现在您要将数据指定为Series 'a'
data = data['a']
type(data)
pandas.core.series.Series
哪个是视图
data._is_view
True
现在您更新非副本new_data
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
这不应该发出警告。这是整个数据框架。
您创建的Series
标记为视图,但它不是DataFrame,并且不像DataFrame视图那样。
系列与数据帧问题在熊猫中非常常见[如果你曾经使用过一段时间的熊猫,则不需要引用]
问题是你应该一直写作
data[['a']]
不是data['a']
Left创建一个数据框视图,右边创建一个系列。
有些人可能会争辩永远不会写data['a']
而是会data.a
。因此,您可以为您的环境添加警告data['a']
代码。
这不起作用。首先使用data.a
语法会导致认知失调。
数据框是列的集合。在python中,我们使用[]
运算符访问集合的成员。我们通过.
运算符访问属性。切换这些会导致任何python程序员的认知失调。特别是当你开始做del data.a
之类的事情并注意到它不起作用时。 See this answer for more extensive explaination
很难看出data[['a']]
和data['a']
这是一种气味。我们应该既不。
使用干净代码原则和蟒蛇的正确方法“明确比隐含更好”
就是这样:
columns = ['a']
data[columns]
这可能不是那么令人难以置信,但请看下面的例子:
data[['ad', 'cpc', 'roi']]
这是什么意思?这些专栏是什么?你在这里得到什么数据?
在阅读这行代码时,这是第一个到达任何人头脑的问题。
如何解决?不要发表评论。
ad_performance_columns = ['ad', 'cpc', 'roi']
data[ad_performance_columns]
更明确的总是更好。
有关更多信息,请考虑购买干净代码的书籍。也许this one