You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复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无法确定你是想修改原数据还是副本。

修复步骤

  1. 显式创建独立副本
    在生成Closes时,调用.copy()方法,让Closes成为完全独立的DataFrame,脱离与原Stocks的关联:

    Closes = Stocks.loc[:, (slice(None), ['Close', 'Volume'])].copy()
    
  2. 可选:优化列添加逻辑(提升性能)
    循环逐个添加列会导致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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 07:33:14