pandas 中的动态滚动功能
Dynamic rolling function in pandas
我正在尝试在 Pandas 中实现动态移动平均线和其他动态移动函数,例如 std
和 max
。 'normal' 和动态移动平均线之间的区别在于边缘的行为。这主要改进了两件事:
- 返回的数据 未 与 'normal' 移动平均线
相同
- 返回的数据涵盖输入数据的整个范围。使用 'normal' 移动平均线,根据移动平均线的 window 大小裁剪返回的数据范围。
因此,要获得动态移动平均线,有多种方法,例如 反射、first/last 值的重复、... 对我来说 反射方法 就足够了。此行为和其他行为在 scripy.ndimage.filters
的过滤器中实现,例如uniform_filter1d
。我查看了 Pandas 文档,但在 rolling
上我找不到任何改变边缘行为的参数......
我自己添加这个似乎是可行的,但我问这个问题是为了看看 Pandas 中是否已经有一个我错过的实现。
所以我的问题可以简化为:有没有办法像我描述的那样动态地使用 Pandas rolling
?
'Normal' 移动平均线:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage import filters
def moving_avg(series: pd.Series, window: int) -> pd.Series:
return series.rolling(window=window).mean()
t = np.linspace(0, 100, 1000)
y = np.sin(2 * np.pi * 0.03 * t)
filtered_y = filters.uniform_filter1d(y, 200)
pd_y = pd.Series(y, name="Pandas Moving Average")
pd_y = moving_avg(pd_y, 200) # Using a large window on purpose to show the shift!
plt.plot(y, label="Raw Data")
plt.plot(filtered_y, label="uniform_filter1d")
pd_y.plot()
plt.legend()
plt.show()
结果
那么有什么办法可以解决这个问题吗?
我不认为有你想要实现的东西。一种简单的方法是使用 concat
添加边缘值以创建反射效果。在函数中,它可能类似于
def rolling_reflect_center(s, window):
nb_ref = window // 2
rolling_ = pd.concat(
[pd.Series(s.iloc[:nb_ref].values)[::-1],#reflect on the left
s,
pd.Series(s.iloc[-nb_ref+1:].values[::-1]) #reflect on the right
]).rolling(window ,center=True)
return rolling_
那你就做
filtered_y = filters.uniform_filter1d(y, 200)
pd_y = pd.Series(y, name="Pandas Moving Average")
pd_y = rolling_reflect_center( pd_y, window=200).mean()
print(np.allclose(pd_y.dropna().to_numpy(),filtered_y))
#True
情节也很好,因为它会自动删除 nan
我正在尝试在 Pandas 中实现动态移动平均线和其他动态移动函数,例如 std
和 max
。 'normal' 和动态移动平均线之间的区别在于边缘的行为。这主要改进了两件事:
- 返回的数据 未 与 'normal' 移动平均线 相同
- 返回的数据涵盖输入数据的整个范围。使用 'normal' 移动平均线,根据移动平均线的 window 大小裁剪返回的数据范围。
因此,要获得动态移动平均线,有多种方法,例如 反射、first/last 值的重复、... 对我来说 反射方法 就足够了。此行为和其他行为在 scripy.ndimage.filters
的过滤器中实现,例如uniform_filter1d
。我查看了 Pandas 文档,但在 rolling
上我找不到任何改变边缘行为的参数......
我自己添加这个似乎是可行的,但我问这个问题是为了看看 Pandas 中是否已经有一个我错过的实现。
所以我的问题可以简化为:有没有办法像我描述的那样动态地使用 Pandas rolling
?
'Normal' 移动平均线:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage import filters
def moving_avg(series: pd.Series, window: int) -> pd.Series:
return series.rolling(window=window).mean()
t = np.linspace(0, 100, 1000)
y = np.sin(2 * np.pi * 0.03 * t)
filtered_y = filters.uniform_filter1d(y, 200)
pd_y = pd.Series(y, name="Pandas Moving Average")
pd_y = moving_avg(pd_y, 200) # Using a large window on purpose to show the shift!
plt.plot(y, label="Raw Data")
plt.plot(filtered_y, label="uniform_filter1d")
pd_y.plot()
plt.legend()
plt.show()
结果
那么有什么办法可以解决这个问题吗?
我不认为有你想要实现的东西。一种简单的方法是使用 concat
添加边缘值以创建反射效果。在函数中,它可能类似于
def rolling_reflect_center(s, window):
nb_ref = window // 2
rolling_ = pd.concat(
[pd.Series(s.iloc[:nb_ref].values)[::-1],#reflect on the left
s,
pd.Series(s.iloc[-nb_ref+1:].values[::-1]) #reflect on the right
]).rolling(window ,center=True)
return rolling_
那你就做
filtered_y = filters.uniform_filter1d(y, 200)
pd_y = pd.Series(y, name="Pandas Moving Average")
pd_y = rolling_reflect_center( pd_y, window=200).mean()
print(np.allclose(pd_y.dropna().to_numpy(),filtered_y))
#True
情节也很好,因为它会自动删除 nan