gpt4 book ai didi

python - 窗口大小的滚动平均值是列值的间隔

转载 作者:行者123 更新时间:2023-12-04 17:23:41 24 4
gpt4 key购买 nike

我正在尝试计算一些不完整数据的滚动平均值。我想对第 1 列(英里)中值的大小为 1.0 的窗口的第 2 列中的值求平均值。我试过 .rolling(),但是(根据我有限的理解)这只会创建基于索引的窗口,而不是基于列值。

import pandas as pd
import numpy as np

df = pd.DataFrame([
[4.5, 10],
[4.6, 11],
[4.8, 9],
[5.5, 6],
[5.6, 6],
[8.1, 10],
[8.2, 13]
])

averages = []
for index in range(len(df)):
nearby = df.loc[np.abs(df[0] - df.loc[index][0]) <= 0.5]
averages.append(nearby[1].mean())
df['rollingAve'] = averages

给出所需的输出:

     0   1  rollingAve
0 4.5 10 10.0
1 4.6 11 10.0
2 4.8 9 10.0
3 5.5 6 6.0
4 5.6 6 6.0
5 8.1 10 11.5
6 8.2 13 11.5

但这对于大数据帧来说会大大减慢速度。有没有办法用不同的窗口大小或类似的东西来实现 .rolling() ?

最佳答案

Pandas 的BaseIndexer非常方便,尽管需要一点点挠头才能正确使用。

在下文中,我使用 np.searchsorted快速找到每个窗口的索引(开始、结束):

from pandas.api.indexers import BaseIndexer

class RangeWindow(BaseIndexer):
def __init__(self, val, width):
self.val = val.values
self.width = width

def get_window_bounds(self, num_values, min_periods, center, closed):
if min_periods is None: min_periods = 0
if closed is None: closed = 'left'
w = (-self.width/2, self.width/2) if center else (0, self.width)
side0 = 'left' if closed in ['left', 'both'] else 'right'
side1 = 'right' if closed in ['right', 'both'] else 'left'
ix0 = np.searchsorted(self.val, self.val + w[0], side=side0)
ix1 = np.searchsorted(self.val, self.val + w[1], side=side1)
ix1 = np.maximum(ix1, ix0 + min_periods)

return ix0, ix1

一些高级选项:min_periodscenterclosed 是根据DataFrame.rolling 实现的。指定。

应用:

df = pd.DataFrame([
[4.5, 10],
[4.6, 11],
[4.8, 9],
[5.5, 6],
[5.6, 6],
[8.1, 10],
[8.2, 13]
], columns='a b'.split())

df.b.rolling(RangeWindow(df.a, width=1.0), center=True, closed='both').mean()

# gives:
0 10.0
1 10.0
2 10.0
3 6.0
4 6.0
5 11.5
6 11.5
Name: b, dtype: float64

时间:

df = pd.DataFrame(
np.random.uniform(0, 1000, size=(1_000_000, 2)),
columns='a b'.split(),
)
df = df.sort_values('a').reset_index(drop=True)


%%time
avg = df.b.rolling(RangeWindow(df.a, width=1.0)).mean()

CPU times: user 133 ms, sys: 3.58 ms, total: 136 ms
Wall time: 135 ms

性能更新:

根据 @anon01 的评论,我想知道是否可以更快地处理滚动涉及大窗口的情况。事实证明,我应该先测量 Pandas 的滚动均值和总和性能......(过早的优化,有人吗?)最后看看为什么。

无论如何,我们的想法是只执行一次 cumsum,然后计算被 windows 端点取消引用的元素的差异:

# both below working on numpy arrays:
def fast_rolling_sum(a, b, width):
z = np.concatenate(([0], np.cumsum(b)))
ix0 = np.searchsorted(a, a - width/2, side='left')
ix1 = np.searchsorted(a, a + width/2, side='right')
return z[ix1] - z[ix0]

def fast_rolling_mean(a, b, width):
z = np.concatenate(([0], np.cumsum(b)))
ix0 = np.searchsorted(a, a - width/2, side='left')
ix1 = np.searchsorted(a, a + width/2, side='right')
return (z[ix1] - z[ix0]) / (ix1 - ix0)

有了这个(以及上面的 100 万行 df),我明白了:

%timeit fast_rolling_mean(df.a.values, df.b.values, width=100.0)
# 93.9 ms ± 335 µs per loop

对比:

%timeit df.rolling(RangeWindow(df.a, width=100.0), min_periods=1).mean()
# 248 ms ± 1.54 ms per loop

但是!!! Pandas 可能已经在进行这样的优化(这是一个非常明显的优化)。时间不会随着窗口的增加而增加(这就是为什么我说我应该先检查)。

关于python - 窗口大小的滚动平均值是列值的间隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64721437/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com