我有一些价格数据(例如来自雅虎财经(,将每日粒度日期时间变量作为索引,让我们称之为 df,假设它是微软收盘价作为价值变量。为了获得每月平均收盘价,我显然可以做以下两个之一:
import yfinance as yf
import pandas as pd
df = yf.download("CMG", start="2012-01-01",end="2020-01-01" )
dfm = df.resample("M").mean()
dfm2 = df.groupby(df.index.to_period("M")).mean()
对我来说,它们看起来非常相似,我能说的唯一区别是,在重新采样时,新的日期时间索引是月底,而分组to_period的索引将为 yyyy-mm。
我现在想在 df 中添加一列,具有每日粒度,每个每日收盘价都偏离其月平均值。所以 1/jan/2020 - 平均值(1 月 20 日(,2/1 月/2020 - 平均值(1 月 20 日(,1/Feb/2020 - 平均值(2 月 20 日(。
因为 dfm 和 df 有不同的索引,所以我不能只做 df-dfm。
我唯一能想到的就是遍历 df,在 dfm 上放一个计数器,并在循环中放一个 if 语句,这在很大程度上是一种 c 类型的方法,但不是很pythonic。我想它看起来像这样(但这不起作用(:
counter = 0
df["dailyminusmonthly"] =""
for i in df:
if i.index <= dfm[counter].index:
i.dailyminusmonthly = i.close - dfm.close[counter]
else:
counter = counter +1
i.dailyminusmonthly = i.close - dfm.close[counter]
您可以将DatetimeIndex
转换为月期,因此您可以减去dfm2
,只有这样才需要转换为numpy数组,因为减去Series
的索引与原始df
不同,以防止完整的NaN
s列:
df['dailyminusmonthly1']= (df['Close'].to_period('M')
.sub(df.groupby(df.index.to_period("M"))['Close'].mean())
.to_numpy())
另一个更简单的解决方案是使用与 original 相同的索引Resampler.transform
:
df['dailyminusmonthly2']= df['Close'].sub(df.resample("M")['Close'].transform('mean'))
print (df)
Open High Low Close Adj Close
Date
2012-01-03 343.700012 350.489990 340.000000 341.269989 341.269989
2012-01-04 346.000000 349.980011 345.010010 348.750000 348.750000
2012-01-05 346.880005 351.980011 342.570007 350.480011 350.480011
2012-01-06 348.880005 352.630005 347.350006 348.950012 348.950012
2012-01-09 349.000000 349.489990 336.290009 339.739990 339.739990
... ... ... ... ...
2019-12-24 827.099976 829.409973 823.159973 828.890015 828.890015
2019-12-26 829.409973 839.280029 828.239990 838.599976 838.599976
2019-12-27 839.969971 840.000000 835.000000 836.789978 836.789978
2019-12-30 838.169983 838.750000 829.010010 836.070007 836.070007
2019-12-31 837.239990 842.270020 833.359985 837.109985 837.109985
Volume dailyminusmonthly1 dailyminusmonthly2
Date
2012-01-03 728100 -13.559013 -13.559013
2012-01-04 743100 -6.079002 -6.079002
2012-01-05 672300 -4.348991 -4.348991
2012-01-06 370700 -5.878990 -5.878990
2012-01-09 748600 -15.089012 -15.089012
... ... ...
2019-12-24 91900 3.640494 3.640494
2019-12-26 255400 13.350455 13.350455
2019-12-27 201900 11.540458 11.540458
2019-12-30 211400 10.820487 10.820487
2019-12-31 282200 11.860465 11.860465
[2012 rows x 8 columns]