解决Pandas新增计算列时的SettingWithCopyWarning并优化代码
解决Pandas SettingWithCopyWarning警告的优化方案
Hey there! That SettingWithCopyWarning pops up because when you run df1 = df[df['name_code'].isin(wanted)], Pandas might be returning a view of the original DataFrame instead of a fully independent copy. So when you try to add new columns to df1, Pandas can't be sure if you intend to modify the original df or just the sliced subset—hence the warning.
Here are a few solid, practical ways to fix this:
1. 显式创建切片的独立副本
最简单的修复方式是在创建df1时添加.copy(),确保它是一个独立的对象,后续修改就不会触发警告:
import pandas as pd data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy', 'Daisy', 'River', 'Kate', 'David', 'Jack', 'Nancy'], 'code' : ['JJ', 'MM', 'TT', 'JJ', 'AA', 'DD', 'RR', 'KK', 'DD', 'JJ', 'NN'], 'month of entry': ["20171002", "20171206", "20171208", "20171018", "20090506", "20171128", "20101216", "20171230", "20171115", "20171030", "20171216"], 'reports': [14, 24, 31, 22, 34, 16, 47, 32, 14, 10, 28]} df = pd.DataFrame(data) dict_hour = {'JasonJJ' : 3, 'MollyMM' : 6, 'TinaTT' : 2, 'JakeJJ' : 3, 'AmyAA' : 8, 'DaisyDD' : 6, 'RiverRR' : 4, 'KateKK' : 8, 'DavidDD' : 5, 'JackJJ' : 5, 'NancyNN' : 2} wanted = ['JasonJJ', 'TinaTT', 'AmyAA', 'DaisyDD', 'KateKK'] df['name_code'] = df['name'].astype(str) + df['code'].astype(str) # 添加.copy()让df1成为独立副本 df1 = df[df['name_code'].isin(wanted)].copy() df1['hour'] = df1['name_code'].map(dict_hour).astype(float) df1['coefficient'] = df1['reports'] / df1['hour'] - 1
2. 使用.loc进行切片与列赋值
另一种方法是用.loc直接定位目标行和列,避免创建模糊的视图。你甚至可以链式完成列赋值操作:
import pandas as pd data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy', 'Daisy', 'River', 'Kate', 'David', 'Jack', 'Nancy'], 'code' : ['JJ', 'MM', 'TT', 'JJ', 'AA', 'DD', 'RR', 'KK', 'DD', 'JJ', 'NN'], 'month of entry': ["20171002", "20171206", "20171208", "20171018", "20090506", "20171128", "20101216", "20171230", "20171115", "20171030", "20171216"], 'reports': [14, 24, 31, 22, 34, 16, 47, 32, 14, 10, 28]} df = pd.DataFrame(data) dict_hour = {'JasonJJ' : 3, 'MollyMM' : 6, 'TinaTT' : 2, 'JakeJJ' : 3, 'AmyAA' : 8, 'DaisyDD' : 6, 'RiverRR' : 4, 'KateKK' : 8, 'DavidDD' : 5, 'JackJJ' : 5, 'NancyNN' : 2} wanted = ['JasonJJ', 'TinaTT', 'AmyAA', 'DaisyDD', 'KateKK'] df['name_code'] = df['name'].astype(str) + df['code'].astype(str) # 用.loc筛选行并直接赋值列 mask = df['name_code'].isin(wanted) df.loc[mask, 'hour'] = df.loc[mask, 'name_code'].map(dict_hour).astype(float) df.loc[mask, 'coefficient'] = df.loc[mask, 'reports'] / df.loc[mask, 'hour'] - 1 # 如果仍需要独立的df1,赋值完成后再切片 df1 = df[mask].copy()
3. 使用assign()实现简洁的链式工作流
如果你更喜欢函数式的链式写法,可以用assign()添加列,无需原地修改原数据或切片,同时自动创建独立副本:
import pandas as pd data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy', 'Daisy', 'River', 'Kate', 'David', 'Jack', 'Nancy'], 'code' : ['JJ', 'MM', 'TT', 'JJ', 'AA', 'DD', 'RR', 'KK', 'DD', 'JJ', 'NN'], 'month of entry': ["20171002", "20171206", "20171208", "20171018", "20090506", "20171128", "20101216", "20171230", "20171115", "20171030", "20171216"], 'reports': [14, 24, 31, 22, 34, 16, 47, 32, 14, 10, 28]} df = pd.DataFrame(data) dict_hour = {'JasonJJ' : 3, 'MollyMM' : 6, 'TinaTT' : 2, 'JakeJJ' : 3, 'AmyAA' : 8, 'DaisyDD' : 6, 'RiverRR' : 4, 'KateKK' : 8, 'DavidDD' : 5, 'JackJJ' : 5, 'NancyNN' : 2} wanted = ['JasonJJ', 'TinaTT', 'AmyAA', 'DaisyDD', 'KateKK'] # 链式操作一步完成所有处理 df1 = (df .assign(name_code=lambda x: x['name'].astype(str) + x['code'].astype(str)) .query('name_code in @wanted') .assign(hour=lambda x: x['name_code'].map(dict_hour).astype(float), coefficient=lambda x: x['reports'] / x['hour'] - 1))
这种方式把所有操作整合在一个链中,自动创建df1作为独立副本,完全避免警告。
内容的提问来源于stack exchange,提问作者Mark K
相关产品推荐
相关产品推荐

