[英]Finding Intersection Between a Matrix and a Vector, by Row
考慮以下:
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'實際上是≈1000000x 2200,我有6700個向量來比較。 我在這里的解決方案太慢而無法嘗試。
我怎樣才能改善我正在做的事情?
值得注意的是,matr里面的值來自一組~30000的值,而且我有完整的值。 我已經考慮過這樣的解決方案,我針對每個向量對這些30000值進行了一個dict,並且在按行求和之前使用dict在整個矩陣中轉換為True / False。 我不確定這是否會有所幫助。
對於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)])
您可以使用set intersection來加快速度。 這是一個比較:
您目前的列表理解解決方案:
%%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)
這是一個簡單易讀的解決方案,使用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]])
這表明為什么沿行的求和產生所需的輸出。
我們來看看當前算法的速度。 根據python wiki,檢查項目是否在像y in vec
一樣的數組是O(n),意味着最壞的情況,它必須遍歷vec
每個元素。 由於您正在檢查矩陣的每個元素,因此您的總操作數為numRows * numCols * vecLen
,即O(n^3)
。
更快的方法是為vec
構建字典以優化查找,因為字典是O(1)
而不是O(n)
,這意味着無論vec有多長,它們都可以在1次操作中進行檢查:
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]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.