我有一个表格数组:
x = np.array([ 1230., 1230., 1227., 1235., 1217., 1153., 1170.])
我想生成另一个数组,其中值是我原始数组中每对值的平均值:
xm = np.array([ 1230., 1228.5, 1231., 1226., 1185., 1161.5])
有人知道在不使用循环的情况下最简单快捷的方法吗?
答案 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₁
,第一和第二个元素。
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. ]])