如何修复Pandas的SettingWithCopyWarning警告(非忽略)
解决Pandas SettingWithCopyWarning警告问题
问题背景
我通过yfinance库从Yahoo Finance获取股票交易的价格与成交量数据,创建了包含收盘价(Close)和成交量(Volume)的Closes DataFrame。尝试为该DataFrame添加年、季、月、周维度的成交量均值列时,触发了SettingWithCopyWarning警告。希望彻底消除该警告,同时保证新增列的计算逻辑正确,而非简单忽略警告。
原代码
import yfinance as yf import pandas as pd import warnings warnings.filterwarnings("ignore", message="The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.", category=FutureWarning, module="yfinance.utils") warnings.filterwarnings("ignore", category=pd.errors.PerformanceWarning) #warnings.filterwarnings("ignore", message="DataFrame is highly fragmented. This is usually the result of calling `frame.insert` many times, which has poor performance. Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`", category=pd.errors.PerformanceWarning) TickersList=['A', 'AAL', 'AAPL', 'ABBV', 'ABNB', 'ABT', 'ACGL', 'ACN', 'ADBE', 'ADI', 'ADM'] Stocks=yf.download(TickersList[0::1], period="1y", interval="1d", group_by='ticker') Stocks.sort_index(level=0,axis=1,inplace=True) Closes=Stocks.loc[:, (slice(None), ['Close', 'Volume'])] for i in Closes.columns.get_level_values(0): Closes.loc[:,(i,'Meam1Y')]=Closes.loc[:,(i,'Volume')].rolling (250).mean() Closes.loc[:,(i,'Meam1Q')]=Closes.loc[:,(i,'Volume')].rolling (62).mean() Closes.loc[:,(i,'Meam1M')]=Closes.loc[:,(i,'Volume')].rolling (20).mean() Closes.loc[:,(i,'Meam1W')]=Closes.loc[:,(i,'Volume')].rolling (5).mean() Closes
警告内容
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy Closes.loc[:,(i,'Meam1Y')]=Closes.loc[:,(i,'Volume')].rolling (250).mean() C:\Users\iiiva\AppData\Local\Temp\ipykernel_27188\26776804.py:4: 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
解决方案
核心原因
Closes是从Stocks切片得到的视图而非独立副本,直接修改视图会触发Pandas的SettingWithCopyWarning——因为Pandas无法确定你是想修改原数据还是副本。
修复步骤
显式创建独立副本
在生成Closes时,调用.copy()方法,让Closes成为完全独立的DataFrame,脱离与原Stocks的关联:Closes = Stocks.loc[:, (slice(None), ['Close', 'Volume'])].copy()可选:优化列添加逻辑(提升性能)
循环逐个添加列会导致DataFrame碎片化,虽然你已忽略PerformanceWarning,但可以通过批量生成新列后合并的方式优化性能:# 预先存储所有新列 new_columns = [] for i in Closes.columns.get_level_values(0): col_y = Closes.loc[:, (i, 'Volume')].rolling(250).mean().rename((i, 'Meam1Y')) col_q = Closes.loc[:, (i, 'Volume')].rolling(62).mean().rename((i, 'Meam1Q')) col_m = Closes.loc[:, (i, 'Volume')].rolling(20).mean().rename((i, 'Meam1M')) col_w = Closes.loc[:, (i, 'Volume')].rolling(5).mean().rename((i, 'Meam1W')) new_columns.extend([col_y, col_q, col_m, col_w]) # 合并所有新列到Closes Closes = pd.concat([Closes] + new_columns, axis=1)
修改后完整代码
import yfinance as yf import pandas as pd import warnings warnings.filterwarnings("ignore", message="The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.", category=FutureWarning, module="yfinance.utils") warnings.filterwarnings("ignore", category=pd.errors.PerformanceWarning) TickersList=['A', 'AAL', 'AAPL', 'ABBV', 'ABNB', 'ABT', 'ACGL', 'ACN', 'ADBE', 'ADI', 'ADM'] Stocks=yf.download(TickersList[0::1], period="1y", interval="1d", group_by='ticker') Stocks.sort_index(level=0,axis=1,inplace=True) # 显式创建副本 Closes=Stocks.loc[:, (slice(None), ['Close', 'Volume'])].copy() # 批量生成并合并新列 new_columns = [] for i in Closes.columns.get_level_values(0): col_y = Closes.loc[:, (i, 'Volume')].rolling(250).mean().rename((i, 'Meam1Y')) col_q = Closes.loc[:, (i, 'Volume')].rolling(62).mean().rename((i, 'Meam1Q')) col_m = Closes.loc[:, (i, 'Volume')].rolling(20).mean().rename((i, 'Meam1M')) col_w = Closes.loc[:, (i, 'Volume')].rolling(5).mean().rename((i, 'Meam1W')) new_columns.extend([col_y, col_q, col_m, col_w]) Closes = pd.concat([Closes] + new_columns, axis=1) Closes
效果验证
修改后运行代码,SettingWithCopyWarning会彻底消失,同时新增列的计算逻辑与原代码完全一致,还能避免DataFrame碎片化带来的性能问题。
内容的提问来源于stack exchange,提问作者Vasiliy Deryuga
相关产品推荐
相关产品推荐

