繁体   English   中英

每对 numpy.array 的中点

[英]Middle point of each pair of an numpy.array

我有一个表单数组:

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

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

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

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

更短,更甜:

(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只是该值的一半。 这几乎总是可以通过将指数减一来完成,除了两种情况:

    • 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 + (ba)/2 error_mine = (ax) - (xb) error_theirs = (ay) - (yb) 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.46diff变体有 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的两个值的平均值。

简短而甜蜜:

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

也就是说,取x除最后一个元素之外的每个元素,并加上它与后续元素之间的差值的二分之一。

尝试这个:

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

这很容易,应该很快。

如果速度很重要,请按照 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
>>> 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. ])

现在你可以删除最后一个元素,如果你愿意

我最终在多维数组上大量使用此操作,因此我将发布我的解决方案(灵感来自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. ]])

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM