将数组舍入到另一个数组中给出的值

时间:2015-01-08 13:32:25

标签: python arrays numpy rounding

说我有一个数组:

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方式吗?

5 个答案:

答案 0 :(得分:5)

一种选择是:

>>> x = np.subtract.outer(values, rounds)
>>> y = np.argmin(abs(x), axis=1)

然后roundedresidues分别为:

>>> 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])

基本上xvalues中每个值减去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)