有效地在numpy数组中查找具有特定条件的行

时间:2019-06-08 21:29:13

标签: python arrays performance numpy numpy-ndarray

我有两个numpy数组2D。我想做的是在np_weight中找到np_sentence的特定行。

例如:

#rows are features, columns are clusters or whatever
np_weight = np.random.uniform(1.0,10.0,size=(7,4))
print(np_weight)

[[9.96859395 8.65543961 6.07429382 4.58735497]
 [3.21776471 8.33560037 2.11424961 8.89739975]
 [9.74560314 5.94640798 6.10318198 7.33056421]
 [6.60986206 2.36877835 3.06143215 7.82384351]
 [9.49702267 9.98664568 3.89140374 5.42108704]
 [1.93551346 8.45768507 8.60233715 8.09610975]
 [5.21892795 4.18786508 5.82665674 8.28397111]]

#rows are sentence index, columns are words on that sentence
np_sentence = np.random.randint(0.0,7.0,size=(5,3))
print(np_sentence)

[[2 5 1]
 [1 6 4]
 [0 0 0]
 [2 3 6]
 [4 2 4]]

如果我在每一列上对np_weight进行排序,然后获得前5名,我将得到这一列 (这里我仅显示第一列)

temp_sorted_result=
[9.96859395 ] --->index=0
[9.74560314 ] --→ index=2
[9.49702267 ] --→ index=4
[6.60986206 ] --->index=3
[5.21892795 ] --->index=6

现在,我想在第二个numpy数组np_sentence中对这些索引进行两个搜索,以查看其中包含两个索引的行。

例如,基于此,它必须输出:1,3,4。这些是np_sentence的索引,其中包括temp_sorted_result中两个索引的组合。

例如,both 4 and 6中可用的temp_sorted_resultnp_sentencerow=1的同一行中,依此类推。

我需要对np_weight的每一列执行此操作。对于我来说,非常有效的代码非常重要,因为行数非常大

到目前为止,我只在第二个数组中搜索了一个项目,而这并不是我最终想要的:

一种方法可能是我为每一列形成所有组合,例如,对于temp_sorted_result上方显示的第一列,我形成

(0,2) (0,4)(0,3) (0,6)
(2,4) (2,3) (2,6)
(4,3)(4,6)
(3,6)

,然后检查np_sentence行中哪一个可用。基于我的np_sentence的{​​{1}}行索引,包含其中一些。

现在我的问题是,如何才能以最有效的方式实现这一目标?

请告诉我它是否不明显。

感谢您的帮助:)

1 个答案:

答案 0 :(得分:1)

这是一种方法:下面的函数f创建一个与weight形状相同的蒙版(加上False s的一个虚拟行),在每一列中标记前五个条目, True

然后它使用np_sentence索引到掩码中,并为每一列,行对计算True并与阈值2进行比较。

仅复杂:我们必须禁止np_sentence行中的重复值。为此,我们对行进行排序,然后将等于其左邻居的每个索引指向掩码中的虚拟行。

此函数返回一个掩码。脚本的最后一行演示了如何将掩码转换为索引。

import numpy as np

def f(a1, a2, n_top, n_hit):
    N,M = a1.shape
    mask = np.zeros((N+1,M), dtype=bool)
    np.greater_equal(
        a1,a1[a1.argpartition(N-n_top, axis=0)[N-n_top], np.arange(M)],
        out=mask[:N])
    a2 = np.sort(a2, axis=1)
    a2[:,1:][a2[:,1:]==a2[:,:-1]] = N
    return np.count_nonzero(mask[a2], axis=1) >= n_hit

a1 = np.matrix("""[[9.96859395 8.65543961 6.07429382 4.58735497]
 [3.21776471 8.33560037 2.11424961 8.89739975]
 [9.74560314 5.94640798 6.10318198 7.33056421]
 [6.60986206 2.36877835 3.06143215 7.82384351]
 [9.49702267 9.98664568 3.89140374 5.42108704]
 [1.93551346 8.45768507 8.60233715 8.09610975]
 [5.21892795 4.18786508 5.82665674 8.28397111]]"""[2:-2].replace("]\n [",";")).A

a2 = np.matrix("""[[2 5 1]
 [1 6 4]
 [0 0 0]
 [2 3 6]
 [4 2 4]]"""[2:-2].replace("]\n [",";")).A

print(f(a1,a2,5,2))

from itertools import groupby
from operator import itemgetter

print([[*map(itemgetter(1),grp)] for k,grp in groupby(np.argwhere(f(a1,a2,5,2).T),itemgetter(0))])

输出:

[[False  True  True  True]
 [ True  True  True  True]
 [False False False False]
 [ True False  True  True]
 [ True  True  True False]]
[[1, 3, 4], [0, 1, 4], [0, 1, 3, 4], [0, 1, 3]]