Python 熊猫滚动物体是如何工作的?
编辑:我将这个问题浓缩,因为它可能太复杂了。问题的要点用黑体字写在下面 我想了解更多关于使用或时实际创建的对象的信息: 此处Python 熊猫滚动物体是如何工作的?,python,pandas,numpy,dataframe,cython,Python,Pandas,Numpy,Dataframe,Cython,编辑:我将这个问题浓缩,因为它可能太复杂了。问题的要点用黑体字写在下面 我想了解更多关于使用或时实际创建的对象的信息: 此处rwindows将采用1d或2dndarray并构建与指定窗口大小相等的滚动“块”(如下所示)一个.rolling对象与下面的ndarray输出相比如何?它是一个迭代器,为每个块存储了某些属性吗?或者完全是别的什么?我尝试过在对象上使用属性/方法(如\u dict\u和\u get\u index()。我也在熊猫身上看到过一种方法——它是否与stripped方法相似 # a
rwindows
将采用1d或2dndarray
并构建与指定窗口大小相等的滚动“块”(如下所示)一个.rolling
对象与下面的ndarray
输出相比如何?它是一个迭代器,为每个块存储了某些属性吗?或者完全是别的什么?我尝试过在对象上使用属性/方法(如\u dict\u
和\u get\u index()。我也在熊猫身上看到过一种方法——它是否与stripped
方法相似
# 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]]]
第二部分,额外学分
使用上述NumPy方法(OLS实现)是必要的,因为必须在
从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
对象的布局有什么关系?我建议您查看源代码,以了解rolling的具体功能。我特别建议您查看和中的滚动
函数。从这里可以查看在指定窗口类型或默认窗口类型时使用的。最后一个继承自\u滚动和扩展
,最终继承了\u滚动
和\u窗口
也就是说,我会给我的两分钱:熊猫的整个滚动机制依赖于numpy功能。尤其是在熊猫身上。它与cython模块一起使用。在你的系列中,出现了聚合滚动窗口。对于典型的聚合函数,它可以有效地为您处理它们,但是对于自定义函数(使用apply()
),它使用了一个位于windows.pyx
中的
pandas中的滚动功能在pandas数据帧列上独立运行。它不是一个,并且是延迟加载的,这意味着在对其应用聚合函数之前不会计算任何内容。真正应用数据滚动窗口的函数直到聚合完成之前才被使用
造成混淆的一个原因可能是您将滚动对象视为一个数据帧。(您已在上一个代码段中将滚动对象命名为df
)。事实并非如此。它是一个对象,可以通过在它所包含的窗口逻辑上应用聚合来生成数据帧
您提供的lambda将应用于新数据帧的每个单元。它在旧数据帧中向后(沿每列)获取一个窗口,并将其聚合到新数据帧中的一个单元格中。聚合可以是像sum
、mean
、定制的东西等等,在一些窗口大小上,比如3。以下是一些例子:
a = np.arange(5)
df = pd.DataFrame(a, columns=['a'])
df.rolling(3).mean().dropna()
。。。这也可以通过以下方式实现:
df.rolling(3).apply(np.mean).dropna()
。。。并生产:
a
2 3.0
3 6.0
4 9.0
(第一列是索引值,在这里和下面的示例中可以忽略。)
注意我们是如何提供一个现有的numpy聚合函数的。这就是我的想法。我们应该能够提供我们想要的任何东西,只要它符合聚合函数的功能,即获取一个值向量并从中生成一个值。下面是我们创建自定义聚合函数的另一个示例,在本例中为窗口的L2范数:
df.rolling(3).apply(lambda x: np.sqrt(x.dot(x))).dropna()
如果您不熟悉lambda函数,则如下所示:
def euclidean_dist(x):
return np.sqrt(x.dot(x))
df.rolling(3).apply(euclidean_dist).dropna()
。。。屈服:
a
2 2.236068
3 3.741657
4 5.385165
为了确保这一点,我们可以手动检查np.sqrt(0**2+1**2+2**2)
是否确实是2.236068
[在最初的编辑中,在]最后一段代码中,您的代码可能比您预期的更早失败。调用df.apply(…)
之前失败。您正在尝试将名为df
的滚动对象添加到数字2,然后将其传递到df.apply(…)
。滚动对象不是对其执行操作的对象。您提供的聚合函数通常也不符合聚合函数。a
是一个包含窗口值的列表,b
将是您传入的一个常量额外参数。如果您愿意,它可以是一个滚动对象,但通常不会是您想要做的事情。更清楚地说,这里有一点与您在原始编辑中所做的类似,但很有效:
a = np.arange(8)
df = pd.DataFrame(a, columns=['a'])
n = 4
rol = df.rolling(n)
def prod(window_list, constant_rol):
return window_list.dot(constant_rol.sum().dropna().head(n))
rol.apply(prod, args=(rol,)).dropna()
# [92.0, 140.0, 188.0, 236.0, 284.0]
这是一个人为的例子,但我展示它是为了说明一点,你可以把你想要的任何东西作为常数传递进来,即使是你正在使用的滚动对象本身。动态部分在您的案例中是第一个参数a
,在我的案例中是window\u list
。以单个列表形式定义的所有窗口都会逐个传递到该函数中
根据您的后续评论,这可能是您想要的:
import numpy as np
import pandas as pd
n = 3
a = np.arange(5)
df = pd.DataFrame(a, columns=['a'])
def keep(window, windows):
windows.append(window.copy())
return window[-1]
windows = list()
df['a'].rolling(n).apply(keep, args=(windows,))
df = df.tail(n)
df['a_window'] = windows
将阵列/向量添加到每个滚动块,从而产生:
a a_window
2 2 [0.0, 1.0, 2.0]
3 3 [1.0, 2.0, 3.0]
4 4 [2.0, 3.0, 4.0]
请注意,只有在一次对一列执行此操作时,它才起作用。如果您想在将窗口存储在中之前对其进行一些计算,请保留,这也很好
这就是说,如果没有更多关于您正试图实现的目标的投入,就很难构建一个适合您需要的示例
如果您的最终目标是创建滞后变量的数据帧,那么我会使用shift()
:
。。。给予:
a a-1 a-2
2 2 1.0 0.0
3 3 2.0 1.0
4 4 3.0 2.0
(也许有更好的方法,但它能完成任务。)
关于第一个代码段中的变量b
,还记得DataFram吗
a a_window
2 2 [0.0, 1.0, 2.0]
3 3 [1.0, 2.0, 3.0]
4 4 [2.0, 3.0, 4.0]
import numpy as np
import pandas as pd
a = np.arange(5)
df = pd.DataFrame(a, columns=['a'])
for i in range(1,3):
df['a-%s' % i] = df['a'].shift(i)
df.dropna()
a a-1 a-2
2 2 1.0 0.0
3 3 2.0 1.0
4 4 3.0 2.0
import pandas as pd
a = np.arange(50)
df = pd.DataFrame(a, columns=['a'])
df.index = pd.to_datetime('2016-01-01') + pd.to_timedelta(df['a'], 'D')
blocks, obj, index = df.rolling(4, freq='W')._create_blocks(how=None)
for b in blocks:
print(b)
a
a
2016-01-03 2.0
2016-01-10 9.0
2016-01-17 16.0
2016-01-24 23.0
2016-01-31 30.0
2016-02-07 37.0
2016-02-14 44.0
2016-02-21 NaN
a
a
2016-01-03 NaN
2016-01-10 NaN
2016-01-17 NaN
2016-01-24 50.0
2016-01-31 78.0
2016-02-07 106.0
2016-02-14 134.0
2016-02-21 NaN
import pandas as pd
a = np.arange(5)
df = pd.DataFrame(a, columns=['a'])
blocks, obj, index = df.rolling(3)._create_blocks(how=None)
for b in blocks:
print(b)
a
a
2016-01-01 0
2016-01-02 1
2016-01-03 2
2016-01-04 3
2016-01-05 4