如何以numpy为单位高效地对卷进行采样?

如何以numpy为单位高效地对卷进行采样?,numpy,scipy,Numpy,Scipy,我有一个三维布尔数组。我想从那些具有True值(如果有)的元素中选择一个随机元素。选择任何True元素的概率应相同。我需要所选元素的坐标 有效但不是特别快的方法: 随机选取元素并检查它们是否为真 形成所有真元素的索引列表(例如使用numpy.nonzero),然后从中随机选取 阵列通常是大小为256x256x256的立方体。真正的要素大约占总数的1%到10%。我不确定你的方法是否能在主要方面得到改进。无论如何,这里有一个flatnonzero解决方案和一个用于比较的试错方案: import

我有一个三维布尔数组。我想从那些具有
True
值(如果有)的元素中选择一个随机元素。选择任何
True
元素的概率应相同。我需要所选元素的坐标

有效但不是特别快的方法:

  • 随机选取元素并检查它们是否为真

  • 形成所有真元素的索引列表(例如使用
    numpy.nonzero
    ),然后从中随机选取


阵列通常是大小为256x256x256的立方体。真正的要素大约占总数的1%到10%。

我不确定你的方法是否能在主要方面得到改进。无论如何,这里有一个
flatnonzero
解决方案和一个用于比较的试错方案:

import numpy as np
from timeit import timeit

def pick_true(data, n):
    nz = np.flatnonzero(data)
    return np.unravel_index(np.random.choice(nz, n), data.shape)


def pick_true_2(data, n, p):
    pick = np.random.randint(0, data.size, (int(round(n/p)),))
    return np.unravel_index(pick[data.ravel()[pick]], data.shape)

data = np.random.random((256,256,256)) < 0.01

print(pick_true(data, 10), data[pick_true(data, 10)])

print('indexing small {:6.4f} secs'.format(timeit(lambda: pick_true(data, 100), number=10)/10))
print('indexing large {:6.4f} secs'.format(timeit(lambda: pick_true(data, 10000), number=10)/10))


print(pick_true_2(data, 10, 0.01), data[pick_true_2(data, 10, 0.01)])

print('non-indexing small {:6.4f} secs'.format(timeit(lambda: pick_true_2(data, 100, 0.01), number=10)/10))
print('non-indexing large {:6.4f} secs'.format(timeit(lambda: pick_true_2(data, 10000, 0.01), number=10)/10))

嗯,这两颗子弹不是唯一可能产生结果的方法吗?@Paul可能。。。索引或非索引似乎是两种主要的方法,但非索引可以矢量化。我认为您应该创建
True
列表,您只随机采样一次并将其交给函数,而不是每次调用
pick\u True
。此外,
pick\u true\u 2
并不总是提供
n
值,因此时间比较是不公平的。在我看来,您应该使其递归或使用
while
循环,直到找到
True
。@StefanS“我认为您应该创建True的列表…只创建一次”这就是
n
参数的用途。“pick_true_2并不总是提供n个值”,事实上,它几乎从未提供过。但是,在舍入之前,预期值为
n
。“使其递归或使用while循环,直到找到一个True”是不可取的,因为在几乎任何情况下,仅仅在向量化代码中绘制更多并丢弃多余的命中数都会显著加快。对于中等大小的
n
来说,一个小的安全裕度就足以保证足够高的命中率。我承认这个玩具示例的第一点(没有人编写两行函数只调用一次),但是“保证足够高的命中率”听起来像是一个等待发生的bug。不过,关于“丢弃多余部分”的说法可能是对的,因此无论是否真的有足够的内容,您只需要在函数周围添加一个包装器(或在之后进行检查)。不过,你的时间测试仍然不够,所以我的原意是。@StefanS整个练习的重点不是写一个交钥匙解决方案,而是演示并粗略量化主要的权衡,“创建指数是否值得?哪种策略的快速实施是什么?”显然,在生产代码中会包含各种检查,但在原则证明代码中不会,因为这只会分散对重要内容的注意力。“不管你是否真的有足够的钱”你不会真的期望任何一个有点常识的人忽略这种琐碎的支票吧?
(array([  8, 164, 247, 160, 154, 147, 146,  73,  89,   1]),
array([ 89,   0,   7, 217,  46,  45, 139, 205, 163,  92]),
array([ 70, 129,  92,   7,  14, 155, 148,  51, 146, 176]))
[ True  True  True  True  True  True  True  True  True  True]
indexing small 0.0072 secs
indexing large 0.0090 secs
(array([ 29, 113,   7,  18, 159, 203,  97,  45]),
array([227, 251,   8, 137,  61, 226, 170,  17]),
array([249,  28, 160,  99,  99, 191, 174, 234]))     
[ True  True  True  True  True  True  True  True]
non-indexing small 0.0002 secs
non-indexing large 0.0206 secs