簡體   English   中英

按行查找矩陣和矢量之間的交點

[英]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。 我不確定這是否會有所幫助。

對於matrvec作為數組,這里有一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM