是否可以使用步长大于 1 的 pandas.DataFrame.rolling ?

use*_*831 11 python numpy r zoo pandas

在 R 中,您可以使用指定的窗口计算滚动平均值,该窗口每次可以移动指定的量。

但是,也许我只是没有在任何地方找到它,但您似乎无法在 Pandas 或其他 Python 库中找到它?

有谁知道解决这个问题的方法?我会给你一个例子来说明我的意思:

例子

这里我们有双周数据,我正在计算两个月移动平均线,该移动平均线移动 1 个月,即 2 行。

所以在 RI 中会做类似的事情:two_month__movavg=rollapply(mydata,4,mean,by = 2,na.pad = FALSE) Python 中没有等价物吗?

编辑1:

DATE  A DEMAND   ...     AA DEMAND  A Price
    0  2006/01/01 00:30:00  8013.27833   ...     5657.67500    20.03
    1  2006/01/01 01:00:00  7726.89167   ...     5460.39500    18.66
    2  2006/01/01 01:30:00  7372.85833   ...     5766.02500    20.38
    3  2006/01/01 02:00:00  7071.83333   ...     5503.25167    18.59
    4  2006/01/01 02:30:00  6865.44000   ...     5214.01500    17.53
Run Code Online (Sandbox Code Playgroud)

小智 7

如果数据量不是太大,这里有一个简单的方法:

by = 2
win = 4
start = 3 ## it is the index of your 1st valid value.
df.rolling(win).mean()[start::by] ## calculate all, choose what you need.
Run Code Online (Sandbox Code Playgroud)

  • 用 iloc 切片可能更安全,即。`df.rolling(win).mean().iloc[start::by]` 如果 DF 索引不是从 0 开始的数字序列。 (2认同)

pga*_*zio 7

所以,我知道自从提出这个问题以来已经很长时间了,因为我遇到了同样的问题,并且在处理长时间序列时,您确实希望避免对您不感兴趣的值进行不必要的计算。由于 Pandas 滚动方法没有实现step参数,因此我使用 numpy 编写了一个解决方法。

它基本上是这个链接中的解决方案和BENY提出的索引的结合。

def apply_rolling_data(data, col, function, window, step=1, labels=None):
    """Perform a rolling window analysis at the column `col` from `data`

    Given a dataframe `data` with time series, call `function` at
    sections of length `window` at the data of column `col`. Append
    the results to `data` at a new columns with name `label`.

    Parameters
    ----------
    data : DataFrame
        Data to be analyzed, the dataframe must stores time series
        columnwise, i.e., each column represent a time series and each
        row a time index
    col : str
        Name of the column from `data` to be analyzed
    function : callable
        Function to be called to calculate the rolling window
        analysis, the function must receive as input an array or
        pandas series. Its output must be either a number or a pandas
        series
    window : int
        length of the window to perform the analysis
    step : int
        step to take between two consecutive windows
    labels : str
        Name of the column for the output, if None it defaults to
        'MEASURE'. It is only used if `function` outputs a number, if
        it outputs a Series then each index of the series is going to
        be used as the names of their respective columns in the output

    Returns
    -------
    data : DataFrame
        Input dataframe with added columns with the result of the
        analysis performed

    """

    x = _strided_app(data[col].to_numpy(), window, step)
    rolled = np.apply_along_axis(function, 1, x)

    if labels is None:
        labels = [f"metric_{i}" for i in range(rolled.shape[1])]

    for col in labels:
        data[col] = np.nan

    data.loc[
        data.index[
            [False]*(window-1)
            + list(np.arange(len(data) - (window-1)) % step == 0)],
        labels] = rolled

    return data


def _strided_app(a, L, S):  # Window len = L, Stride len/stepsize = S
    """returns an array that is strided
    """
    nrows = ((a.size-L)//S)+1
    n = a.strides[0]
    return np.lib.stride_tricks.as_strided(
        a, shape=(nrows, L), strides=(S*n, n))
Run Code Online (Sandbox Code Playgroud)


WeN*_*Ben 6

您可以再次使用滚动,只需要一点点工作与您分配索引

这里 by = 2

by = 2

df.loc[df.index[np.arange(len(df))%by==1],'New']=df.Price.rolling(window=4).mean()
df
    Price    New
0      63    NaN
1      92    NaN
2      92    NaN
3       5  63.00
4      90    NaN
5       3  47.50
6      81    NaN
7      98  68.00
8     100    NaN
9      58  84.25
10     38    NaN
11     15  52.75
12     75    NaN
13     19  36.75
Run Code Online (Sandbox Code Playgroud)


NaN*_*NaN 1

现在,这对于一维数据数组来说有点大材小用,但您可以简化它并提取您需要的内容。由于 pandas 可以依赖 numpy,因此您可能需要检查它们的滚动/跨步功能是如何实现的。20 个连续数字的结果。7 天的窗口,跨步/滑动 2

    z = np.arange(20)
    z   #array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
    s = stride(z, (7,), (2,))

np.mean(s, axis=1)  # array([ 3.,  5.,  7.,  9., 11., 13., 15.])
Run Code Online (Sandbox Code Playgroud)

这是我使用的代码,没有文档的主要部分。它源自 numpy 中 strided 函数的许多实现,可以在此站点上找到。有变体和化身,这只是另一个。

def stride(a, win=(3, 3), stepby=(1, 1)):
    """Provide a 2D sliding/moving view of an array.
    There is no edge correction for outputs. Use the `pad_` function first."""
    err = """Array shape, window and/or step size error.
    Use win=(3,) with stepby=(1,) for 1D array
    or win=(3,3) with stepby=(1,1) for 2D array
    or win=(1,3,3) with stepby=(1,1,1) for 3D
    ----    a.ndim != len(win) != len(stepby) ----
    """
    from numpy.lib.stride_tricks import as_strided
    a_ndim = a.ndim
    if isinstance(win, int):
        win = (win,) * a_ndim
    if isinstance(stepby, int):
        stepby = (stepby,) * a_ndim
    assert (a_ndim == len(win)) and (len(win) == len(stepby)), err
    shp = np.array(a.shape)    # array shape (r, c) or (d, r, c)
    win_shp = np.array(win)    # window      (3, 3) or (1, 3, 3)
    ss = np.array(stepby)      # step by     (1, 1) or (1, 1, 1)
    newshape = tuple(((shp - win_shp) // ss) + 1) + tuple(win_shp)
    newstrides = tuple(np.array(a.strides) * ss) + a.strides
    a_s = as_strided(a, shape=newshape, strides=newstrides, subok=True).squeeze()
    return a_s
Run Code Online (Sandbox Code Playgroud)

我没有指出您可以创建一个输出,并将其作为一列附加到 pandas 中。回到上面使用的原始定义

nans = np.full_like(z, np.nan, dtype='float')  # z is the 20 number sequence
means = np.mean(s, axis=1)   # results from the strided mean
# assign the means to the output array skipping the first and last 3 and striding by 2

nans[3:-3:2] = means        

nans # array([nan, nan, nan,  3., nan,  5., nan,  7., nan,  9., nan, 11., nan, 13., nan, 15., nan, nan, nan, nan])
Run Code Online (Sandbox Code Playgroud)