numpy,返回形状的索引数组

时间:2015-09-04 08:12:32

标签: python arrays numpy matrix-indexing

我想从numpy数组得到索引列表(或数组)的结果,形状为:(len(indices),(一个索引操作的形状))。

有没有办法直接使用索引列表,而不使用for循环,就像我在mininal示例中使用的那样,如下所示?

c = np.random.randint(0, 5, size=(4, 5))
indices = [[0, slice(0, 4)], [1, slice(0, 4)], [1, slice(0, 4)], [2, slice(0, 4)]]

# desired result using a for loop
res = []
for idx in indices:
    res.append(c[idx])

应该注意的是,索引列表并不代表我的问题,它作为一个例子,通常它是在运行时生成的。 但是,每个索引操作都返回相同的形状

2 个答案:

答案 0 :(得分:0)

看起来你基本上是在从2D​​输入数组的开头到2 rows4 columns切片,然后分割每一行。您可以使用c[:2,:4]进行切片,然后使用np.vsplit拆分行以获得类似的单行解决方案 -

res_out = np.vsplit(c[:2,:4],2)

示例运行 -

In [10]: c
Out[10]: 
array([[0, 2, 5, 1, 0],
       [1, 5, 5, 0, 3],
       [0, 1, 0, 6, 6],
       [2, 6, 2, 3, 3]])

In [11]: indices
Out[11]: [[0, slice(0, 4, None)], [1, slice(0, 4, None)]]

In [12]: # desired result using a for loop
    ...: res = []
    ...: for idx in indices:
    ...:     res.append(c[idx])
    ...:     

In [13]: res
Out[13]: [array([0, 2, 5, 1]), array([1, 5, 5, 0])]

In [14]: np.vsplit(c[:2,:4],2)
Out[14]: [array([[0, 2, 5, 1]]), array([[1, 5, 5, 0]])]

请注意,np.vsplit的输出将是2D数组的列表,而不是问题中发布的代码的1D数组列表。

答案 1 :(得分:0)

您的示例可以重写为列表理解:

In [121]: [c[idx] for idx in indices]
Out[121]: 
[array([4, 2, 1, 2]),
 array([3, 2, 2, 3]),
 array([3, 2, 2, 3]),
 array([0, 3, 4, 4])]

可以变成一个漂亮的二维数组:

In [122]: np.array([c[idx] for idx in indices])
Out[122]: 
array([[4, 2, 1, 2],
       [3, 2, 2, 3],
       [3, 2, 2, 3],
       [0, 3, 4, 4]])

这里np.array()是一种连接形式,沿着新轴连接数组。

由于第二个索引对于所有行(slice(4))都是相同的,因此这个索引也有效:

In [123]: c[[0,1,1,2],slice(4)]  # or [...,:4]
Out[123]: 
array([[4, 2, 1, 2],
       [3, 2, 2, 3],
       [3, 2, 2, 3],
       [0, 3, 4, 4]])

重复第一轴不是问题。在第二局中不同的切片需要更多操作。除了这个特殊的:4情况,您必须将切片转换为范围。没有办法用多个切片索引一个维度。

切片全部具有相同长度但不同的“开始”值的情况类似于https://stackoverflow.com/a/28007256/901925 access-multiple-elements-of-an-array中讨论的那种情况。

In [135]: c.flat[[i*c.shape[1]+np.arange(j.start,j.stop) for i,j in indices]]
Out[135]: 
array([[4, 2, 1, 2],
       [3, 2, 2, 3],
       [3, 2, 2, 3],
       [0, 3, 4, 4]])

我以这种方式生成的索引是:

In [136]: [i*c.shape[1]+np.arange(j.start,j.stop) for i,j in indices]
Out[136]: 
[array([0, 1, 2, 3]),
 array([5, 6, 7, 8]),
 array([5, 6, 7, 8]),
 array([10, 11, 12, 13])]

如果indices有些不规则,它可以正常工作:indices1 = [[0, slice(0, 3)], [1, slice(2, 5)], [1, slice(1, 4)], [2, slice(0, 3)]]

我之前的回答是关于索引的其他一些方法。但是,即使考虑到生成索引数组所需的计算,通常在展平数组上进行索引也是最快的。

如果切片长度不同,那么您将无法生成数组列表或hstack这样的列表:

In [158]: indices2 = [[0, slice(0, 2)], [1, slice(2, 5)], 
    [1, slice(0, 4)], [2, slice(0, 5)]]

In [159]: c.flat[np.hstack([i*c.shape[1]+np.arange(j.start,j.stop) 
     for i,j in indices2])]
Out[159]: array([4, 2, 2, 3, 1, 3, 2, 2, 3, 0, 3, 4, 4, 3])

In [160]: [c.flat[i*c.shape[1]+np.arange(j.start,j.stop)] for i,j in indices2]
Out[160]: [array([4, 2]), array([2, 3, 1]), array([3, 2, 2, 3]),
    array([0, 3, 4, 4, 3])]

In [161]: np.hstack(_)
Out[161]: array([4, 2, 2, 3, 1, 3, 2, 2, 3, 0, 3, 4, 4, 3])

更多关于变化但等长的切片:

In [190]: indices1 = [[0, slice(0, 3)], [1, slice(2, 5)], [1, slice(1, 4)], [2, slice(0, 3)]]

In [191]: c.flat[[i*c.shape[1]+np.arange(j.start,j.stop) for i,j in indices1]]Out[191]: 
array([[4, 2, 1],
       [2, 3, 1],
       [2, 2, 3],
       [0, 3, 4]])

In [193]: rows = [[i] for i,j in indices1]
In [200]: cols=[np.arange(j.start,j.stop) for i,j in indices1]

In [201]: c[rows,cols]
Out[201]: 
array([[4, 2, 1],
       [2, 3, 1],
       [2, 2, 3],
       [0, 3, 4]])

在这种情况下,rows是一个垂直列表,可以使用cols进行广播。