Pandas SettingWithCopyWarning成因及apply与astype选型咨询
问题分析与解答
先看你的代码和数据源:
示例代码
import pandas as pd import numpy as np pd.set_option('display.expand_frame_repr', False) foo = pd.read_csv("foo2.csv", skipinitialspace=True, index_col='Index') foo.loc[:, 'Date'] = pd.to_datetime(foo.Date) for i in range(0, len(foo)-1): if foo.at[i, 'Type'] == 'Reservation': for j in range(i+1, len(foo)): if foo.at[j, 'Type'] == 'Payout': foo.at[j, 'Nights'] = foo.at[i, 'Nights'] break mask = (foo['Date'] >= '2018-03-31') & (foo['Date'] <= '2019-03-31') foo2019 = foo.loc[mask] foopayouts2019 = foo2019.loc[foo2019['Type'] == 'Payout'] foopayouts2019.loc[:, 'Nights'] = foopayouts2019['Nights'].apply(np.int64) # foopayouts2019.loc[:, 'Nights'] = foopayouts2019['Nights'].astype(np.int64, copy=False)
数据源(foo2.csv)
Index,Date,Type,Nights,Amount,Payout 0,03/07/2018,Reservation,2.0,1000.00, 1,03/07/2018,Payout,,,1000.00 2,09/11/2018,Reservation,3.0,1500.00, 3,09/11/2018,Payout,,,1500.00 4,02/16/2019,Reservation,2.0,2000.00, 5,02/16/2019,Payout,,,2000.00 6,04/25/2019,Reservation,7.0,1200.00, 7,04/25/2019,Payout,,,1200.00
1. SettingWithCopyWarning的成因是什么?已使用.loc,是否是更早代码逻辑导致?
没错,问题确实出在更早的切片逻辑上,和你最后用不用.loc关系不大。
当你执行foo2019 = foo.loc[mask]和foopayouts2019 = foo2019.loc[foo2019['Type'] == 'Payout']时,这两个变量都是原DataFramefoo的视图(view),而非独立的副本(copy)。Pandas的切片默认会尽量返回视图以节省内存,但这就导致后续你对foopayouts2019做修改时,Pandas无法确定你是想修改原数据foo,还是只想修改这个切片后的临时对象,因此抛出警告。
解决方法很简单,在创建切片时显式添加.copy(),强制生成独立副本:
foo2019 = foo.loc[mask].copy() foopayouts2019 = foo2019.loc[foo2019['Type'] == 'Payout'].copy()
这样后续修改foopayouts2019就不会触发警告了。
2. 数据类型转换时,apply(np.int64)与astype(np.int64, copy=False)哪种方案更优?
毫无疑问,astype(np.int64, copy=False)是更优的选择,原因有两点:
- 效率更高:
astype是Pandas针对整个Series的向量化操作,底层用C实现,处理速度远快于apply。apply本质是逐元素遍历执行函数,相当于Python层面的循环,数据量越大,效率差距越明显。 - 内存控制更灵活:
copy=False参数会让Pandas尝试在原内存块上直接修改数据(如果数据类型转换允许的话),避免不必要的内存拷贝。而apply一定会生成新的Series,无法做到这一点。
另外要注意:如果你的Nights列存在缺失值(NaN),转int64会报错,因为整数类型无法存储NaN。不过从你的数据源来看,这列数据都是有效的数值,所以没问题。
内容的提问来源于stack exchange,提问作者Faheem Mitha
相关产品推荐
相关产品推荐

