说我有一个数组:
values = np.array([1.1,2.2,3.3,4.4,2.1,8.4])
我想将这些值舍入到任意数组的成员,例如:
rounds = np.array([1.,3.5,5.1,6.7,9.2])
理想情况下返回一个舍入数字数组和一个残差数组:
rounded = np.array([1.,1.,3.5,5.1,1.,9.2])
residues = np.array([-0.1,-1.2,0.2,0.7,-1.1,0.6])
有一种好的pythonic方式吗?
答案 0 :(得分:5)
一种选择是:
>>> x = np.subtract.outer(values, rounds)
>>> y = np.argmin(abs(x), axis=1)
然后rounded
和residues
分别为:
>>> rounds[y]
array([ 1. , 1. , 3.5, 5.1, 1. , 9.2])
>>> rounds[y] - values
array([-0.1, -1.2, 0.2, 0.7, -1.1, 0.8])
基本上x
是values
中每个值减去rounds
中每个值的二维数组。 y
是每行x
的最小绝对值索引的一维数组。然后,此y
用于索引rounds
。
我应该通过注意如果len(values) * len(rounds)
很大(例如开始超过10e8
)来回答这个问题,那么内存使用可能会开始受到关注。在这种情况下,您可以考虑迭代地构建y
,以避免必须将大块内存分配给x
。
答案 1 :(得分:2)
由于rounds
数组中的项目已排序(或未对其进行排序),我们可以O(n logn)
使用numpy.searchsorted
执行此操作:
from functools import partial
def closest(rounds, x):
ind = np.searchsorted(rounds, x, side='right')
length = len(rounds)
if ind in (0, length) :
return rounds[ind]
else:
left, right = rounds[ind-1], rounds[ind]
val = min((left, right), key=lambda y:abs(x-y))
return val
f = partial(closest, rounds)
rounded = np.apply_along_axis(f, 1, values[:,None])[:,0]
residues = rounded - values
print repr(rounded)
print repr(residues)
<强>输出:强>
array([ 1. , 1. , 3.5, 5.1, 1. , 9.2])
array([-0.1, -1.2, 0.2, 0.7, -1.1, 0.8])
答案 2 :(得分:2)
与Ashwini Chaudhary的答案同时复杂,但完全矢量化:
def round_to(rounds, values):
# The main speed is in this line
I = np.searchsorted(rounds, values)
# Pad so that we can index easier
rounds_p = np.pad(rounds, 1, mode='edge')
# We have to decide between I and I+1
rounded = np.vstack([rounds_p[I], rounds_p[I+1]])
residues = rounded - values
J = np.argmin(np.abs(residues), axis=0)
K = np.arange(len(values))
return rounded[J,K], residues[J,K]
答案 3 :(得分:1)
在轮次中找到最接近的x数:
def findClosest(x,rounds):
return rounds[np.argmin(np.absolute(rounds-x))]
循环遍历所有值:
rounded = [findClosest(x,rounds) for x in values]
residues = values - rounded
这是一种简单的方法,但您可以更有效地使用您的rounds数组进行排序。
def findClosest(x,rounds):
for n in range(len(rounds)):
if x > rounds[n]:
if n == 0:
return rounds[n]
elif rounds[n]-x > x-rounds[n-1]:
return rounds[n-1]
else:
return rounds[n]
return rounds[-1]
这可能是,但不一定比argmin方法更快,因为你浪费了python for循环的时间,但是你不必检查整个数组。
答案 4 :(得分:0)
所选答案已经很棒了。对于那些不一定习惯于更复杂的列表理解的人来说,这可能看起来很复杂,但如果你熟悉它,它实际上很清楚(IMO)。
(有趣的是,这种情况比选择的答案运行得更快。为什么numPy版本比这慢?嗯......)
values = np.array([1.1,2.2,3.3,4.4,2.1,8.4])
rounds = np.array([1.,3.5,5.1,6.7,9.2])
rounded, residues = zip(*[
[
(rounds[cIndex]),
(dists[cIndex])
]
for v in values
for dists in [[r-v for r in rounds]]
for absDists in [[abs(d) for d in dists]]
for cIndex in [absDists.index(min(absDists))]
])
print np.array(rounded)
print np.array(residues)