Python一个万万不能忽略的警告!

1 一个警告

Pandas中有一个警告,很有意思,并且出现频率很高,它就是 SettingWithCopyWarning, 既然是个警告,那么我们是不是可以忽略呢。就像标题说的那样,万万不可。并且,这个警告还要引起我们足够重视。知道为什么会出现这个警告,并知道怎么解决,或许帮助你真正从pandas的被动使用者,变为一个Pandas专家。

2 警告是什么

首先要理解的是,SettingWithCopyWarning 是一个警告,而不是错误 Erro,警告的作用是提醒程序员,他们的代码可能存在潜在的错误或问题,但是这些操作仍然是该编程语言中的合法操作。在这种情况下,警告很可能表明一个严重但不容易意识到的错误。

SettingWithCopyWarning 告诉你,你的操作可能没有按预期运行,你应该检查结果以确保没有出错。在采取下一步行动之前,花点时间了解为什么会获得这一警告。

3 重要概念

要了解 SettingWithCopyWarning,首先需要了解 Pandas 中的某些操作可以返回数据的视图(View),而某些操作将返回数据的副本(Copy)。

视图就是原来数据的一部分,而副本是新生成的数据,和原来没有一毛钱关系。

赋值(Assignment) - 设置某些变量值的操作,例如

data = pd.read_csv('**.csv')

访问(Access) - 返回某些值的操作,例如下面的索引和链式索引示例

索引(Indexing) - 引用数据子集的任何赋值或访问方法,例如 data[1:5]

链式索引(Chaining) - 连续使用多个索引操作,例如data[1:5][1:3]

4 链式赋值

链式赋值是链式索引和赋值的组合。造一组数据,让它出现这个warning

In [2]: df = pd.DataFrame({'name':['gz','lg','zx'],'score':[80,70,90]})                                                                                                    
In [3]: dfOut[3]:   name  score0   gz     801   lg     702   zx     90In [5]: df[df['name']=='gz']['score']=85                                                                                                                                   /export/gz/conda3/bin/ipython:1: SettingWithCopyWarning: 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
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

可以看到,我们很容易地就调出了这个warning,并且可以看出链式赋值的基本操作过程,首先,df[df['name']] 返回的是副本,也就是重新生成了一个对象,然后再对满足条件的行,其列score赋值,当然和原数据没有任何关系了。

5 配置警告

Pandas 的 mode.chained_assignment 选项可以采用以下几个值之一:

'raise' - 抛出异常(exception)而不是警告

'warn' - 生成警告(默认)

None - 完全关闭警告

例如,如果要关闭警告:

pd.set_option('mode.chained_assignment', None)data[data.bidder == 'parakeet2004']['bidderrate'] = 100

因为这样没有给我们任何警告,除非你完全了解自己在做什么,否则不建议这样做。如果你对想要实现的操作有任何一丁点的疑问,关闭警告都不被推荐。有些开发者非常重视 SettingWithCopy 甚至选择将其提升为异常,这样可以避免某些超出预期的行为出现。

6 追溯历史

你可能想知道为什么要造成这么混乱的现状,为什么不明确指定索引方法是返回视图还是副本,来完全避免 SettingWithCopy 问题。要理解这一点,我们必须研究 Pandas 的过去。

Pandas 确定返回一个视图还是一个副本的逻辑,源于它对 NumPy 库的使用,这是 Pandas 库的基础。视图实际上是通过 NumPy 进入 Pandas 的词库的。实际上,视图在 NumPy 中很有用,因为它们能够可预测地返回。由于 NumPy 数组是单一类型的,因此 Pandas 尝试使用最合适的 dtype 来最小化内存处理需求。因此,包含单个 dtype 的 DataFrame 切片可以作为单个 NumPy 数组的视图返回,这是一种高效处理方法。但是,多类型的切片不能以相同的方式存储在 NumPy 中。Pandas 兼顾多种索引功能,并且保持高效地使用其 NumPy 内核的能力。

最终,Pandas 中的索引被设计为有用且通用的方式,其核心并不完全与底层 NumPy 数组的功能相结合。随着时间的推移,这些设计和功能元素之间的相互作用,导致了一组复杂的规则,这些规则决定了返回视图还是副本。经验丰富的 Pandas 开发者通常都很满意 Pandas 的做法,因为他们可以轻松地浏览其索引行为。

7 总结

不幸的是,对于 Pandas 的新手来说,链式索引几乎是不可避免的,因为 get 操作返回的就是可索引的 Pandas 对象。此外,用 Pandas 的核心开发人员之一 Jeff Reback 的话来说,“从语言的角度来看,直接检测链式索引是不可能的,必须经过推断才能了解”。幸运的是,解决警告只需要识别链式赋值并修复。如果整篇文章你只了解到了一件事,那么就应该是这一点。

写作这篇文章主要参考了网络 https://www.jianshu.com/p/72274ccb647a,原文有些冗长,我将核心摘取出来,中间添加了自己书写的例子和部分理解。

期望大家积极参与送书活动,会在本周四送出如下经典书籍,2本。您也可以点击链接购买。感谢机械工业出版社的大力支持!

原文发布于微信公众号 - Python与机器学习算法频道(alg-channel)

原文发表时间:2019-04-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券