一尘不染

Python-在numpy数组中查找多个值的行索引

python

我有一个数组X

X = np.array([[4,  2],
              [9,  3],
              [8,  5],
              [3,  3],
              [5,  6]])

我希望在此数组中找到多个值的行的索引:

searched_values = np.array([[4, 2],
                            [3, 3],
                            [5, 6]])

对于此示例,我想要一个类似的结果:

[0,3,4]

我有一个执行此操作的代码,但我认为它过于复杂:

X = np.array([[4,  2],
              [9,  3],
              [8,  5],
              [3,  3],
              [5,  6]])

searched_values = np.array([[4, 2],
                            [3, 3],
                            [5, 6]])

result = []

for s in searched_values:
    idx = np.argwhere([np.all((X-s)==0, axis=1)])[0][1]
    result.append(idx)

print(result)

我找到了类似问题的答案,但仅适用于一维数组。

有没有一种方法可以更简单地完成我想要的工作?


阅读 1309

收藏
2020-02-14

共1个答案

一尘不染

方法1

一种方法是NumPy broadcasting像这样

np.where((X==searched_values[:,None]).all(-1))[1]

方法#2

一种内存有效的方法是将每一行转换为等效的线性索引,然后使用np.in1d,例如,

dims = X.max(0)+1
out = np.where(np.in1d(np.ravel_multi_index(X.T,dims),\
                    np.ravel_multi_index(searched_values.T,dims)))[0]

方法3

使用np.searchsorted并具有转换为线性索引等效项的相同原理的另一种内存有效方法将是这样的-

dims = X.max(0)+1
X1D = np.ravel_multi_index(X.T,dims)
searched_valuesID = np.ravel_multi_index(searched_values.T,dims)
sidx = X1D.argsort()
out = sidx[np.searchsorted(X1D,searched_valuesID,sorter=sidx)]

请注意,此np.searchsorted方法假定searched_valuesin 中的每一行都有一个匹配项X。

np.ravel_multi_index工作如何?

此函数为我们提供了线性索引当量数。它接受,设置为列的2D数组n-dimensional indices和该n维网格本身的形状,这些索引将映射到该n维网格上并计算等效的线性索引。

让我们使用针对当前问题的输入。以输入为例,X并注意输入的第一行。由于我们正在尝试将的每一行X转换为其等效的线性索引,并且由于np.ravel_multi_index将每一列都假定为一个索引元组,因此我们需要X在转入函数之前进行转置。由于X在这种情况下每行元素的数量为2,因此要映射到的n维网格将为2D。每行中有3个元素X,它本来是3D用于映射的网格,依此类推。

要查看此功能将如何计算线性指标,考虑的第一行X

In [77]: X
Out[77]: 
array([[4, 2],
       [9, 3],
       [8, 5],
       [3, 3],
       [5, 6]])

我们将n维网格的形状设为dims

In [78]: dims
Out[78]: array([10,  7])

让我们创建一个二维网格,以查看该映射如何工作以及如何使用np.ravel_multi_index 计算线性索引

In [79]: out = np.zeros(dims,dtype=int)

In [80]: out
Out[80]: 
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])

让我们从设置第一个索引元组X,即从X网格开始的第一行-

In [81]: out[4,2] = 1

In [82]: out
Out[82]: 
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])

现在,要查看刚设置的元素的线性索引等效项,我们将其展平并用于np.where检测1。

In [83]: np.where(out.ravel())[0]
Out[83]: array([30])

如果考虑行优先排序,也可以计算得出。

让我们使用np.ravel_multi_index并验证这些线性指标-

In [84]: np.ravel_multi_index(X.T,dims)
Out[84]: array([30, 66, 61, 24, 41])

因此,我们将具有对应于from中每个索引元组X(即from中的每一行)的线性索引X。

选择尺寸np.ravel_multi_index以形成唯一的线性索引

现在,将每行X作为n维网格的索引元组并将每个这样的元组转换为标量的想法是要具有与唯一元组相对应的唯一标量,即中的唯一行X。

让我们再来看一看X

In [77]: X
Out[77]: 
array([[4, 2],
       [9, 3],
       [8, 5],
       [3, 3],
       [5, 6]])

现在,如前一节所述,我们将每一行都视为索引元组。在每个这样的索引元组中,第一个元素将代表n-dim网格的第一个轴,第二个元素将是网格的第二个轴,依此类推,直到中的每一行的最后一个元素X。本质上,每一列将代表网格的一个维度或轴。如果我们要将所有元素映射X到同一n-dim网格,则需要考虑这样一个建议的n-dim网格的每个轴的最大拉伸。假设我们在中处理正数X,则这样的延展将是X+ 1 中每一列的最大值。这+ 1是因为Python遵循0-based索引。因此,例如,X[1,0] == 9将映射到第十行拟议的网格。同样,X[4,1] == 6将转到7th该网格的列。

因此,对于我们的示例案例,我们有-

In [7]: dims = X.max(axis=0) + 1 # Or simply X.max(0) + 1

In [8]: dims
Out[8]: array([10,  7])

因此,(10,7)对于样本盒,我们将需要至少一个形状为的网格。沿尺寸的更多长度不会受到损害,并且也会为我们提供独特的线性指标。

结束语:这里要注意的一件重要事情是,如果我们有负数X,则需要在每列中添加适当的偏移量,X以使使用索引的那些元组成为正数np.ravel_multi_index

2020-02-14