背景
我刚刚把我的Pandas从0.11升级到了0.13.0rc1。现在,该应用程序正在弹出许多新的警告。其中一个是这样的:
E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
我想知道它到底是什么意思?我需要改变什么吗?
如果我坚持使用,我应该如何暂停警告 quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
?
给出错误的函数
def _decode_stock_quote(list_of_150_stk_str):
"""decode the webpage and return dataframe"""
from cStringIO import StringIO
str_of_all = "".join(list_of_150_stk_str)
quote_df = pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
quote_df.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
quote_df['TClose'] = quote_df['TPrice']
quote_df['RT'] = 100 * (quote_df['TPrice']/quote_df['TPCLOSE'] - 1)
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
quote_df['TAmt'] = quote_df['TAmt']/TAMT_SCALE
quote_df['STK_ID'] = quote_df['STK'].str.slice(13,19)
quote_df['STK_Name'] = quote_df['STK'].str.slice(21,30)#.decode('gb2312')
quote_df['TDate'] = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
return quote_df
更多错误消息
E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
E:\FinReporter\FM_EXT.py:450: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TAmt'] = quote_df['TAmt']/TAMT_SCALE
E:\FinReporter\FM_EXT.py:453: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TDate'] = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
5条答案
按热度按时间vfhzx4xs1#
这个
SettingWithCopyWarning
创建时标记可能会混淆的“链接”分配,例如以下分配,但这些分配并不总是按预期工作,特别是当第一个选择返回副本时[背景讨论见gh5390和gh5597。]警告建议重写如下:
但是,这不适合您的使用,这相当于:
很明显,您不关心写操作返回到原始帧(因为您正在覆盖对它的引用),但不幸的是,此模式无法与第一个链式赋值示例区分开来。因此出现了(假阳性)警告。如果您想进一步阅读,关于索引的文档中会提到误报的可能性。您可以通过以下分配安全地禁用此新警告。
其他资源
Pandas用户指南:索引和选择数据
python数据科学手册:数据索引和选择
真正的python:settingwithcopywarning在pandas中:视图与副本
dataquest:settingwithcopywarning:如何修复pandas中的此警告
走向数据科学:解释Pandas的复制警告设置
rggaifut2#
如何处理Pandas中的复制警告设置?
这篇文章是为那些,
希望了解此警告的含义
希望了解抑制此警告的不同方式
希望了解如何改进他们的代码并遵循良好实践,以避免将来出现此警告。
设置
CopyWarning的设置是什么?
要知道如何处理这一警告,重要的是要理解它的含义以及为什么首先提出这一警告。
过滤 Dataframe 时,根据内部布局和各种实现细节,可以对帧进行切片/索引以返回视图或副本。顾名思义,“视图”是指向原始数据的视图,因此修改视图可能会修改原始对象。另一方面,“副本”是原始数据的复制,修改副本对原始数据没有影响。
正如其他答案所提到的
SettingWithCopyWarning
已创建以标记“链接分配”操作。考虑df
在上面的设置中。假设您希望选择列“b”中的所有值,其中列“a”中的值大于5。pandas允许您以不同的方式执行此操作,有些方法比其他方法更正确。例如以及,
它们返回相同的结果,因此,如果您只读取这些值,则不会产生任何差异。那么,问题是什么?链式赋值的问题是,通常很难预测是否返回视图或副本,因此在尝试重新赋值时,这在很大程度上成为一个问题。要在前面的示例中构建,请考虑解释器如何执行此代码:
带着一个
__setitem__
召唤df
. Otoh,考虑这个代码:现在,取决于
__getitem__
返回了一个视图或副本__setitem__
操作可能不起作用。一般来说,您应该使用
loc
用于基于标签的分配,以及iloc
对于基于整数/位置的指定,因为规范保证它们始终对原始对象进行操作。此外,对于设置单个单元格,应使用at
及iat
.更多信息可在文档中找到。
笔记
使用完成的所有布尔索引操作
loc
也可以用iloc
. 唯一的区别是iloc
索引需要整数/位置或布尔值的numpy数组,列需要整数/位置索引。例如
可以写入nas
以及,
可以写成
等等
请告诉我如何抑制警告!
考虑“A”列的简单操作
df
. 选择“a”并除以2将发出警告,但操作将起作用。有两种方法可以直接消除此警告:
(推荐)使用
loc
要切片子集,请执行以下操作:改变
pd.options.mode.chained_assignment
可以设置为None
,"warn"
或"raise"
."warn"
是默认值。None
将完全抑制警告,并且"raise"
将抛出一个SettingWithCopyError
,防止操作通过。制造
deepcopy
```df2 = df'A'.copy(deep=True)
df2['A'] /= 2
class ChainedAssignent:
def init(self, chained=None):
acceptable = [None, 'warn', 'raise']
assert chained in acceptable, "chained must be in " + str(acceptable)
self.swcw = chained
some code here
with ChainedAssignent():
df2['A'] /= 2
more code follows
with ChainedAssignent(chained='raise'):
df2['A'] /= 2
SettingWithCopyError:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
df
A B C D E
0 5 0 3 3 7
1 9 3 5 2 4
2 7 6 8 8 1
A B C D E
0 5 0 3 3 7
1 1000 3 5 2 4
2 1000 6 8 8 1
df.A[df.A > 5] = 1000 # works, because df.A returns a view
df[df.A > 5]['A'] = 1000 # does not work
df.loc[df.A 5]['A'] = 1000 # does not work
df.loc[df.A > 5, 'A'] = 1000
A B C D E
0 5 0 3 3 7
1 9 3 5 12345 4
2 7 6 8 8 1
df.loc[1, 'D'] = 12345
df.iloc[1, 3] = 12345
df.at[1, 'D'] = 12345
df.iat[1, 3] = 12345
A B C D E
1 9 3 5 2 4
2 7 6 8 8 1
df2.loc[df2.C == 5, 'D'] = 123
df2 = df[df.A > 5]
df2 = df[df.A > 5].copy()
Or,
df2 = df.loc[df.A > 5, :]
A B C D E
1 9 3 5 2 4
2 7 6 8 8 1
df2.drop('C', axis=1, inplace=True)
df2 = df[df.A > 5]
drkbr07n3#
总的来说
SettingWithCopyWarning
是向用户(尤其是新用户)显示,他们可能是在拷贝上操作,而不是他们认为的原始操作。有误报(如果你知道你在做什么,那就可以了)。一种可能是按照@garrett的建议关闭(默认警告)警告。这是另一个选择:
您可以设置
is_copy
向False
,这将有效地关闭该对象的检查:如果显式复制,则不会发生进一步的警告:
op上面显示的代码虽然是合法的,可能我也会这么做,但从技术上讲,它是针对这个警告的,而不是误报。另一种没有警告的方法是通过执行选择操作
reindex
,例如。或
bxgwgixi4#
Dataframe 复制警告
当你去做这样的事情时:
df = pd.DataFrame({"a": [1,2,3,4], "b": [1,1,2,2]})
dfcopy = df.ix[:,["a"]]
dfcopy.a.ix[0] = 2
行为二:这将更改原始 Dataframe 。
改为使用.loc
Pandas开发商认识到
.ix
对象相当臭[推测],因此创建了两个新对象,这有助于数据的存取和分配(另一个存在.iloc
).loc
速度更快,因为它不尝试创建数据的副本。.loc
是为了修改现有的 Dataframe ,这更节省内存。.loc
是可预测的,它有一个行为。解决方案
在代码示例中,您正在加载一个包含许多列的大文件,然后将其修改为更小的文件。
这个
pd.read_csv
函数可以帮助您解决很多问题,还可以加快文件的加载速度。因此,与其这样做
这样做
这将只读取您感兴趣的列,并正确命名它们。没有必要使用邪恶
.ix
反对做神奇的事情。xfyts7mz5#
在这里,我直接回答这个问题。如何处理?
制造
.copy(deep=False)
在你切完之后。请参阅pandas.dataframe.copy。等等,切片不返回副本吗?毕竟,这就是警告信息试图表达的意思?阅读长答案:
这是一个警告:
这并不是:
二者都
df0
及df1
是DataFrame
对象,但它们的某些方面有所不同