【问题标题】:Pandas dataframe rolling mean efficiently熊猫数据框滚动意味着有效
【发布时间】:2019-01-25 22:10:15
【问题描述】:

我有一个巨大的数据框,并且经常添加一行。 我希望在添加单行后更新滚动平均值(在最近的时间窗口内)和标准偏差。有人知道 pandas 是使用新包含/删除的行的增量在恒定时间内自动执行此操作,还是实际上重新计算总和和平方和?

编辑:已请求一个示例来解释我所说的恒定时间滚动平均更新的含义:

data_set = (1,2,3)
old_mean = 2

new_value: 4
expired_value = 1
new_mean = (old_mean * num_of_values - expired_value + new_value) / num_values
         = (2 * 3 - 1 + 4) / 3
         = 3

^恒定时间。这对于大型数据帧很重要。

【问题讨论】:

  • 这是一个相当简单的操作,请提供minimal reproducible example
  • 滚动均值部分很容易理解,但是您仍然没有提供 DataFrame。听起来你只是想要df.rolling(3).mean()
  • 所以我的问题是,mean() 部分是否是一个属性,它是通过添加新行在恒定时间内更新的属性,还是一个费力遍历所有行的方法每次添加时滚动 DF 的一部分?

标签: python pandas dataframe mean


【解决方案1】:

从性能数据和代码来看,* pandas 没有执行您要求的任何优化(* 我对代码没有深入的了解,所以也许我遗漏了一些东西)。只需查看how the Window operation is implemented,您将找不到任何将任何预先计算的值考虑在内的过滤器。 如果你仔细想想,你可能会得出结论,熊猫需要记住所有值发生变化的“脏”行。这是相当多的内存密集型操作。 看看性能数据,这也是正确的:

import pandas
import numpy
df = pandas.DataFrame({'A':numpy.random.random(20000000)})
r = df.rolling(3)

.

%%time
r.mean()

CPU 时间:用户 312 毫秒,系统:515 毫秒,总计:828 毫秒 挂墙时间:836 毫秒

# Add one row
df.loc[len(df)] = {'A': numpy.random.random(1)[0]}

.

%%time
r.mean()

CPU 时间:用户 334 毫秒,系统:534 毫秒,总计:868 毫秒 挂墙时间:950 毫秒 无论您执行单元格的频率如何,时间都不会发生太大变化。 那么如何改善时代呢? 让我们以此为基础来比较其他结果:

%timeit df.rolling(3).mean()

每个循环 854 毫秒 ± 38.5 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

这会计算窗口大小为 3 的所有行的平均值。 为了根据新行的最后相关行计算平均值,您只能使用 pandas 来执行此操作:

%timeit df.iloc[-3:, df.columns.get_loc('A')].mean()

每个循环 192 µs ± 21.9 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环)

这已经是 4000 倍以上的改进。 但是直接使用numpy会增加一些:

%timeit df.values[-3:].mean()

每个循环 15.2 µs ± 699 ns(平均值 ± 标准偏差,7 次运行,每次 100000 次循环)

这远高于 8000 倍。 没有更多的努力,这就像它得到的一样快。但是请注意,在您自己实现较低级别的操作时,您会失去 pandas 提供的一些便利(类型检查和转换等)。如果您想使用 Cython,那就更是如此。

【讨论】:

    猜你喜欢
    • 2022-12-18
    • 2021-12-22
    • 1970-01-01
    • 2016-04-29
    • 2021-09-05
    • 1970-01-01
    • 2020-05-31
    • 2021-03-31
    • 2020-07-05
    相关资源
    最近更新 更多