我想以一定的概率翻转数组中的数字

时间:2020-09-24 16:33:28

标签: python numpy

我正在尝试以给定的概率(例如p = 0.2。)从某个numpy数组中翻转数字(0 / 1s)。

我已经想到了以下解决方案(使用np.logical_not和使用p创建的数字掩码),但是并不能产生预期的结果:

>> arr = np.array([[0,1,1,0,],[1,1,0,1],[0,0,0,0],[1,1,1,1]],dtype=bool)

>> arr

array([[False,  True,  True, False],
       [ True,  True, False,  True],
       [False, False, False, False],
       [ True,  True,  True,  True]])

>> flip_mask = np.array(np.random.choice([0,1], p=[0.8, 0.2], size = arr.shape),
                     dtype=bool)
>> flip_mask

array([[False,  True, False,  True],
       [False, False, False, False],
       [False, False, False, False],
       [False, False,  True, False]])

>> np.logical_not(arr, where=flip_mask)

array([[ True, False,  True,  True],
       [ True,  True,  True,  True],
       [False, False, False, False],
       [False, False, False,  True]])

根据掩码的定义,我的理解是,第一个元素(0,0)应该保持为(False),因为掩码在0,0中的值为False。 但是,在上面的示例中情况并非如此。

3 个答案:

答案 0 :(得分:1)

如果您阅读ufunc where关键字的文档,则会显示:

1.7版中的新功能。

接受一个布尔数组,该布尔数组与操作数一起广播。值为True表示要在该位置计算ufunc,值为False表示将值保留在输出中。此参数不能用于通用ufunc,因为它们采用非标量输入。 请注意,如果创建了未初始化的返回数组,则False值会将这些值保留为未初始化

强调不是我的。

当新数组分配到具有随机垃圾的内存块中时,您会看到这种效果。为了缓解这种情况,您需要使用正确的值初始化输出缓冲区。这里有两种可能性:

就地:

np.logical_not(arr, where=flip_mask, out=arr)

这只是直接翻转arr中的值,而其他所有内容都保持不变。

使用布尔索引可以执行相同的操作,但是效率较低,因为您两次应用了索引:

arr[flip_mask] = ~arr[flip_mask]

另一种方法是应用logical_xor^)而不是logical_not

arr ^= flip_mask

OR

np.logical_xor(arr, flip_mask, out=arr)

XOR解决方案可能是最有效的,因为它们不将掩码转换为索引,只需要在数组上进行一次非常快速的传递。

新数组:

np.logical_not(arr, where=flip_mask, out=arr.copy())

此版本复制原始阵列。如果翻转的可能性低,这是一个不错的选择。

np.where(flip_mask, ~arr, arr)

使用where效率不高,因为它会为整个数组计算logical_not

您也可以为此选项使用索引:

out = np.empty_like(arr)
out[~flip_mask] = arr[~flip_mask]
out[flip_mask] = ~arr[flip_mask]

当然还有XOR:

out = arr ^ flip_mask

要了解XOR为什么与翻转蒙版相同,请查看以下真值表:

  arr | flip | out
------+------+------
   T  |   T  |   F
   F  |   T  |   T
   T  |   F  |   T
   F  |   F  |   F

答案 1 :(得分:0)

使用以下内容:

>>> arr

array([[False,  True,  True, False],
       [ True,  True, False,  True],
       [False, False, False, False],
       [ True,  True,  True,  True]])

>>> flip_mask = np.array(np.random.choice([0,1], p=[0.8, 0.2], size = arr.shape),
                     dtype=bool)
>>> flip_mask
array([[False, False, False, False],
       [False, False,  True, False],
       [ True,  True,  True,  True],
       [False, False, False, False]])
>>> np.where(flip_mask, np.logical_not(arr), arr)
array([[False,  True,  True, False],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]])

答案 2 :(得分:0)

@MadPhysicist很好地解释了为什么代码不起作用。

由于您以0/1开始,因此翻转它们的一种方法是,以定义的概率减去0/1的随机数组,然后取绝对值:

JOIN

和原始数组:

RIGHT JOIN