即使使用 .loc[row_indexer,col_indexer] = value,SettingWithCopyWarning
- 2025-01-14 08:51:00
- admin 原创
- 110
问题描述:
这是我的代码中的其中一行SettingWithCopyWarning
:
value1['Total Population']=value1['Total Population'].replace(to_replace='*', value=4)
然后我将其改为:
row_index= value1['Total Population']=='*'
value1.loc[row_index,'Total Population'] = 4
仍然会出现相同的警告。我该如何消除它?
另外,我使用过convert_objects(convert_numeric=True)函数时也收到同样的警告,有什么方法可以避免这种情况吗?
value1['Total Population'] = value1['Total Population'].astype(str).convert_objects(convert_numeric=True)
这是我收到的警告信息:
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 the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
解决方案 1:
如果使用.loc[row, column]
仍然出现相同错误,则可能是因为复制了另一个数据框。您必须使用.copy()
。
这是一步一步的错误重现:
import pandas as pd
d = {'col1': [1, 2, 3, 4], 'col2': [3, 4, 5, 6]}
df = pd.DataFrame(data=d)
df
# col1 col2
#0 1 3
#1 2 4
#2 3 5
#3 4 6
创建新列并更新其值:
df['new_column'] = None
df.loc[0, 'new_column'] = 100
df
# col1 col2 new_column
#0 1 3 100
#1 2 4 None
#2 3 5 None
#3 4 6 None
我没有收到任何错误。但是,让我们根据前一个数据框创建另一个数据框:
new_df = df.loc[df.col1>2]
new_df
#col1 col2 new_column
#2 3 5 None
#3 4 6 None
现在,使用.loc
,我将尝试以相同的方式替换一些值:
new_df.loc[2, 'new_column'] = 100
然而,我再次收到了这个令人憎恶的警告:
尝试在 DataFrame 切片的副本上设置值。请尝试使用 .loc[row_indexer,col_indexer] = value
请参阅文档中的注意事项:
https ://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
解决方案
在创建新数据框时使用.copy()
将解决警告:
new_df_copy = df.loc[df.col1>2].copy()
new_df_copy.loc[2, 'new_column'] = 100
现在,您将不会收到任何警告!
如果您的数据框是使用另一个数据框之上的过滤器创建的,请始终使用.copy()
。
解决方案 2:
您是否尝试过直接设置?:
value1.loc[value1['Total Population'] == '*', 'Total Population'] = 4
解决方案 3:
我不知道这对数据存储/内存的影响有多严重,但它每次都会为你的平均数据帧修复这个问题:
def addCrazyColFunc(df):
dfNew = df.copy()
dfNew['newCol'] = 'crazy'
return dfNew
就像消息中说的那样... 复制一份就可以了。如果有人可以在没有复制的情况下修复上述问题,请发表评论。上述所有 loc 内容在这种情况下都不起作用。
解决方案 4:
我来这里是因为我想根据另一列中的值有条件地设置新列的值。
对我有用的是numpy.where:
import numpy as np
import pandas as pd
...
df['Size'] = np.where((df.value > 10), "Greater than 10", df.value)
从numpy docs来看,这相当于:
[xv if c else yv
for c, xv, yv in zip(condition, x, y)]
这是 zip 的一个非常好的用法...
解决方案 5:
这是关于源 df 是否在使用切片索引的副本更新中更新的警告。如果是副本更新,请尝试pd.set_option('mode.chained_assignment', None)
在出现警告的行之前添加
df_value = pd.DataFrame({ 'Total Population':['a','b','c','*'] })
value1 = df_value[ df_value['Total Population']=='*']
pd.set_option('mode.chained_assignment', None) # <=== SettingWithCopyWarning Off
row_index = value1['Total Population']=='*'
value1.loc[row_index,'Total Population'] = 44
pd.set_option('mode.chained_assignment', 'warn') # <=== SettingWithCopyWarning Default
解决方案 6:
我能够使用如下语法来避免相同的警告信息:
value1.loc[:, 'Total Population'].replace('*', 4)
请注意,数据框不需要重新分配给自身,即value1['Total Population']=value1['Total Population']...
解决方案 7:
得到解决方案:
我创建了一个新的 DataFrame 并仅存储了我需要处理的列的值,现在它没有给我任何错误!
很奇怪,但是有效。
解决方案 8:
指定它是副本对我来说是有效的。我刚刚.copy()
在声明的末尾添加了
value1['Total Population'] = value1['Total Population'].replace(to_replace='*', value=4).copy()
解决方案 9:
这应该可以解决你的问题:
value1[:, 'Total Population'] = value1[:, 'Total Population'].replace(to_replace='*', value=4)