请考虑以下内容:
tmp1 = ['a', 'b', 'c', 'd', 'e']
tmp2 = ['f', 'g', 'h', 'b', 'd']
tmp3 = ['b', 'i', 'j', 'k', 'l']
matr = np.array([tmp1, tmp2, tmp3])
matr
产生矩阵:
array([['a', 'b', 'c', 'd', 'e'],
['f', 'g', 'h', 'b', 'd'],
['b', 'i', 'j', 'k', 'l']],
dtype='|S1')
现在,我想知道与向量相交的每一行的值总和。说,
vec = ['a', 'c', 'f', 'b']
[sum([y in vec for y in row]) for row in matr]
返回
[3, 2, 1]
这是所需的输出。问题是我的“ matr”实际上是≈1000000 x 2200,我有6700个向量要比较。我在这里找到的解决方案太慢了,无法尝试。
我该如何改善自己的工作?
值得注意的是,矩阵内部的值来自一组〜30000个值,而我有完整的值。我已经考虑过解决方案,在这些解决方案中,我针对每个向量对这30000个值进行了运算,并使用该字典在整个矩阵中将其转换为True / False,然后才按行求和。我不确定这是否有帮助。
答案 0 :(得分:2)
对于matr
和vec
作为数组,这里是np.searchsorted
-
def count_in_rowwise(matr,vec):
sidx = vec.argsort()
idx = np.searchsorted(vec,matr,sorter=sidx)
idx[idx==len(vec)] = 0
return (vec[sidx[idx]] == matr).sum(1)
vec
相对较小,我们可以对其进行预排序并使用,从而为我们提供了一种替代方法来计算行数,就像这样-
def count_in_rowwise_v2(matr,vec,assume_sorted=False):
if assume_sorted==1:
sorted_vec = vec
else:
sorted_vec = np.sort(vec)
idx = np.searchsorted(sorted_vec,matr)
idx[idx==len(sorted_vec)] = 0
return (sorted_vec[idx] == matr).sum(1)
上述解决方案适用于通用输入(数字或字符串相同)。为了解决特定的字符串情况,我们可以进一步优化它,方法是使用np.unique
将字符串转换为数字,然后重新使用count_in_rowwise/count_in_rowwise_v2
,这将为我们提供第二种方法->
u,ids = np.unique(matr, return_inverse=True)
out = count_in_rowwise(ids.reshape(matr.shape),ids[np.searchsorted(u,vec)])
答案 1 :(得分:2)
您可以使用设置相交来加快速度。比较一下:
您目前具有列表理解的解决方案:
%%timeit
print([sum([y in vec for y in row]) for row in matr])
#Output
[3,2,1]
20 µs ± 1.9 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
在列表理解中设置交集的建议解决方案:
%%timeit
print([len(set(row).intersection(vec)) for row in matr])
#Output:
[3,2,1]
17.8 µs ± 1.46 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
如果vec
也是一个集合,我们将获得更高的效率:
%%timeit
vec = {'a', 'c', 'f', 'b'}
print([len(set(row).intersection(vec)) for row in matr])
#Output:
[3, 2, 1]
16.6 µs ± 1.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
答案 2 :(得分:1)
这是一个np.isin()
(docs)的简单可读解决方案:
np.sum(np.isin(matr, vec), axis=1)
作为奖励,如果要获取向量中矩阵的哪些元素,则可以不加和使用np.isin()
:
>>> np.isin(matr, vec)
array([[ True, True, True, False, False],
[ True, False, False, True, False],
[ True, False, False, False, False]])
这说明了为什么沿行求和会产生所需的输出。
答案 3 :(得分:1)
让我们看一下当前算法的速度。根据python Wiki的说法,检查某项是否位于y in vec
之类的数组中是否为O(n),这意味着最坏的情况是,它必须遍历vec
中的每个元素。由于您要检查矩阵的每个元素,因此操作总数为numRows * numCols * vecLen
,即O(n^3)
。
一种更快的方法是为vec
构造一个字典来优化查找,因为字典是O(1)
而不是O(n)
,这意味着它们可以在1个操作中完成检查,而无需不管vec多久:
vecDict = dict([(x, 1) for x in vec])
因此,您的新时间复杂度为(numRows * numCols) + vecLen
,也就是O(n^2)
,我认为它的获取速度最快。
[sum([y in vecDict for y in row]) for row in matr]