方法#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 方法假定X 中的searched_values 中的每一行都有匹配项。
此函数为我们提供线性索引等效数。它接受 n-dimensional indices 的 2D 数组,设置为列,以及要映射这些索引和计算等效线性索引的 n 维网格本身的形状。
让我们使用现有的输入来解决手头的问题。以输入X 为例,注意它的第一行。因为,我们试图将X 的每一行转换为其线性索引等效项,并且由于np.ravel_multi_index 假定每一列都是一个索引元组,我们需要在输入函数之前转置X。因为在这种情况下,X 中每行的元素数是 2,所以要映射到的 n 维网格将是 2D。 X 中每行有 3 个元素,它应该是 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])
因此,我们将有对应于来自X 的每个索引元组的线性索引,即来自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 将映射到建议网格的第 10 行。同样,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 的每一列中添加适当的偏移量,以使这些索引元组在使用@987654382 之前为正数@。