问题复现
要处理的数据格式:
假设我们只想对1月份的数据进行处理:
import pandas as pd
data = pd.read_csv('weather.csv')
# print(data.head())
# 只选1月份的数据进行分析
condition = data['日期'].str.startswith('2023-01')
# print(condition)
# 设置温差
data[condition]['温差'] = data['最高气温'] - data['最低气温']
# 看看是否修改成功
data[condition].head()
运行输出:
D:\temp\python_work\pandas-practice\test.py:10: SettingWithCopyWarning:
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 caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
data[condition]['温差'] = data['最高气温'] - data['最低气温']
由输出可以看到,出现了SettingWithCopyWarning告警。
问题原因
发出告警的代码data[condition]['温差'] = data['最高气温'] - data['最低气温']
。
在 Pandas 中,链式操作(如 data[condition]['温差']
)可能会导致不确定的行为。
Pandas 无法确定 data[condition]
返回的是原始数据的视图(view)还是副本(copy)。
如果返回的是副本,那么对副本的修改不会反映到原始数据中。
核心要点:pandas的DataFrame修改写操作,只允许在源DataFrame上进行,一步到位。
解决方法
解决方法1:使用 .loc 进行显式赋值,用一个步骤完成修改操作
这个方法使用.loc
,是一步操作,直接在源DataFrame上修改。
import pandas as pd
data = pd.read_csv('weather.csv')
print('下面是原始数据的前几行:')
print(data.head())
print('-------------------------------------')
# 只选1月份的数据进行分析
condition = data['日期'].str.startswith('2023-01')
# 设置温差
data.loc[condition, '温差'] = data['最高气温'] - data['最低气温']
# 看看是否修改成功
print('下面是修改后数据的前几行:')
print(data.head())
运行输出:
下面是原始数据的前几行:
日期 最高气温 最低气温 天气
0 2023-01-01 17 12 多云
1 2023-01-02 19 12 多云
2 2023-01-03 17 12 多云
3 2023-01-04 18 13 多云
4 2023-01-05 22 14 多云
-------------------------------------
下面是修改后数据的前几行:
日期 最高气温 最低气温 天气 温差
0 2023-01-01 17 12 多云 5.0
1 2023-01-02 19 12 多云 7.0
2 2023-01-03 17 12 多云 5.0
3 2023-01-04 18 13 多云 5.0
4 2023-01-05 22 14 多云 8.0
解决方法2:使用 .copy() 方法,显式创建一个副本,避免修改原始数据
import pandas as pd
data = pd.read_csv('weather.csv')
print('下面是原始数据的前几行:')
print(data.head())
print('-------------------------------------')
# 只选1月份的数据进行分析
condition = data['日期'].str.startswith('2023-01')
# 使用copy()方法得到一个新的DataFrame
data2 = data[condition].copy()
# 在新的DataFrame上增加 温差 这列
data2['温差'] = data['最高气温'] - data['最低气温']
print('下面是新数据的前几行:')
print(data2.head())
运行输出:
下面是原始数据的前几行:
日期 最高气温 最低气温 天气
0 2023-01-01 17 12 多云
1 2023-01-02 19 12 多云
2 2023-01-03 17 12 多云
3 2023-01-04 18 13 多云
4 2023-01-05 22 14 多云
-------------------------------------
下面是新数据的前几行:
日期 最高气温 最低气温 天气 温差
0 2023-01-01 17 12 多云 5
1 2023-01-02 19 12 多云 7
2 2023-01-03 17 12 多云 5
3 2023-01-04 18 13 多云 5
4 2023-01-05 22 14 多云 8