Изменить: Я скомпрометировал этот вопрос, учитывая, что он, вероятно, слишком запутан для начала. Мяч вопроса выделен жирным шрифтом ниже.
Я хотел бы узнать больше об объекте, который создается при использовании DataFrame.rolling
или Series.rolling
:
print(type(df.rolling))
<class 'pandas.core.window.Rolling'>
Некоторые предпосылки: рассмотрим часто используемую альтернативу с np.as_strided
. Этот фрагмент кода сам по себе не важен, но его результатом является моя контрольная точка при задании этого вопроса.
def rwindows(a, window):
if a.ndim == 1:
a = a.reshape(-1, 1)
shape = a.shape[0] - window + 1, window, a.shape[-1]
strides = (a.strides[0],) + a.strides
windows = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
return np.squeeze(windows)
Здесь rwindows
возьмет 1d или 2d ndarray
и построит скользящие "блоки", равные указанному размеру окна (как показано ниже). Как объект .rolling
сравнивается с выходом ndarray
ниже? Является ли он итератором с определенными атрибутами, хранящимися для каждого блока? Или что-то еще? Я пробовал играть с завершением табуляции на объекте с помощью атрибутов/методов, таких как __dict__
и _get_index()
, и они не очень мне говорят. Я также видел метод _create_blocks
в pandas - он вообще похож на метод strided
?
# as_strided version
a = np.arange(5)
print(rwindows(a, 3)) # 1d input
[[0 1 2]
[1 2 3]
[2 3 4]]
b = np.arange(10).reshape(5,2)
print(rwindows(b, 4)) # 2d input
[[[0 1]
[2 3]
[4 5]
[6 7]]
[[2 3]
[4 5]
[6 7]
[8 9]]]
Часть 2, дополнительный кредит
Использование подхода NumPy выше (реализация OLS здесь) обусловлена тем, что func
внутри pandas.core.window.Rolling.apply должен
выдает одно значение из входных данных ndarray * args и ** kwargs передается функции
Таким образом, аргумент не может быть другим подвижным объектом. То есть.
def prod(a, b):
return a * b
df.rolling(3).apply(prod, args=((df + 2).rolling(3),))
-----------------------------------------------------------------------
...
TypeError: unsupported operand type(s) for *: 'float' and 'Rolling'
Итак, это действительно от того, где мой вопрос выше. Почему передаваемая функция должна использовать массив NumPy и создавать одно скалярное значение, и что это связано с компоновкой объекта .rolling
?