使用另一个2D数组索引NumPy 2D数组

6

我有类似以下的内容

m = array([[1, 2],
            [4, 5],
            [7, 8],
            [6, 2]])

and

select = array([0,1,0,0])

我的目标是:
result = array([1, 5, 7, 6])

我尝试使用_ix,因为我在Simplfy row AND column extraction, numpy上读到了相关内容,但这并没有得到我想要的结果。
附:如果您能想到更精确的标题,请更改此问题的标题。

2
我建议将标题设为“通过列表筛选2D数组”。 - Adobe
6个回答

12

numpy 的方式是使用 np.choose 或者高级索引 / take(见下文):

m = array([[1, 2],
           [4, 5],
           [7, 8],
           [6, 2]])
select = array([0,1,0,0])

result = np.choose(select, m.T)
所以不需要使用Python循环或任何东西,因为NumPy的所有速度优势。只需要使用m.T是因为np.choose(select, (m[:,0], m[:1]))实际上更像是在两个数组之间做出选择,但像这样使用它是很直接的。


使用fancy indexing
result = m[np.arange(len(select)), select]

如果速度非常重要,可以使用np.take,它适用于1D视图(出于某种原因它要快得多,但对于这些小数组可能不是这样):

result = m.take(select+np.arange(0, len(select) * m.shape[1], m.shape[1]))

截至本文撰写时(np 1.9.2),np.choose()可能存在一个严重的限制,即最多只能有32个元素。如果m的较长维度超过此值,则会收到“ValueError:需要2到(32)个数组对象(包括)。” - rocking_ellipse

2
我更喜欢使用NP.where来进行此类索引任务(而不是NP.ix_)。
在原始帖子中未提到结果是通过位置(源数组中的行/列)还是通过某些条件(例如m>=5)选择的。无论如何,下面的代码片段都涵盖了两种情况。
三个步骤:
1. 创建条件数组; 2. 通过调用NP.where并传入此条件数组来生成一个索引数组; 3. 对源数组应用此索引数组。
>>> import numpy as NP

>>> cnd = (m==1) | (m==5) | (m==7) | (m==6)
>>> cnd
  matrix([[ True, False],
          [False,  True],
          [ True, False],
          [ True, False]], dtype=bool)

>>> # generate the index array/matrix 
>>> # by calling NP.where, passing in the condition (cnd)
>>> ndx = NP.where(cnd)
>>> ndx
  (matrix([[0, 1, 2, 3]]), matrix([[0, 1, 0, 0]]))

>>> # now apply it against the source array   
>>> m[ndx]
  matrix([[1, 5, 7, 6]])


NP.where函数的参数是一个布尔数组,这个数组是由多个复合条件表达式(如上方第一行)组成的单个表达式的结果。

如果构建这样的值过滤器不适用于您的特定用例,那没关系,您只需要以其他方式生成实际的布尔矩阵(即cnd的值)或直接创建它。


1

使用Python怎么样?

result = array([subarray[index] for subarray, index in zip(m, select)])

1
我的看法是,这是最简单的变体:

IMHO,这是最简单的变体:

m[np.arange(4), select]

1

由于标题涉及使用另一个二维数组索引二维数组,因此实际的通用numpy解决方案可以在此处找到。

简而言之:使用形状为(n,m)的索引的2D数组 具有任意大的维度m,名为inds,用于访问形状为(n,k)的另一个2D数组,名为B的元素:

# array of index offsets to be added to each row of inds
offset = np.arange(0, inds.size, inds.shape[1])

# numpy.take(B, C) "flattens" arrays B and C and selects elements from B based on indices in C
Result = np.take(B, offset[:,np.newaxis]+inds)

另一种解决方案,不使用np.take,我认为更加直观,如下:

B[np.expand_dims(np.arange(B.shape[0]), -1), inds]

这种语法的优点在于它既可以基于inds(例如np.take)读取来自B的元素,也可以用于赋值。

0
result = array([m[j][0] if i==0 else m[j][1] for i,j in zip(select, range(0, len(m)))])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接