当前位置: 首页 > 面试题库 >

熊猫滚动物体如何工作?

商琛
2023-03-14
问题内容

编辑: 鉴于这个问题可能涉及太多,所以我简化了这个问题。问题的实质在下面以黑体显示。

我想进一步了解使用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或2dndarray并构建等于指定窗口大小的滚动“块”(如下所示)。 对象与 下面
输出 相比 如何 ?.rolling``ndarray
它是一个迭代器,为每个块存储了某些属性吗?还是完全其他?我尝试使用诸如__dict__和的属性/方法在对象上使用制表符补全_get_index(),但它们并不能告诉我太多。我也在_create_blocks熊猫中看到了一种方法-
完全类似于该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部分,额外功劳

由于必须在pandas.core.window.Rolling.apply中使用上述NumPy方法(此处为OLS实现)func

从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对象的布局有什么关系?


问题答案:

我建议您看一下源代码,以便深入了解滚动的作用。特别地,我建议您看一下generic.py和window.py中的rolling函数。从那里,你可以看一下类,如果你指定一个窗口类型或默认所使用的类。最后一个继承自,最终继承于和。WindowRolling_Rolling_and_Expanding``_Rolling``_Window

就是说,我将给我两分钱:熊猫的整个滚动机制依赖于numpy函数apply_along_axis。特别是用它在这里的大熊猫。它与windows.pyxcython模块一起使用。进入您的系列,出来总的滚动窗口。对于典型的聚合函数,它可以为您高效地处理它们,而对于自定义函数(使用apply()),它使用roll_generic()in windows.pyx

熊猫中的滚动功能独立地在熊猫数据帧列上运行。它不是python迭代器,并且是延迟加载的,这意味着在您对它应用聚合函数之前不会计算任何内容。直到完成聚合之前,才会使用实际应用数据滚动窗口的功能。

造成混乱的原因可能是您将滚动对象视为数据框。(您已经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_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]

请注意,仅当您一次在列上执行此操作时,它才有效。如果您想在存储之前在窗口上做一些数学运算,keep那也很好。

就是说,如果没有更多关于您要实现的目标的投入,那么很难构建一个适合您需求的示例。

如果您的最终目标是创建一个滞后变量的数据框,那么我将使用使用实列shift()

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

(可能有一些更漂亮的方法,但是它可以完成工作。)

关于b第一个代码段中的变量,请记住,pandas中的DataFrame通常不作为任意尺寸/对象的张量来处理。您可能可以将任何内容塞进去,但是最终将得到字符串,时间对象,整数和浮点数。这可能就是熊猫设计者没有费心将滚动聚合转换为非标量值的原因。甚至似乎还没有一个简单的字符串被允许作为聚合函数的输出。

无论如何,我希望这能回答您的一些问题。如果没有告知我,我会尽力在评论或更新中为您提供帮助。

关于_create_blocks()滚动物体功能的最后说明。

_create_blocks()使用freq参数时,该函数将处理重新索引和装箱rolling

如果您将freq与以下几个星期配合使用freq=W

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

注意,这不是聚合滚动的输出。这只是它正在处理的新块。在这之后。我们像这样进行聚合sum并得到:

                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

…以总和检验:50 = 2 + 9 + 16 + 23。

如果您不使用freq它作为参数,它只会返回原始数据结构:

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

…,用于滚动窗口聚合。



 类似资料:
  • 问题内容: 我最终在写出这个问题的时候就弄清楚了,所以无论如何我都会发布并回答我自己的问题,以防别人需要一点帮助。 问题 假设我们有一个,包含该数据。 目标 对于每一行,将 其一个月*以内的每一行的总和相加,最好使用一种非常干净的语法。 * 我尝试过的 但这引发了异常 版: 问题答案: 使用偏移量而不是专门使用30天或大约一个月。 最初,我凭直觉跳了起来,使用了一个月,但现在很清楚为什么不起作用。

  • 我有一个这样的数据帧: 我试图了解如何应用自定义滚动函数。我尝试过这样做: 但这给了我原来的DataFrame回来: 如果我有一个不同的数据帧,如下所示: 同样的滚动应用似乎工作: 为什么这对第一个数据帧不起作用? 熊猫版本:0.20。2. Python版本:2.7.10 使现代化 所以,我意识到的列是对象类型的,而lambda函数的输出是整数。的列都是整数列。我假设这就是应用程序不起作用的原因。

  • 我需要得到df的滚动第二大值。 以获得最大的价值 当我尝试这个时,python抛出了一个错误 这是虫子吗?我还能用什么性能好的?

  • 问题内容: 如何获得系列中最常出现的物品? 考虑系列 返回值应该是 问题答案: 您可以使用并提取第一个值: 这不一定是低效率的。与往常一样,对您的数据进行测试以查看适合的数据。

  • 问题内容: 我的动机是利用熊猫功能来进行滚动多因素回归(这个问题是 不是 关于滚动多因素回归)。我希望我可以在a之后使用,并使用所得结果提取ndarray并执行必要的矩阵乘法。那样行不通。 这是我发现的: 对象是什么样的: 矩阵乘法的行为正常: 使用Apply执行逐行点积的行为符合预期: Groupby-> Apply的行为符合我的预期: 但是当我跑步时: 我得到: AttributeError:

  • 问题内容: 因此,我试图理解pandas.dataFrame.groupby()函数,并在文档中遇到了以下示例: 为了进一步探讨,我没有这样做: 它输出相同的dataFrame,但是当我这样做时: 它给了我这个: 这是什么意思?在正常的dataFrame打印中,仅输出前5行,这是什么情况? 还有为什么打印输出与数据帧输出相同?难道不是应该按列的元素分组吗? 问题答案: 当您只使用 你得到一个对象。

  • 问题内容: 样本数据 我有一些这样的代码 电流输出 预期产量 由于数据正在流式传输。我想检查重复的记录(其商人和金额值相同)是否在两分钟内到达,所以我将其丢弃并对其不进行任何处理。将其打印为副本。 我是否需要对索引压缩或groupby进行处理?但是然后如何等于多列。或在两列上有一些滚动条件,但找不到任何方法。 我在这里想念什么? 谢谢 编辑 所以我尝试这样的事情,如果结果少于120秒,我可以处理它

  • 我想知道它到底是什么意思?我需要改变什么吗? 如果坚持使用,应如何挂起警告?