Anders Wang


我所认识的每个人都是榜样,都有值得我去尊敬和学习的地方。


SettingwithCopyWarning在pandas中的解决方案

我在用Pandas对数据集做处理的时候会容易被抛出SettingWithCopyWarning警告信息,我相信很多人都会对它视而不见。其实,SettingWithCopyWarning 警告不应该被忽略,因为出现该警告正说明你的代码执行的结果可能没有按预期运行,需要检查结果,这是Pandas的针对链式赋值(Chained Assignment)的保护机制导致的结果。。如果视而不见的话当代码量足够大的时候再去排查就更加困难了。

如下我先模拟一个数据集来说明如何解决这个问题,以DataFrame类型为数据集输出10行6列数据。

既然这篇文章要说明的是SettingWithCopyWarning的解决方案,那首先要知道SettingWithCopyWarning什么时候才会遇到,它是如何产生的。

在演示如何产生SettingWithCopyWarning警告前,我打算先说明一个知识点,那就是当对DataFrame数据进行操作的时候会出现浅拷贝(Shallow Copy)与深拷贝(Deep Copy)两种模式。下图描述了浅拷贝和深拷贝的区别,假设B复制了A,当修改B时,如果A也跟着变了,说明这是浅拷贝。如果A没变,那就是深拷贝。

说的简单点就是浅拷贝只是创建了对象的一个引用,而深拷贝则是创建了对象的一个独立的实体副本。

明白了深浅拷贝的区别后,来看如下例子,下图代码的意图是从数据中筛选出所有性别为性的数据,后面会打算把这些数据设置为数字0。

注意,下面的代码打算把这些数据设置为数字0时因为使用多个中括号来索引操作,也就是显式链式赋值的方式。第一次是访问操作(get),返回一个 DataFrame列出了所有包含性别为的数据,然后第二个是赋值操作(set)对gender列数据赋值为0,而这个赋值操作是在筛选出所有性别为的这个新的 DataFrame 数据集上运行的,而压根没有在原始 DataFrame 数据集上运行。

这个时候pandas就分不清到底你是对数据做深拷贝还是浅拷贝操作,也就是修改的数据是本身还是独立的,更不知道最后得出来的结果是不是你想要的,简单理解,就是pandas无法对通过两个方括号选取的数据赋值。最后就产生模棱两可的状态于是就抛出了SettingWithCopyWarning警告。

可以看到,当赋值操作后再次输出data的数据后,发现gender数据里的数据并没有被修改为0,说明pandas分不清到底你是对数据做深拷贝还是浅拷贝操作,代码执行的结果没有按预期运行。这也就是之前提到为什么遇到SettingWithCopyWarning警告时不能视而不见的原因了。

解决方案(一)

这个解决方案很简单:使用 loc 将链式操作组合到一个 方括号[ ] 操作中,这样用检索所条件作为loc的行列参数,将两次索引变成一次,以便 Pandas 可以确保 set 操作是在原始 DataFrame上执行。Pandas 会始终确保下面这样的非链式 set 操作起作用。其实这个方案也正是SettingWithCopyWarning里建议的操作方式。

解决方案(二)

另一种解决方案就是使用隐式赋值的方式。从原始数据中先提取自己想要的数据后并赋值保存给另一个变量,然后再对这个新变量对象进行操作。

可以从上面的结果看到,代码成功修改了数据值。但是依然出现了SettingWithCopyWarning警告信息,原因是通过隐式赋值变量的方式传递数据pandas不能保证修改的是本身数据。

所以,要解决这个警告信息的办法就是明确使用copy()方法,告诉它我创建的是一个独立副本。

这样就不会出现任何烦人的警告信息了。但是要注意这种办法并不是在原始的数据集上做修改,而是把需要修改的数据完全单独剥离了出来,所以最终输出的数据也仅仅是被筛选过的。

最后提一个中肯的建议,即使SettingWithCopyWarning警告只在 set 操作时才会发生,但在进行 get 操作时,最好也避免使用链式索引。不仅因为链式操作较慢,而且因为链式索引始终是一个潜在的问题,只要你稍后进行赋值操作,就可能不会影响到原始对象,这可能不是你的预期操作。所以,请不惜一切代价避免使用链式索引。

参考资料:https://www.dataquest.io/blog/settingwithcopywarning/

更早的文章

图解axis=0/1参数的理解使用

在numpy与pandas的使用中,有个常见的参数axis,根据对axis的设定值不同就会得到截然不同的结果。对于如何正确设置axis的参数值,如果有人与我曾经一样有似懂非懂的经历,那一定是在某…

Python, 技术博文详细阅读
comments powered by Disqus