【发布时间】:2019-09-25 23:09:33
【问题描述】:
我有一个非常简单的操作,涉及两个不太大的数组:
- 对于第一个(更大的)数组中的每个元素,位于位置
i - 查找它是否存在于第二个(较小的)数组中
- 如果是,则在第二个数组中找到它的索引:
j - 将取自第三个数组(与第一个数组长度相同)的浮点数存储在位置
i,第四个数组的位置j(与第二个数组长度相同)
下面的 for 块可以工作,但对于不太大的数组 (>10000) 会变得非常慢。
这个实现可以更快吗?
import numpy as np
import random
##############################################
# Generate some random data.
#'Nb' is always smaller then 'Na
Na, Nb = 50000, 40000
# List of IDs (could be any string, I use integers here for simplicity)
ids_a = random.sample(range(1, Na * 10), Na)
ids_a = [str(_) for _ in ids_a]
random.shuffle(ids_a)
# Some floats associated to these IDs
vals_in_a = np.random.uniform(0., 1., Na)
# Smaller list of repeated IDs from 'ids_a'
ids_b = random.sample(ids_a, Nb)
# Array to be filled
vals_in_b = np.zeros(Nb)
##############################################
# This block needs to be *a lot* more efficient
#
# For each string in 'ids_a'
for i, id_a in enumerate(ids_a):
# if it exists in 'ids_b'
if id_a in ids_b:
# find where in 'ids_b' this element is located
j = ids_b.index(id_a)
# store in that position the value taken from 'ids_a'
vals_in_b[j] = vals_in_a[i]
【问题讨论】:
-
是的,这是一个多项式时间算法。当你增加输入的大小时,它会变得越来越慢。使用更好的算法,可能使用支持恒定时间(而不是线性时间)成员资格测试的不同数据结构。
-
关于更好的算法胡安有什么建议吗?
-
创建
ids_b中项目的字典到它们的索引,然后只使用该字典而不是检查数组上的成员资格。 -
您可以 1) 连接 ids_a 和 ids_b,2) 使用关键字 return_inverse=True 应用 np.unique,3) 将逆拆分为 inv_a 和 inv_b,4) 映射值以匹配唯一性的顺序: vals[inv_a] = vals_in_a,和 5) 使用 inv_b 选择正确的值:result = vals[inv_b]
-
明天早上我会尝试这两种方法,看看结果如何。谢谢。
标签: python arrays performance numpy