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

1 一个警告

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

2 警告是什么

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

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

3 重要概念

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

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

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

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

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

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

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

4 链式赋值

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

  1. In [2]: df = pd.DataFrame({'name':['gz','lg','zx'],'score':[80,70,90]})
  2. In [3]: df
  3. Out[3]:
  4. name score
  5. 0 gz 80
  6. 1 lg 70
  7. 2 zx 90
  8. In [5]: df[df['name']=='gz']['score']=85
  9. /export/gz/conda3/bin/ipython:1: SettingWithCopyWarning:
  10. A value is trying to be set on a copy of a slice from a DataFrame.
  11. Try using .loc[row_indexer,col_indexer] = value instead
  12. 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 – 完全关闭警告

例如,如果要关闭警告:

  1. pd.set_option('mode.chained_assignment', None)
  2. 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://zhuanlan.zhihu.com/p/62736380
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞