Python 查找numpy数组中多个值的行索引
我有一个数组X:Python 查找numpy数组中多个值的行索引,python,arrays,numpy,Python,Arrays,Numpy,我有一个数组X: X = np.array([[4, 2], [9, 3], [8, 5], [3, 3], [5, 6]]) 我希望找到这个数组中多个值行的索引: searched_values = np.array([[4, 2], [3, 3], [5, 6
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)
我发现了一个类似的问题,但它只适用于一维数组
有没有一种更简单的方法来做我想做的事情?方法#1
一种方法是像这样使用-
np.where((X==searched_values[:,None]).all(-1))[1]
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]
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)]
方法#2
一种节省内存的方法是将每一行转换为等价的线性索引,然后像这样使用-
np.where((X==searched_values[:,None]).all(-1))[1]
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]
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)]
方法#3
另一种高效内存的方法是使用相同的转换为线性索引等价物的原理-
np.where((X==searched_values[:,None]).all(-1))[1]
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]
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
方法假定X
中的searched\u值中的每一行都有匹配项
它是如何工作的?
此函数为我们提供了线性索引等价数。它接受一个2D
数组,设置为列和n维网格本身的形状,这些索引将映射到该网格上,并计算等效的线性索引
让我们利用手头问题的输入。以输入X
为例,记下它的第一行。因为,我们试图将X
的每一行转换为它的线性索引等价物,并且因为np.ravel\u multi\u index
假设每一列都是一个索引元组,所以在输入函数之前,我们需要对X
进行转置。由于在这种情况下,X
中每行元素的数量是2
,因此要映射到的n维网格将是2D
。在X
中,每行有3个元素,它应该是3D
网格,用于映射等等
查看此函数如何计算线性索引,考虑<代码> x < /代码> -< /p>的第一行。
In [77]: X
Out[77]:
array([[4, 2],
[9, 3],
[8, 5],
[3, 3],
[5, 6]])
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\u multi\u 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\u multi\u index
并验证这些线性索引-
In [84]: np.ravel_multi_index(X.T,dims)
Out[84]: array([30, 66, 61, 24, 41])
因此,我们将具有与X
中的每个索引元组对应的线性索引,即X
中的每一行
为np.ravel\u多重索引选择维度
以形成唯一的线性索引
现在,将X
的每一行视为一个n维网格的索引元组,并将每一个这样的元组转换为一个标量,其背后的思想是具有对应于唯一元组的唯一标量,即X
中的唯一行
让我们再看一看X
-
In [77]: X
Out[77]:
array([[4, 2],
[9, 3],
[8, 5],
[3, 3],
[5, 6]])
In [77]: X
Out[77]:
array([[4, 2],
[9, 3],
[8, 5],
[3, 3],
[5, 6]])
现在,如前一节所讨论的,我们将每一行视为索引元组。在每个这样的索引元组中,第一个元素表示n-dim网格的第一个轴,第二个元素表示网格的第二个轴,依此类推,直到X
中每行的最后一个元素。本质上,每一列将代表网格的一个维度或轴。如果我们要把所有的元素从<代码> x>代码>映射到同一个n-朦胧网格上,我们需要考虑这样一个提出的n-朦胧网格的每个轴的最大拉伸。假设我们处理的是X
中的正数,那么这样的延伸就是X
+1中每列的最大值。+1
是因为Python遵循基于0的
索引。因此,例如X[1,0]==9
将映射到建议网格的第10行。类似地,X[4,1]==6将进入该网格的7列
因此,对于我们的示例案例,我们有-
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
X = np.array([[4, 2],
[9, 3],
[8, 5],
[3, 3],
[5, 6]])
S = np.array([[4, 2],
[3, 3],
[5, 6]])
result = [[i for i,row in enumerate(X) if (s==row).all()] for s in S]
或
如果您想要一个简单的列表(假设每个搜索值正好有一个匹配)。另一种选择是使用asvoid
(以下)将每一行作为单个行查看
void
dtype的值。这将2D数组缩减为1D数组,从而允许您像往常一样使用np.in1d
:
import numpy as np
def asvoid(arr):
"""
Based on http://stackoverflow.com/a/16973510/190597 (Jaime, 2013-06)
View the array as dtype np.void (bytes). The items along the last axis are
viewed as one value. This allows comparisons to be performed which treat
entire rows as one value.
"""
arr = np.ascontiguousarray(arr)
if np.issubdtype(arr.dtype, np.floating):
""" Care needs to be taken here since
np.array([-0.]).view(np.void) != np.array([0.]).view(np.void)
Adding 0. converts -0. to 0.
"""
arr += 0.
return arr.view(np.dtype((np.void, arr.dtype.itemsize * arr.shape[-1])))
X = np.array([[4, 2],
[9, 3],
[8, 5],
[3, 3],
[5, 6]])
searched_values = np.array([[4, 2],
[3, 3],
[5, 6]])
idx = np.flatnonzero(np.in1d(asvoid(X), asvoid(searched_values)))
print(idx)
# [0 3 4]
该软件包(免责声明:我是其作者)包含有效执行此类操作的功能(还使用引擎盖下的searchsorted)。就功能而言,它相当于list.index的矢量化等价物:
import numpy_indexed as npi
result = npi.indices(X, searched_values)
请注意,使用“missing”kwarg,您可以完全控制丢失项的行为,并且它也适用于nd数组(fi;图像堆栈)
更新:使用与@RikX=[520000,28,28]
和searched\u values=[20000,28,28]
相同的形状,它运行时间为0.8064秒
,使用missing=-1来检测和表示X中不存在的条目。这里有一个非常快速的解决方案,可以使用numpy和hashlib进行良好的扩展。它可以在几秒钟内处理大尺寸矩阵或图像。我在520000 X(28 X 28)阵列和20000 X(28 X 28)阵列上使用它,在我的CPU上只需2秒钟
代码:
输出:
unique_idx= [4 3 0]
X[unique_idx]= [[5 6]
[3 3]
[4 2]]
另一种方法是使用scipy.space.distance