我想从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])
应该注意的是,索引列表并不代表我的问题,它作为一个例子,通常它是在运行时生成的。 但是,每个索引操作都返回相同的形状
答案 0 :(得分:0)
看起来你基本上是在从2D输入数组的开头到2 rows
和4 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
进行广播。