我从雅虎财经 (yfinance) 下载了有关股票交易价格和交易量的数据。然后我创建了 Closes 数据框,其中包含收盘价和成交量的数据(我删除了不必要的信息)。然后我想将列添加到 Closes 数据框中,并计算年、季度、月和周的平均交易量。但在执行代码时,会出现警告“正在尝试在 DataFrame 切片的副本上设置值。请尝试使用 .loc[row_indexer,col_indexer] = value 代替”。我读了这篇文章“https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy”,但我不明白我应该做什么我的情况。我希望消除警告,并在添加的列中正确处理计算。 如何解决此警告(不是忽略它,而是修复它)?
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
警告全文:
请参阅文档中的警告: 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') ].滚动(250).mean() C:\ Users \ iiiva \ AppData \ Local \ Temp \ ipykernel_27188 \ 26776804.py:4:SettingWithCopyWarning: 尝试在 DataFrame 的切片副本上设置一个值。 尝试使用 .loc[row_indexer,col_indexer] = value 代替
这个警告之所以出现是因为你试图在一个可能是 DataFrame 视图的对象上进行修改。你遇到的问题在于,当你执行
Closes.loc[:, (i, 'Volume')]
时,你并不能保证这会返回 DataFrame 的视图还是副本。如果是副本,修改不会反映到原始 DataFrame 中。
以下是如何修改代码来避免此警告并确保将新列添加到
Closes
DataFrame 中:
import yfinance as yf
import pandas as pd
# ... (你现有的代码来下载和准备数据)
for i in Closes.columns.get_level_values(0):
# 使用 .loc 直接分配给新的列
Closes.loc[:, (i, 'Meam1Y')] = Closes[(i, 'Volume')].rolling(250).mean()
Closes.loc[:, (i, 'Meam1Q')] = Closes[(i, 'Volume')].rolling(62).mean()
Closes.loc[:, (i, 'Meam1M')] = Closes[(i, 'Volume')].rolling(20).mean()
Closes.loc[:, (i, 'Meam1W')] = Closes[(i, 'Volume')].rolling(5).mean()
Closes
解释:
-
直接赋值:
我们使用
Closes.loc[:, (i, 'NewColumnName')] = ...
来直接在Closes
DataFrame 上创建和分配新的列。这确保了修改会反映到原始 DataFrame 上。
通过这个修改,你应该能够避免警告,并且计算出的移动平均线将正确存储在
Closes
DataFrame 中。