NumPy:将数组的和减少n

时间:2018-08-16 15:50:24

标签: python arrays numpy

我正在寻找一种有效的方法来将NumPy数组a的总和减少给定的数字n,以使a中的任何值都不低于0,我可以为pvals中的不同值指定概率a。因此,如果我的函数的签名是:

> def removeRandom(a, n, pvals):
>    ...

然后应执行以下操作:

> a     = np.array([2,   3,   5,   10])
> pvals = np.array([0.1, 0.1, 0.4, 0.4]) 
> removeRandom(a, 5, pvals)
array([2, 2, 3, 8])

由于删除操作应该是随机的,因此下次输出可能会有所不同:

> removeRandom(a, 5, pvals)
array([1, 3, 4, 7])

我目前有一种方法可以执行删除步骤,然后检查a中的任何值是否都低于0,如果是,请重复此步骤,直到a中的值都没有低于0:

def removeRandom(a, n, pvals=None):
    if n < np.sum(a):
        # remove a total of n at random indexes, taking the pvals into account
        aranged = np.arange(a.size)
        randomIndexes = np.random.choice(aranged, n, p=pvals)
        np.subtract.at(a, randomIndexes, 1)

        while(a[a < 0].size > 0):   
            # what's the sum of all cells below 0?
            sumBelowZero = np.abs(np.sum(a[a < 0]))
            # set them to 0
            a[a < 0] = 0   

            # rinse and repeat the process
            randomIndexes = np.random.choice(aranged, n, p=pvals)
            np.subtract.at(a, randomIndexes, 1)
        return a
    else:
        return np.zeros_like(a)

该循环显然不是很优雅,而且如果函数至少将一个值降到0以下,则该函数有可能陷入该循环。随着n接近{ {1}}。

posted here是解决此问题的一种非常优雅的方法,但它不允许设置概率:

np.sum(a)

由于这里也使用def removeRandom(a, n): c = np.cumsum(np.r_[0, a]) if n < c[-1]: r = np.random.choice(np.arange(c[-1]) + 1, n, replace = False) d = np.sum(r[:,None] <= c[None,:], axis=0) return np.diff(c-d) else: return np.zeros_like(a) 并接受概率,因此我一直在寻找一种利用该方法的方法(显然没有成功)–可以做到吗?

当然,我也希望有其他解决方案。

1 个答案:

答案 0 :(得分:2)

这让我有些头疼,想把我的头缠起来,但是我想我理解你的问题。下面的方法从数组中的随机元素中删除总和。

def remove_random(array, total, probs=None):
    if total >= np.sum(array):
        return np.zeros_like(array)

    if total < 0:
        raise ValueError("Cannot remove non-positive amount!")

    to_remove = total

    while to_remove != 0:
        idx = np.random.choice(range(len(array)), p=probs)

        removeable = min(array[idx], to_remove)

        array[idx] = array[idx] - removeable
        to_remove = to_remove - removeable

    return array

输出(例如)

>>>a = np.array([2, 3, 5, 10])
>>>pvals = np.array([0.1, 0.1, 0.4, 0.4])
>>>n = 10

>>>print(remove_random(a, n, pvals))

<<<[2 3 5 0]

total接近数组的总和时,它将放慢速度(许多值最终为零),但是至少该方法不再卡住了。可以通过例如调用np.random.choice时仅采用非零元素并将其相关概率标准化。