每对numpy.array的中间点

时间:2014-05-25 13:52:16

标签: python numpy mean

我有一个表格数组:

x = np.array([ 1230., 1230., 1227., 1235., 1217., 1153., 1170.])

我想生成另一个数组,其中值是我原始数组中每对值的平均值:

xm = np.array([ 1230., 1228.5, 1231., 1226., 1185., 1161.5])

有人知道在不使用循环的情况下最简单快捷的方法吗?

6 个答案:

答案 0 :(得分:41)

更短,更甜蜜:

(x[1:] + x[:-1]) / 2

  • 这更快:

    >>> python -m timeit -s "import numpy; x = numpy.random.random(1000000)" "x[:-1] + numpy.diff(x)/2"
    100 loops, best of 3: 6.03 msec per loop
    
    >>> python -m timeit -s "import numpy; x = numpy.random.random(1000000)" "(x[1:] + x[:-1]) / 2"
    100 loops, best of 3: 4.07 msec per loop
    
  • 这非常准确:

    考虑x[1:] + x[:-1]中的每个元素。因此,请考虑x₀x₁,第一和第二个元素。

    根据IEEE,

    x₀ + x₁计算完美精度,然后然后四舍五入。因此,如果只需要这一切,那将是正确的答案。

    (x₀ + x₁) / 2只是该值的一半。除了两种情况外,几乎总是可以通过将指数减1来完成:

    • x₀ + x₁溢出。这将导致无穷大(任一符号)。这不是想要的,所以计算将错误

    • x₀ + x₁下溢。由于尺寸减少,舍入将是完美的,因此计算将正确

    在所有其他情况下,计算将正确


    现在考虑x[:-1] + numpy.diff(x) / 2。通过检查来源,直接评估

    x[:-1] + (x[1:] - x[:-1]) / 2
    

    然后再考虑x₀x₁

    对于许多值,

    x₁ - x₀会对下溢产生严重的“问题”。这也会因大量取消而失去精确度。但是,如果标志相同,这并不是很明显,因为错误会在添加时有效抵消。重要的是舍入发生

    (x₁ - x₀) / 2将不会更低,但x₀ + (x₁ - x₀) / 2涉及另一个舍入。这意味着错误蔓延。证明:

    import numpy
    
    wins = draws = losses = 0
    
    for _ in range(100000):
        a = numpy.random.random()
        b = numpy.random.random() / 0.146
    
        x = (a+b)/2 
        y = a + (b-a)/2
    
        error_mine   = (a-x) - (x-b)
        error_theirs = (a-y) - (y-b)
    
        if x != y:
            if abs(error_mine) < abs(error_theirs):
                wins += 1
            elif abs(error_mine) == abs(error_theirs):
                draws += 1
            else:
                losses += 1
        else:
            draws += 1
    
    wins / 1000
    #>>> 12.44
    
    draws / 1000
    #>>> 87.56
    
    losses / 1000
    #>>> 0.0
    

    这表明,对于精心挑选的1.46常量,diff变体的完整12-13%的答案是错误的!正如所料,我的版本总是正确的。

    现在考虑下溢。虽然我的变体存在溢出问题,但这些问题远远不如取消问题。很明显,为什么上述逻辑的双舍入是非常有问题的。证明:

    ...
        a = numpy.random.random()
        b = -numpy.random.random()
    ...
    
    wins / 1000
    #>>> 25.149
    
    draws / 1000
    #>>> 74.851
    
    losses / 1000
    #>>> 0.0
    

    是的,它有25%的错误!

    事实上,将此值提高到50%并不需要太多修剪:

    ...
        a = numpy.random.random()
        b = -a + numpy.random.random()/256
    ...
    
    wins / 1000
    #>>> 49.188
    
    draws / 1000
    #>>> 50.812
    
    losses / 1000
    #>>> 0.0
    

    嗯,这并不是那么糟糕。我认为,只要标志相同,就只有1个最不重要的位置


所以你有它。我的答案是最好的,除非您找到两个值的平均值,其总和超过1.7976931348623157e+308或小于-1.7976931348623157e+308

答案 1 :(得分:7)

短而甜蜜:

x[:-1] + np.diff(x)/2

即,除了最后一个元素之外,取x的每个元素,并添加它与后续元素之间差异的一半。

答案 2 :(得分:4)

试试这个:

midpoints = x[:-1] + np.diff(x)/2

这很简单,应该很快。

答案 3 :(得分:1)

如果速度很重要,请按照Veedrac的答案使用乘法而不是除法:

    0.5 * (x[:-1] + x[1:])

分析结果:

    >>> python -m timeit -s "import numpy; x = numpy.random.random(1000000)" "0.5 * (x[:-1] + x[1:])"
    100 loops, best of 3: 4.20 msec per loop

    >>> python -m timeit -s "import numpy; x = numpy.random.random(1000000)" "(x[:-1] + x[1:]) / 2"
    100 loops, best of 3: 5.10 msec per loop

答案 4 :(得分:0)

>>> x = np.array([ 1230., 1230., 1227., 1235., 1217., 1153., 1170.])

>>> (x+np.concatenate((x[1:], np.array([0]))))/2
array([ 1230. ,  1228.5,  1231. ,  1226. ,  1185. ,  1161.5,   585. ])

现在你可以剥离最后一个元素,如果你想要

答案 5 :(得分:0)

我最终在多维数组上使用此操作,因此我将发布我的解决方案(受np.diff()源代码的启发)

def zcen(a, axis=0):
    a = np.asarray(a)
    nd = a.ndim
    slice1 = [slice(None)]*nd
    slice2 = [slice(None)]*nd
    slice1[axis] = slice(1, None)
    slice2[axis] = slice(None, -1)
    return (a[slice1]+a[slice2])/2

>>> a = [[1, 2, 3, 4, 5], [10, 20, 30, 40, 50]]
>>> zcen(a)
array([[  5.5,  11. ,  16.5,  22. ,  27.5]])
>>> zcen(a, axis=1)
array([[  1.5,   2.5,   3.5,   4.5],
       [ 15. ,  25. ,  35. ,  45. ]])