我正在尝试以给定的概率(例如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。 但是,在上面的示例中情况并非如此。
答案 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