我有一个数据帧,df
看起来像这样
Open High Low Close Volume
Date
2007-03-22 2.65 2.95 2.64 2.86 176389
2007-03-23 2.87 2.87 2.78 2.78 63316
2007-03-26 2.83 2.83 2.51 2.52 54051
2007-03-27 2.61 3.29 2.60 3.28 589443
2007-03-28 3.65 4.10 3.60 3.80 1114659
2007-03-29 3.91 3.91 3.33 3.57 360501
2007-03-30 3.70 3.88 3.66 3.71 185787
我正在尝试创建一个新列,该列首先将打开列移动 3 行 (df。Open.shift(-3)),然后取其自身的平均值和接下来的 2 个值。
例如,上述数据帧的Open
列将移动 -3 行,如下所示:
Date
2007-03-22 2.610
2007-03-23 3.650
2007-03-26 3.910
2007-03-27 3.700
2007-03-28 3.710
2007-03-29 3.710
2007-03-30 3.500
然后,我想通过迭代获取接下来 3 个值(包括自身)的正向平均值。 因此,第一次迭代将 2.610(第一个值)+ 3.650 + 3.910(下一个值)除以 3。 然后我们取下一个值 3.650(第一个值)并执行相同的操作。创建值列。
起初我尝试了类似的东西:
df['Avg'] =df.Open.shift(-3).iloc[0:3].mean()
但这并不能遍历 Open.shift 的所有值。
下一个循环似乎有效,但非常慢,我被告知在 Pandas 中使用循环是一种不好的做法。
for i in range(0, len(df.Open)):
df['Avg'][i] =df.Open.shift(-3).iloc[i:i+4].mean()
我试图思考使用应用程序的方法
df.Open.shift(-3).apply(loc[0:4].mean())
df.Open.shift(-3).apply(lambda x: x[0:4].mean())
但这些似乎给出了错误,例如
TypeError: 'float' object is not subscriptable
等
我想不出一种优雅的方式来做到这一点。
谢谢。
你可以使用熊猫rolling_mean。由于它使用向后窗口,因此它将为您提供前两行为 2.61(值本身)和 3.13(第 0 行和第 1 行的平均值)。要解决这个问题,您可以使用 shift(-2) 将值移动 2 行。
pd.rolling_mean(df, window=3, min_periods=1).shift(-2)
输出:
open
date
2007-03-22 3.390000
2007-03-23 3.753333
2007-03-26 3.773333
2007-03-27 3.706667
2007-03-28 3.640000
2007-03-29 NaN
2007-03-30 NaN
numpy
解决方案
正如承诺的那样
注意:巨大的警告<</strong>br/>这是一项高级技术,不建议任何初学者使用!!
使用它实际上可能会意外地剃掉你的贵宾犬秃顶。 小心!
as_strided
from numpy.lib.stride_tricks import as_strided
import numpy as np
import pandas as pd
# I didn't have your full data for all dates
# so I created my own array
# You should be able to just do
# o = df.Open.values
o = np.array([2.65, 2.87, 2.83, 2.61, 3.65, 3.91, 3.70, 3.71, 3.71, 3.50])
# because we shift 3 rows, I trim with 3:
# because it'll be rolling 3 period mean
# add two np.nan at the end
# this makes the strides cleaner.. sortof
# whatever, I wanted to do it
o = np.append(o[3:], [np.nan] * 2)
# strides are the size of the chunk of memory
# allocated to each array element. there will
# be a stride for each numpy dimension. for
# a one dimensional array, I only want the first
s = o.strides[0]
# it gets fun right here
as_strided(o, (len(o) - 2, 3), (s, s))
# ^ ___________/ __/
# | ______
# object to stride --- size of array ---
# to make memory chunk
# to step forward
# per dimension
[[ 2.61 3.65 3.91]
[ 3.65 3.91 3.7 ]
[ 3.91 3.7 3.71]
[ 3.7 3.71 3.71]
[ 3.71 3.71 3.5 ]
[ 3.71 3.5 nan]
[ 3.5 nan nan]]
现在我们只是取平均值。 一起
o = np.array([2.65, 2.87, 2.83, 2.61, 3.65, 3.91, 3.70, 3.71, 3.71, 3.50])
o = np.append(o[3:], [np.nan] * 2)
s = o.strides[0]
as_strided(o, (len(o) - 2, 3), (s, s)).mean(1)
array([ 3.39 , 3.75333333, 3.77333333, 3.70666667, 3.64 ,
nan, nan])
你可以把它包装在一个熊猫系列中
pd.Series(
as_strided(o, (len(o) - 2, 3), (s, s)).mean(1),
df.index[3:],
)