Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 窗口大小为列值间隔的滚动平均值_Python_Pandas_Dataframe - Fatal编程技术网

Python 窗口大小为列值间隔的滚动平均值

Python 窗口大小为列值间隔的滚动平均值,python,pandas,dataframe,Python,Pandas,Dataframe,我试图计算一些不完整数据的滚动平均值。我想在大小为第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],

我试图计算一些不完整数据的滚动平均值。我想在大小为第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
但对于大数据帧来说,这会大大降低速度。有没有一种方法可以实现具有不同窗口大小的.rolling()或类似的功能?

Panda的方法非常方便,尽管它需要一些技巧才能正确使用

在下面,我使用快速查找每个窗口的索引(开始、结束):

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
一些高级选项:
minu_periods
center
closed
根据指定的实现

应用程序:

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
计时:

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
性能更新:

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发表评论后,我想知道如果滚动涉及到大窗口,是否可以加快速度。原来我应该先测量熊猫的滚动平均值和总和表现。。。(过早优化,有人吗?)

无论如何,我们的想法是只做一次
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 df.rolling(RangeWindow(df.a, width=100.0), min_periods=1).mean()
# 248 ms ± 1.54 ms per loop

然而!!!熊猫可能已经在做这样的优化了(这是一个非常明显的优化)。时间不会随着窗口变大而增加(这就是为什么我说我应该先检查的原因)。

df.rolling
系列。如果索引类型为
DateTimeIndex
TimedeltaIndex
,则滚动允许基于值的窗口。您可以使用此选项接近所需的结果:

df = df.set_index(pd.TimedeltaIndex(df[0]*1e9))
df["rolling_mean"] = df[1].rolling("1s").mean()
df = df.reset_index(drop=True)
输出:

     0   1  rolling_mean
0  4.5  10     10.000000
1  4.6  11     10.500000
2  4.8   9     10.000000
3  5.5   6      8.666667
4  5.6   6      7.000000
5  8.1  10     10.000000
6  8.2  13     11.500000
优势 这是一个三线解决方案,应具有良好的性能,充分利用datetime后端

缺点 这绝对是一个错误,将里程列转换为时间增量秒,平均值不居中(
center
不适用于datetimelike和基于偏移量的窗口)


总的来说:如果您重视性能,并且能够接受一种不以中心为中心的方法,那么这将是一个很好的方法,可以添加一两条注释。

您的代码似乎不正确aligned@piterbarg谢谢,我已经修好了,所以现在应该可以运行了。这很酷,我不知道。对于一个大数据集的性能,或者当窗口大小有很多行时,有什么想法吗?这感觉就像熊猫API中的一个缺口。我想知道作为一个整体,这会有多远超出规格contribution@anon01
np.searchsorted
相当快(算法与
bisect
相同),但无可否认,当第二个数组被排序时,它可能会更快(在这种情况下,应该有一个标志告诉
numpy
)。有关讨论,请参见例如。也就是说,在一个
r5d.2xlarge
EC2实例上,我看到
searchsorted(a,b)
大约540ms,其中
a
b
被排序,并且有1000万个浮动64。至于我在上面的回答中提到的整体操作:处理大窗口没有额外的成本(我最初认为和你一样,但事实并非如此)