草庐IT

python - pandas 滚动对象如何工作?

coder 2023-05-23 原文

编辑:我浓缩了这个问题,因为它可能太复杂了。问题的重点在下面以粗体显示。

我想了解更多有关使用 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 实现 here)是必需的,因为 funcpandas.core.window.Rolling.apply必须

produce a single value from an ndarray input *args and **kwargs are passed to the function



所以参数不能是另一个滚动对象。 IE。
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 generic.py 中的函数和 window.py .从那里您可以查看 Window class如果您指定窗口类型或默认值 Rolling class .最后一个继承自 _Rolling_and_Expanding最终 _Rolling_Window .

也就是说,我要给我两分钱:Pandas 的整个滚动机制依赖于 numpy 函数 apply_along_axis .特别是使用 here在 Pandas 。它与 windows.pyx 一起使用cython 模块。在你的系列中,出现了聚合滚动窗口。对于典型的聚合函数,它可以有效地为您处理它们,但对于自定义函数(使用 apply() ),它使用 roll_generic() windows.pyx .

pandas 中的滚动功能独立地对 Pandas 数据框列进行操作。它不是 python iterator , 并且是延迟加载的,这意味着在您对其应用聚合函数之前不会计算任何内容。实际应用数据滚动窗口的函数直到聚合完成之前才使用。

混淆的一个来源可能是您将滚动对象视为数据框。 (您在上一个代码片段中已将滚动对象命名为 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 的滚动对象。传递给 df.apply(...) 之前的数字 2 .滚动对象不是您对其进行操作的对象。您提供的聚合函数通常也不符合聚合函数。 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 中的 DataFrames 通常不会作为任意维度/对象的张量处理。你可能可以把任何你想要的东西塞进去,但最终字符串、时间对象、整数和浮点数是预期的。这可能是 Pandas 的设计者没有考虑允许滚动聚合到非标量值的原因。似乎甚至不允许使用简单的字符串作为聚合函数的输出。

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

关于 _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

...并用于滚动窗口聚合。

关于python - pandas 滚动对象如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45254174/

有关python - pandas 滚动对象如何工作?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  7. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐