Pandas - A value is trying to be set on a copy of a slice from a DataFrame

(想要直接解决问题的请直接拉到最后)

使用的DataFrame的

 yearstatepopdebt
one2000Ohio1.5NaN
two1000Ohio1.71000
three2002Ohio3.6NaN
four2001Nevada2.4-1.5
five2002Nevada2.9-1.7

 

当使用 frame2['year']['two'] = 10000, 即df名[列名][行名]的方式去赋值就会报错, 提示如下

SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

进入提示网页, 查找与SettingWithCopyWarning有关部分, 这里简单翻译了一下(渣翻译, 推荐大家去看原文, 在最后几部分里)

chained indexing

这就是出现警告的原因, 我们在使用pandas中要极力避免出现chained index)

下面是一个例子解释到底什么是chained indexing

	In [4]: dfmi = pd.DataFrame([list('abcd'), list('efgh'), list('ijkl'), list('mnop')],
	   ...:                     columns=pd.MultiIndex.from_product([['one', 'two'], ['first', 'second']]))
	   ...:
	
	In [5]: dfmi
	Out[5]:
	    one          two
	  first second first second
	0     a      b     c      d
	1     e      f     g      h
	2     i      j     k      l
	3     m      n     o      p

我们通过两种不同的方式去访问同一值

	#第一种方式
        In [6]: dfmi['one']['second']
	Out[6]:
	0    b
	1    f
	2    j
	3    n
	Name: second, dtype: object
	
        #第二种方式
	In [7]: dfmi.loc[:,('one', 'second')]
	Out[7]:
	0    b
	1    f
	2    j
	3    n
	Name: (one, second), dtype: object

可以看出虽然访问方式不同, 但是返回的结果是相同的. 相同结果, 但其实第二种访问方式应该是我们所推荐使用的, 原因如下

第一种访问方式

使用dfmi['one']['second']其实是分为两个独立事件完成的, 一个事情接着一件事情发生:

第一步 执行dfmi['one']

第二步 在第一步的基础上执行dfmi_with_one['second'], 相当于在第一步返回Series基础上, 检索索引['second']

看似是一步到位的访问, 其实在内部调用了两次__getitem__

第二种方式访问

fmi.loc[:,('one', 'second')] 相当于将一个嵌套的元组(slice(None), ('one', 'second'))传递给一个__getitem__, 这就使得pandas将其作为一个整体来处理, 第二种方式比第一种方式速度更快


这里的第一种访问方式就是chained indexing, 接下来解决为什么chained indexing会造成警告.

		#第二种访问方式(推荐方式)
                dfmi.loc[:, ('one', 'second')] = value
		#其实在编译器中是这样操作的
		dfmi.iloc.setitem((slice(None), ('one', 'second')), value)
		
		#但是这一段代码编译器处理就很不同了
        
                #第一种访问方式chained indexing
		dfmi['one']['second'] = value
		#其实在编译器中是这样操作的
		dfmi.__getitem__('one').__setitem__('second', value)

问题的关键就出在这里的__getitem__上, 因为我们很难预测到这里的__getitem__返回的是一个视图或是一个copy, 因为我们无法确定__setitem))修改的到底是真实的dfmi或是暂时的copy副本, 这就是SettingWithCopy想要警告我们的.

到此问题就算是解决了, 出现警告的原因在于无法预测到底修改的是视图还是副本.

注意

dfmi.loc保证是dfmi本身伴随修改索引行为(这句话有点不太通顺, 大家可以去看看原文, 重点是后面一句), 所以dfmi.loc.__getitem__和dfmi.loc__setitem__方法一定是直接作用在dfmi上的. 当然dfmi.loc.__getitem__(idx)就无法预测到时作用在视图上或是副本上了.

另一种会出现这种警告的情形, 虽然这里并没有明显的链式索引.

	In [9]: def do_something(df):
	   ...:     foo = df[['bar', 'baz']]
	   ...:     #对于foo是视图或是副本, 其实我们是无法得知的
	   ...:     foo['quux'] = value
	   ...:     return foo

解决警告的方案:

使用 DafaFrameming.loc[行名, 列名] = 值 的方式去赋值, 而不是使用DataFrame[][]的形式去赋值.

当你在使用pandas处理数据时,可能会遇到这样的警告信息:“A value is trying to be set on a copy of a slice from a DataFrame”。这个警告是由于在DataFrame的切片上尝试设置值时出现的。这个问题可以通过使用.loc[row_indexer,col_indexer] = value来解决,这样可以避免出现这个警告。具体来说,你可以使用.loc来指定要设置值的行和列的索引,而不是直接对切片进行赋值操作。通过这种方式,你就能够避免在切片上进行设置值时出现警告。 举个例子来说明,假设你有一个DataFrame对象df,其中有一个列名为'count'。如果你想要将'count'列中的缺失值填充为0,你可以使用以下代码: df.loc[:, 'count'].fillna(0, inplace=True)。 需要注意的是,这个警告信息是pandas库为了提醒你可能会遇到一些潜在的问题而发出的。所以,当你看到这个警告时,最好参考官方文档中关于切片和赋值的用法来确保你的代码正确无误。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [pandas DataFrame 警告(SettingWithCopyWarning)的解决](https://download.csdn.net/download/weixin_38537941/13991528)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [pandas模块之SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a ...](https://blog.csdn.net/lhbo_bo/article/details/119830123)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值