Python 通过使用索引列表为每行选择特定的列索引

Python 通过使用索引列表为每行选择特定的列索引,python,numpy,Python,Numpy,我正在努力选择NumPy矩阵中每行的特定列 假设我有以下矩阵,我称之为X: [1, 2, 3] [4, 5, 6] [7, 8, 9] 我还有一个每行的列索引列表,我称之为Y: [1, 0, 2] 我需要获得以下值: [2] [4] [9] 我还可以生成一个与X形状相同的矩阵,其中每一列都是0-1范围内的bool/int,指示这是否是必需的列,而不是索引为Y的列表 [0, 1, 0] [1, 0, 0] [0, 0, 1] 我知道这可以通过迭代数组并选择所需的列值来实现。然而,这将在大型

我正在努力选择NumPy矩阵中每行的特定列

假设我有以下矩阵,我称之为
X

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
我还有一个每行的
列索引列表,我称之为
Y

[1, 0, 2]
我需要获得以下值:

[2]
[4]
[9]
我还可以生成一个与
X
形状相同的矩阵,其中每一列都是0-1范围内的
bool
/
int
,指示这是否是必需的列,而不是索引为
Y
列表

[0, 1, 0]
[1, 0, 0]
[0, 0, 1]
我知道这可以通过迭代数组并选择所需的列值来实现。然而,这将在大型数据阵列上频繁执行,这就是为什么它必须以尽可能快的速度运行


因此,我想知道是否有更好的解决方案?

如果您有一个布尔数组,您可以基于该数组进行直接选择,如下所示:

>>> a = np.array([True, True, True, False, False])
>>> b = np.array([1,2,3,4,5])
>>> b[a]
array([1, 2, 3])
按照您最初的示例,您可以执行以下操作:

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> b = np.array([[False,True,False],[True,False,False],[False,False,True]])
>>> a[b]
array([2, 4, 9])
您还可以添加一个
arange
,并对其进行直接选择,不过这取决于生成布尔数组的方式以及代码的外观

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> a[np.arange(len(a)), [1,0,2]]
array([2, 4, 9])

希望这能有所帮助,如果您还有任何问题,请告诉我。

您可以这样做:

In [7]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [8]: lst = [1, 0, 2]

In [9]: a[np.arange(len(a)), lst]
Out[9]: array([2, 4, 9])

有关多维数组索引的更多信息:

您可以使用迭代器进行索引。像这样:

np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)
时间:


一个简单的方法可能如下所示:

In [1]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [2]: y = [1, 0, 2]  #list of indices we want to select from matrix 'a'
range(a.shape[0])
将返回
array([0,1,2])


另一个聪明的方法是首先转置数组,然后对其进行索引。最后,以对角线为例,它总是正确的答案

X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
Y = np.array([1, 0, 2, 2])

np.diag(X.T[Y])
一步一步:

原始阵列:

>>> X
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

>>> Y
array([1, 0, 2, 2])
转置使索引正确成为可能

>>> X.T
array([[ 1,  4,  7, 10],
       [ 2,  5,  8, 11],
       [ 3,  6,  9, 12]])
按Y顺序获取行

>>> X.T[Y]
array([[ 2,  5,  8, 11],
       [ 1,  4,  7, 10],
       [ 3,  6,  9, 12],
       [ 3,  6,  9, 12]])
对角线现在应该变得清晰了

>>> np.diag(X.T[Y])
array([ 2,  4,  9, 12]

最近的
numpy
版本添加了一个
take_沿轴
(和
put_沿轴
)可以干净地进行索引

In [101]: a = np.arange(1,10).reshape(3,3)                                                             
In [102]: b = np.array([1,0,2])                                                                        
In [103]: np.take_along_axis(a, b[:,None], axis=1)                                                     
Out[103]: 
array([[2],
       [4],
       [9]])
其运行方式与:

In [104]: a[np.arange(3), b]                                                                           
Out[104]: array([2, 4, 9])

但轴处理方式不同。它特别针对应用
argsort
argmax

的结果,OP提到它应该在大型阵列上快速运行,因此您的基准测试不是很有代表性。我很好奇您的最后一个方法对于(大得多的)数组的性能如何@莫宁孙:更新<代码>np.diag(X.T[Y])
太慢了。。。但是
np.diag(X.T)
太快了(10us)。我不知道为什么。+1用于使用
arange
的示例。这对我从多个矩阵中检索不同的块特别有用(因此本例基本上是3D情况)。嗨,你能解释一下为什么我们必须使用
arange
而不是
?我知道你的方法行得通,我的方法不行,但我想知道为什么。@tamzord因为它是一个numpy数组,而不是一个普通的python列表,所以
语法的工作方式不同。@SlaterTyranus,谢谢你的回复。经过一些阅读,我的理解是,将
与高级索引混合意味着:“对于
中的每个子空间,应用给定的高级索引”。“我的理解正确吗?”TaZordd解释你所说的“子空间”的意思,请考虑添加解释。感谢您努力理解为什么需要使用arange而不是简单的“:”或range。@MadmanLee Hi使用
将输出多个
len(a)
次的结果,指示每行的索引将打印预期结果。我认为这正是解决此问题的正确且优雅的方法。答案是否更适合您?从技术上讲,这是可行的,看起来非常优雅。但是,我发现,在处理大型阵列时,这种方法会完全崩溃。在我的情况下,NumPy吞下了30GB的交换空间并填满了我的SSD。我建议改用高级索引方法。太棒了,很高兴有你的答案来了解这一点!
In [101]: a = np.arange(1,10).reshape(3,3)                                                             
In [102]: b = np.array([1,0,2])                                                                        
In [103]: np.take_along_axis(a, b[:,None], axis=1)                                                     
Out[103]: 
array([[2],
       [4],
       [9]])
In [104]: a[np.arange(3), b]                                                                           
Out[104]: array([2, 4, 9])