Python 如何使用NumPy/SciPy计算移动/运行/滚动任意函数(例如峰度和偏度)

Python 如何使用NumPy/SciPy计算移动/运行/滚动任意函数(例如峰度和偏度),python,numpy,scipy,statistics,Python,Numpy,Scipy,Statistics,我正在研究时间序列数据。为了从数据中获取特征,我必须计算移动平均值、中值、模式、斜率、峰度、偏度等。我熟悉scipy.stat,它为直接计算提供了一种简单的方法来计算这些量。但对于移动/跑步部分,我浏览了整个互联网,却一无所获 令人惊讶的是,使用numpy计算移动平均值、中值和模式非常容易。不幸的是,没有用于计算峰度和偏度的内置函数。 如果有人能帮忙,如何用scipy计算移动峰度和偏度?非常感谢提供了一种方法,该方法可以与其方法(即df.rolling().apply())结合使用,将任意函数应

我正在研究时间序列数据。为了从数据中获取特征,我必须计算移动平均值、中值、模式、斜率、峰度、偏度等。我熟悉
scipy.stat
,它为直接计算提供了一种简单的方法来计算这些量。但对于移动/跑步部分,我浏览了整个互联网,却一无所获

令人惊讶的是,使用
numpy
计算移动平均值、中值和模式非常容易。不幸的是,没有用于计算峰度和偏度的内置函数。 如果有人能帮忙,如何用scipy计算移动峰度和偏度?非常感谢

提供了一种方法,该方法可以与其方法(即
df.rolling().apply()
)结合使用,将任意函数应用于指定的滚动窗口


如果您正在寻找基于NumPy的解决方案,您可以使用(免责声明:我是它的主要作者)

在这里,您可以找到以下内容:

  • flyingcircus.extra.running_apply()
    :可以将任何函数应用于1D数组并支持权重,但速度较慢
  • flyingcircus.extra.moving_apply()
    :可以将支持
    轴:int
    参数的任何函数应用于1D数组,并支持权重,速度快(但内存不足)
  • flyingcircus.extra.rolling\u apply\u nd()
    :可以将任何支持
    轴:int |序列[int]
    参数的函数应用于任何nd数组,速度快(且内存效率高),但不支持权重
  • 根据您的要求,我建议使用
    rolling\u apply\u nd()
    ,例如:

    import numpy as np
    import scipy as sp
    import flyingcircus as fc
    
    import scipy.stats
    
    
    NUM = 30
    arr = np.arange(NUM)
    
    window = 4
    new_arr = fc.extra.rolling_apply_nd(arr, window, func=sp.stats.kurtosis)
    print(new_arr)
    # [-1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36
    #  -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36 -1.36
    #  -1.36 -1.36 -1.36]
    
    当然,可以随意检查,它是开源的(GPL)


    编辑 为了了解我们谈论的速度,以下是FlyingCircus中实施的解决方案的基准:

    一般方法
    flyingcircus.extra.running\u apply()
    flyingcircus.extra.rolling\u apply nd()
    flyingcircus.extra.moving\u apply()
    慢几个数量级,第一种方法比第二种方法快大约一个数量级。 这显示了通用性或加权支持的速度价格

    使用以下代码中的脚本获得上述曲线图:

    import scipy as sp
    import flyingcircus as fc
    import scipy.stats
    
    
    WINDOW = 4
    FUNC = sp.stats.kurtosis
    
    
    def my_rolling_apply_nd(arr, window=WINDOW, func=FUNC):
        return fc.extra.rolling_apply_nd(arr, window, func=FUNC)
    
    
    def my_moving_apply(arr, window=WINDOW, func=FUNC):
        return fc.extra.moving_apply(arr, window, func)
    
    
    def my_running_apply(arr, window=WINDOW, func=FUNC):
        return fc.extra.running_apply(arr, window, func)
    
    
    def equal_output(a, b):
        return np.all(np.isclose(a, b))
    
    
    input_sizes = (5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000)
    funcs = my_rolling_apply_nd, my_moving_apply, my_running_apply
    
    runtimes, input_sizes, labels, results = benchmark(
        funcs, gen_input=np.random.random, equal_output=equal_output,
        input_sizes=input_sizes)
    
    plot_benchmarks(runtimes, input_sizes, labels, units='s')
    plot_benchmarks(runtimes, input_sizes, labels, units='ms', zoom_fastest=8)
    

    经过反复研究,我提出了一个完全基于
    numpy
    scipy
    的解决方案。当然,它使用的是
    峰度
    偏斜

    import numpy as np
    from scipy.stats import kurtosis, skew
    
    # Window size
    N = 4
    
    # Some random data
    m = np.array([2, 3, 10, 11, 0, 4, 8, 2, 5, 9])
    
    # Running Kurtosis
    def runningKurt(x, N):
        # Initilize placeholder array
        y = np.zeros((len(x) - (N - 1),))
        for i in range(len(x) - (N - 1)):
    
             y[i] = kurtosis(x[i:(i + N)])
    
        return y
    
    # Running Kurtosis
    
    def runningSkew(x, N):
        # Initilize placeholder array
        y = np.zeros((len(x) - (N - 1),))
        for i in range(len(x) - (N - 1)):
    
             y[i] = skew(x[i:(i + N)])
    
        return y
    
    kurt = runningKurt(m, N)
    print("kurtosis : ", kurt)
    # kurtosis :  [-1.93940828 -1.77879935 -1.61464214 -1.40236694 -1.15428571 -1.07626667 -1.42666667]
    
    
    skw = runningSkew(m, N)
    print("skew : ", skw)
    # skew :  [ 0.         -0.1354179  -0.26356495 -0.13814702  0.43465076  0.32331615 -0.36514837]
    

    谢谢你宝贵的时间和努力。实际上,我的要求是只使用
    numpy
    scipy
    。我知道pandas
    df.rolling().apply()
    ,但不在项目范围内。我一定会看的。幸运的是,我成功地用simple
    numpy
    scipy
    完成了这项工作。请看一下我的答案。非常感谢@KhurramKhalil您的答案实现了类似于
    flyingcircus.extra.running_apply()
    的功能。就时间而言,对于您的情况,这不是一个理想的解决方案,您可以从我添加到编辑中的基准中看到。再次感谢您的努力。我明白你的意思了,实际上我只需要几千条数据的解决方案,所以我很快就部署了所管理的内容。然而,我正在转向
    flyingcircus.extra.rolling\u apply\u nd()
    以备将来使用。这基本上是
    flyingcircus.extra.running\u apply()
    中采用的方法,速度非常慢,请查看我答案的更新,以了解这与
    flyingcircus.extra.rolling\u apply\u nd()
    相比有多慢。基本上,问题在于您使用的是显式循环,这通常不是处理NumPy数组的最快方式。