代码之家  ›  专栏  ›  技术社区  ›  Torin M.

Python中计算大型列表标准差的更有效方法

  •  3
  • Torin M.  · 技术社区  · 8 年前

    您好,我正在计算一系列大约20000个值的标准偏差。下面是我的代码示例:

    from statistics import stdev
    
    def main():
        a = [x for x in range(0,20000)]
        b = []
    
        for x in range(2, len(a) + 2):
            b.append(stdev(a[:x]))
    
        print(b)
    
    main()
    

    这种方法速度非常慢,我正试图找出一种方法来提高效率。非常感谢您的帮助。非常感谢。

    [Done] exited with code=null in 820.376 seconds
    
    2 回复  |  直到 8 年前
        1
  •  9
  •   DSM    8 年前

    看起来你想要一个扩展的标准差,我会使用pandas库和 pandas.Series.expanding 方法:

    In [156]: main()[:5]
    Out[156]: 
    [0.7071067811865476,
     1.0,
     1.2909944487358056,
     1.5811388300841898,
     1.8708286933869707]
    
    In [157]: pd.Series(range(20000)).expanding().std()[:5]
    Out[157]: 
    0         NaN
    1    0.707107
    2    1.000000
    3    1.290994
    4    1.581139
    dtype: float64
    

    如果需要,您可以轻松地将第一个元素切掉并转换为列表:

    In [158]: pd.Series(range(20000)).expanding().std()[1:6].tolist()
    Out[158]: 
    [0.7071067811865476,
     1.0,
     1.2909944487358056,
     1.5811388300841898,
     1.8708286933869707]
    

    虽然与列表相比,序列是处理时间序列更有用的数据类型,而且性能更高:

    In [159]: %timeit pd.Series(range(20000)).expanding().std()
    1.07 ms ± 30.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
        2
  •  3
  •   Thierry Lathuille    8 年前

    您可以跟踪值和值的平方和:

    from math import sqrt
    
    a = range(0,20000)
    
    def sdevs(a):
        sds = [0]
        n = 1
        sum_x = a[0]
        sum_x_squared = a[0]**2
    
        for x in a[1:]:
            sum_x += x
            sum_x_squared += x**2
            n += 1
            # as noted by @Andrey Tyukin, statistics.stdev returns
            # the unbiased estimator, hence the n/(n-1)
            sd = sqrt(n/(n-1)*(sum_x_squared/n - (sum_x/n)**2))
            sds.append(sd)
        return sds
    
    sds = sdevs(a)
    print(sds[10000])
    # 2887.184355042123
    

    在一台使用了10年的PC上,这大约需要24毫秒。