我有一个非常大的 1D python 数组x
,其中有些重复的数字以及一些d
相同大小的数据。
x = np.array([48531, 62312, 23345, 62312, 1567, ..., 23345, 23345])
d = np.array([0 , 1 , 2 , 3 , 4 , ..., 99998, 99999])
在我的上下文中,“非常大”是指 10k...100k 条目。其中一些是重复的,因此唯一条目的数量约为 5k...15k。
我想将它们分组到垃圾箱中。这应该通过创建两个对象来完成。一个是矩阵缓冲区,b
数据项取自 d。另一个对象是v
每个缓冲区列引用的唯一 x 值向量。这是示例:
v = [48531, 62312, 23345, 1567, ...]
b = [[0 , 1 , 2 , 4 , ...]
[X , 3 , ....., ...., ...]
[ ...., ....., ....., ...., ...]
[X , X , 99998, X , ...]
[X , X , 99999, X , ...] ]
由于 x 中每个唯一数字的出现次数不同,缓冲区 b 中的一些值是无效的(由大写字母表示X
,即“不关心”)。
在 numpy 中很容易推导出 v:
v, n = np.unique(x, return_counts=True) # yay, just 5ms
我们甚至得到n
b 中每列中有效条目的数量。此外,(np.max(n), v.shape[0])
返回需要分配的矩阵 b 的形状。
但是如何有效地生成 b?一个 for 循环可能会有所帮助
b = np.zeros((np.max(n), v.shape[0]))
for i in range(v.shape[0]):
idx = np.flatnonzero(x == v[i])
b[0:n[i], i] = d[idx]
此循环遍历 b 的所有列,并idx
通过识别 的所有位置来提取索引x == v
。
但是我不喜欢这个解决方案,因为 for 循环相当慢(比唯一命令长约 50 倍)。我宁愿将操作矢量化。
因此,一种矢量化方法是创建一个索引矩阵,x == v
然后nonzero()
在其上沿列运行命令。但是,此矩阵需要 150k x 15k 范围内的内存,因此在 32 位系统上大约需要 8GB。
np.unique
对我来说, -操作甚至可以有效地返回倒排索引听起来很愚蠢,x = v[inv_indices]
但是没有办法为 v 中的每个 bin 获取 v-to-x 分配列表。当函数时,这应该几乎是免费的正在扫描 x。在实现方面,唯一的挑战是生成的索引矩阵的未知大小。
假设 np.unique-command 是用于分箱的方法,则另一种表述这个问题的方法:
给定三个数组x, v, inv_indices
中v
的唯一元素,x
是否x = v[inv_indices]
有一种有效的方法来生成索引向量v_to_x[i]
,all(v[i] == x[v_to_x[i]])
以便所有 bin i
?
我不应该花费比 np.unique-command 本身更多的时间。我很高兴为每个箱子中的物品数量提供一个上限(例如 50 个)。