【问题标题】:Can I make random mask with Numpy?我可以用 Numpy 制作随机掩码吗?
【发布时间】:2018-06-05 01:58:31
【问题描述】:

我正在使用 Python 进行图像处理。

我正在尝试从图像中随机提取一些像素。

Numpy不能做随机掩码吗?

我现在想的是把10​​000个线阵中的1000个元素设为True,其他的都设为False,有没有可能实现这个?

另外,如果不可能,有没有其他方法可以制作随机面具? 谢谢。

【问题讨论】:

标签: python numpy random boolean


【解决方案1】:

另一种选择:

import numpy as np

size = 1000
zero_density = 0.1   # 0.0 => all false / unset
mask = np.random.random(size=size) < zero_density

【讨论】:

    【解决方案2】:

    一种常见的解决方案是创建一个随机整数索引数组,这可以通过 numpy 的随机 choice 有效地完成。

    使用此设置:

    n_dim = 10_000  # size of the original array
    n = 100         # size of the random mask
    rng = np.random.default_rng(123)
    

    要创建随机索引数组,我们可以使用 numpy 的 choice 传递 数组大小 作为第一个参数:

    In [5]: %%timeit  
       ...: m = rng.choice(n_dim, replace=False, size=n) 
       ...:  
       ...:                                                                                                                                  
    21.9 µs ± 161 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    作为比较,其他答案中提到的布尔数组方法(需要对 0 和 1 的数组进行混洗)相当慢(在本例中慢了 10 倍):

    In [7]: %%timeit 
       ...: m = np.hstack([np.ones(n, dtype=bool), np.zeros(n_dim - n, dtype=bool)]) 
       ...: rng.shuffle(m) 
       ...:  
       ...:                                                                                                                                  
    261 µs ± 604 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    注意:整数索引在稀疏情况下效果最佳,即从原始数组中选择一小部分样本时。在这种情况下,整数索引的 RAM 使用率将远低于布尔掩码。当样本的比例超过原始数组的 10..20% 时,布尔掩码方法会更有效。

    NOTE2 整数索引将以随机顺序返回样本。为了在保持顺序的同时对数组进行随机采样,您需要对索引进行排序。布尔掩码自然会返回排序后的样本。

    总而言之,如果您正在执行稀疏采样并且您不关心采样项目的顺序,那么此处显示的整数索引可能会优于其他方法。

    【讨论】:

    • 这仅在您不关心在使用掩码 m 进行索引后保持元素的原始顺序时才有效。如果您确实关心(可能是 OP 的情况,因为它们正在从图像中提取像素),您必须在使用 m.sort() 创建掩码后对其进行排序。它的整体复杂性比布尔掩码方法更差——即,它对于更大的掩码尺寸表现更差。见this benchmark
    • 亲爱的 Anakhand,这是一个公平的观点。 OP问题中没有提到样本分类的要求。整数索引方法在稀疏情况下效果更好,即当所选样本的一小部分是总样本的一小部分时。在这种情况下,它将比布尔掩码更高效(更少 RAM)和更快。当采样点的比例大于 ~1/4 时,我会使用布尔掩码,因为整数掩码在 RAM 方面的优势将消失。
    【解决方案3】:

    类似于 Nils Werner 的回答,但更直接:

    import numpy as np
    
    size = 10000
    num_true = 1000
    
    mask = np.concatenate([np.ones(num_true, dtype=bool), np.zeros(size - num_true, dtype=bool)])
    np.random.shuffle(mask)
    

    同样快;使用 IPython 的 %%timeit 魔法:

    %%timeit
    a = np.zeros(size, dtype=int)
    a[:num_ones] = 1
    np.random.shuffle(a)
    a = a.astype(bool)
    

    输出:217 µs ± 2.33 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

    %%timeit
    mask = np.concatenate([np.ones(num_true, dtype=bool), np.zeros(size - num_true, dtype=bool)])
    np.random.shuffle(mask)
    

    输出:201 µs ± 1.32 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

    【讨论】:

      【解决方案4】:

      创建一个包含False 值的数组,将第一个1000 元素设置为True

      a = np.full(10000, False)
      a[:1000] = True
      

      然后简单地打乱数组

      np.random.shuffle(a)
      

      对于一个稍微快一点的解决方案,您还可以创建一个整数零数组,将一些值设置为1,随机播放并将其转换为bool

      a = np.zeros(10000, dtype=int)
      a[:1000] = 1
      np.random.shuffle(a)
      a = a.astype(bool)
      

      在这两种情况下,您都会有一个数组a,其中在随机位置恰好有 1000 个 True 元素

      如果您希望从[True, False] 中单独挑选每个元素,您可以使用

      np.random.choice([True, False], size=10000, p=[0.1, 0.9])
      

      但请注意,您无法预测数组中 True 元素的数量。您只会知道平均而言您将拥有 1000 个。

      【讨论】:

      • 我喜欢这个解决方案。然而......只是一个想法。我们可以将 np.full(..) 更改为 np.zeros() 并将 a[:1000] 设置为 1。这应该会提高速度。最后也可以添加a.astype(bool)
      • 它们的速度与纯布尔数组在大多数情况下的速度差不多。
      • 啊,我看错时间了。 int 解决方案确实是最快的!会调整我的答案。
      • 也可以使用np.concat([np.ones(1000, dtype=bool), np.zeros(10000 - 1000, dtype=bool)]) 来保存一些行并转换为bool
      • np.random.choice([True, False], size=10000, p=[0.1, 0.9]) 比等效的 np.random.random_sample(10000) &lt; 0.9 慢大约 10 倍。
      【解决方案5】:
      In [7]: import numpy as np 
      
      In [8]: mask=np.array( [False]*10000)
      
      In [9]: inds=np.random.choice(np.arange(10000),size=1000)
      
      In [10]: mask[inds]=True
      

      现在你的面具的前 100 个元素是

      In [11]: print(mask[:100])
      [False False False False False  True False False False False False False
       False False False False False False False False False False  True False
       False False False False False False False  True  True False  True False
       False False False False False False False False False False  True False
       True False False False False False False False False False False False
       False False False False False False  True False False False False False
       False False  True False False False False False False False False False
       False False  True False False False False False False False False False
       False False False False]
      

      【讨论】:

        猜你喜欢
        • 2020-07-07
        • 2011-11-09
        • 2018-09-08
        • 2019-12-13
        • 1970-01-01
        • 2014-06-14
        • 1970-01-01
        • 2017-12-19
        • 1970-01-01
        相关资源
        最近更新 更多