我有一个由 n 个 1x3 数组组成的 numpy 数组 A,其中 n 是 1x3 数组中元素可能组合的总数,其中每个元素的范围从 0 到 50。也就是说,
A = [[0,0,0],[0,0,1]...[0,1,0]...[50,50,50]]
和
len(A) = 50*50*50 = 125000
我有一个由 m 个 1x3 数组组成的 numpy 数组 B,其中 m = 1000 万,数组可以具有属于 A 所描述的集合的值。
我想统计每个组合在B中出现了多少次,即[0,0,0]
在B中出现了多少次,[0出现了多少次,0,1]
出现...[50,50,50]
出现了多少次。到目前为止,我有以下内容:
for i in range(len(A)):
for j in range(len(B)):
if np.array_equal(A[i], B[j]):
y[i] += 1
其中 y 跟踪第 i 个数组出现的次数。所以,y[0]
是[0,0,0]
在B中出现了多少次,y[1]
是多少次[0,0,1]
出现了...y[125000]
是[50,50,50]
出现了多少次,等等.
问题是这需要很长时间。它必须检查 1000 万个条目,125000 次。有没有更快更有效的方法来做到这一点?
最佳答案
这是一个快速的方法。它在 range(50)^3
内处理 10
百万元组,只需几分之一秒,比下一个最好的快大约 100
倍解决方案(@Primusa 的):
它利用了这样的元组和数字 0 - 50^3 - 1
之间存在直接转换这一事实。 (映射恰好与 A
的行和行号之间的映射相同。)函数 np.ravel_multi_index
和 np.unravel_index
实现这个翻译和它的逆。
一旦 B
被转换为数字,就可以使用 np.bincount
非常有效地确定它们的频率。下面我 reshape 结果以获得 50x50x50
直方图,但这只是个人喜好问题,可以忽略不计。 (我冒昧地只使用了 0
到 49
的数字,所以 len(A)
变成了 125000
) :
>>> B = np.random.randint(0, 50, (10000000, 3))
>>> Br = np.ravel_multi_index(B.T, (50, 50, 50))
>>> result = np.bincount(Br, minlength=125000).reshape(50, 50, 50)
让我们看一个更小的例子来演示:
>>> B = np.random.randint(0, 3, (10, 3))
>>> Br = np.ravel_multi_index(B.T, (3, 3, 3))
>>> result = np.bincount(Br, minlength=27).reshape(3, 3, 3)
>>>
>>> B
array([[1, 1, 2],
[2, 1, 2],
[2, 0, 0],
[2, 1, 0],
[2, 0, 2],
[0, 0, 2],
[0, 0, 2],
[0, 2, 2],
[2, 0, 0],
[0, 2, 0]])
>>> result
array([[[0, 0, 2],
[0, 0, 0],
[1, 0, 1]],
[[0, 0, 0],
[0, 0, 1],
[0, 0, 0]],
[[2, 0, 1],
[1, 0, 1],
[0, 0, 0]]])
例如要查询 [2,1,0]
在 B 中有多少次
>>> result[2,1,0]
1
如上所述:在索引到您的 A
和 A
的实际行(这是我的结果
中的索引)之间进行转换, np.ravel_multi_index
和 np.unravel_index
都可以使用。或者您可以省略最后一次整形(即使用 result = np.bincount(Br, minlength=125000)
;然后计数的索引与 A
完全相同。
关于python - 比较大型数组集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49722046/