pandas遇到SettingWithCopyWarning警告出现的原因和解决
pandas遇到SettingWithCopyWarning警告出现的原因和解决
在使用pandas进行数据处理时,经常会遇到SettingWithCopyWarning警告。这个警告通常出现在对DataFrame进行链式操作时,例如在筛选数据后尝试修改数据。本文将详细解释这个警告出现的原因,并提供几种有效的解决方案。
视图和副本的概念
在理解SettingWithCopyWarning之前,我们首先需要区分视图(view)和副本(copy)的概念。
对于 df2 = df.head(3)
来说,df2
为视图,可以理解为截取 df1
的一部分来显示,实际上原数据都是指向 df1
。当对视图 df2
进行修改时,会对原数据进行修改。
而对于 df2 = df.head(3).copy()
来说,df2
为 df1
截取的一个副本,此处df1
和 df2
是两个完全不同的 DataFrame,当对副本 df2
进行修改时,不会修改到 df1
。即用 .copy()
实现了数据隔离。
第一种情况:不想在原df上进行修改
如果不想在原df上进行修改,即对由原df得到的新df进行修改希望的同时不影响到原来df的数据,一般使用 .copy()
,但是考虑数据量和性能,可以考虑使用 双loc即后面加.loc[:] 从原df获得新df,再对新df进行修改,并且同时不影响原df,实际上是隐式创建副本。
import pandas as pd
ids = [1, 2]
info = {'C': 0.5}
df = pd.DataFrame({
'id': [1, 2, 3],
'A': [4, 5, 6],
'B': [7, 8, 9]
})
# 方法1、使用.copy()显式创建一个新df副本
exp_df = df.loc[df['id'].isin(ids)].copy()
if not exp_df.empty:
exp_df.loc[:, 'C'] = info['C']
print(exp_df)
print('-------------')
print(df)
# 方法2、使用.loc[:]隐式创建一个新df副本
exp_df = df.loc[df['id'].isin(ids)].loc[:]
if not exp_df.empty:
exp_df.loc[:, 'C'] = info['C']
print(exp_df)
print('-------------')
print(df)
# 方法3、使用.assign 添加或修改列,并返回一个新的 DataFrame 副本。
exp_df = df.loc[df['id'].isin(ids)].loc[:]
if not exp_df.empty:
exp_df = exp_df.assign(C=info['C'])
print(exp_df)
print('-------------')
print(df)
第二种情况:想在原df上进行修改
如果想在原df上进行修改(例如使用 drop 或 concat 后重新赋值),即对由原df 得到的新df 进行修改希望同时修改原来df 的数据,则可以使用修改后的df覆盖原df来避免SettingWithCopyWarning警告。
df = pd.DataFrame({
'id':[1, 2, 3],
'A': [4, 5, 6],
'B': [7, 8, 9]
})
df = df.loc[df['id'].isin(ids)] # 进行覆盖
print(df)
print('---------------')
if not df.empty:
df.loc[:, 'C'] = 10
print(df)
总结
.copy()
方法用于显式地创建一个 DataFrame 或 Series 的副本,确保数据的独立性,以确保不会在原始数据的副本上进行修改时触发 SettingWithCopyWarning 警告。由于创建完全独立的副本,这意味着所有数据都会被复制一遍,因此在数据量较大的情况下,性能开销(时间、内存消耗)可能会比较大。重新赋值操作(例如使用 drop 删除列后重新赋值,或使用 concat 拼接数据后重新赋值)则主要用于数据的更新和变更。这些操作通常会创建一个新的 DataFrame,并将其赋值给原始变量,从而实现数据的变更。这个过程涉及数据的重新构建,时间和内存对消耗依赖于具体对操作和数据量。常用于需要进行数据变更并更新原始 DataFrame 时。
.loc[:]
时,实际上是创建了一个新的 DataFrame 视图,不复制数据,包含所有原始 DataFrame 数据的引用,虽然不像.copy()
那样创建一个完全独立的副本,但在大多数情况下,对这个新视图的修改也不会影响原始数据,不会触发 SettingWithCopyWarning 警告,但在某些情况(如链式索引可能导致不确定行为)可能会导致意外的修改。常用于需要对筛选后的数据进行修改,但不想显式创建副本时。
总的来说解决SettingWithCopyWarning 警告只有两种方法,第一是创建新df,第二是在原df上修改然后再覆盖原df,只有这两种方式在后续对df修改时才不会报SettingWithCopyWarning。