简体   繁体   English

将切片和广播索引相结合以实现多维numpy数组

[英]Combining slicing and broadcasted indexing for multi-dimensional numpy arrays

I have a ND numpy array (let say for instance 3x3x3) from wich I'd like to extract a sub-array, combining slices and index arrays. 我有一个ND numpy数组(例如3x3x3),我想提取一个子数组,结合切片和索引数组。 For instance: 例如:

import numpy as np  
A = np.arange(3*3*3).reshape((3,3,3))
i0, i1, i2 = ([0,1], [0,1,2], [0,2])
ind1 = j0, j1, j2 = np.ix_(i0, i1, i2)
ind2 = (j0, slice(None), j2)
B1 = A[ind1]
B2 = A[ind2]

I would expect that B1 == B2, but actually, the shapes are different 我希望B1 == B2,但是实际上,形状是不同的

>>> B1.shape
(2, 3, 2)
>>> B2.shape
(2, 1, 2, 3)
>>> B1
array([[[ 0,  2],
        [ 3,  5],
        [ 6,  8]],

       [[ 9, 11],
        [12, 14],
        [15, 17]]])
>>> B2
array([[[[ 0,  3,  6],
         [ 2,  5,  8]]],

       [[[ 9, 12, 15],
         [11, 14, 17]]]])

Someone understands why? 有人知道为什么吗? Any idea of how I could get 'B1' by manipulating only 'A' and 'ind2' objects? 关于如何仅通过操作“ A”和“ ind2”对象来获得“ B1”的任何想法吗? The goal is that it would work for any nD arrays, and that I would not have to look for the shape of dimensions I want to keep entirely (hope I'm clear enough:)). 目标是它适用于任何nD数组,并且我不必寻找要完全保留的尺寸形状(希望我已经很清楚了:)。 Thanks!! 谢谢!!
---EDIT--- - -编辑 - -
To be clearer, I would like to have a function 'fun' such that 更清楚地说,我想有一个功能“有趣”,使

A[fun(ind2)] == B1

The indexing subspaces of ind1 are (2,),(3,),(2,), and the resulting B is (2,3,2) . ind1的索引子空间为(2,),(3,),(2,),结果B(2,3,2) This is a simple case of advanced indexing. 这是高级索引的简单情况。

ind2 is a case of (advanced) partial indexing. ind2是(高级)部分索引的一种情况。 There are 2 indexed arrays, and 1 slice. 有2个索引数组和1个切片。 The advanced indexing documentation states: 高级索引文档指出:

If the indexing subspaces are separated (by slice objects), then the broadcasted indexing space is first, followed by the sliced subspace of x. 如果索引子空间是分离的(按切片对象划分),则首先广播的索引空间,然后是x的切片子空间。

In this case advanced indexing constructs a (2,2) array (from the 1st and 3rd indexes), and appends the slice dimension at the end, resulting in a (2,2,3) array. 在这种情况下,高级索引从第一个索引和第三个索引构造一个(2,2)数组,并在末尾附加切片尺寸,从而得到一个(2,2,3)数组。

I explain the reasoning in more detail in https://stackoverflow.com/a/27097133/901925 我会在https://stackoverflow.com/a/27097133/901925中更详细地说明推理的原因

A way to fix a tuple like ind2 , is to expand each slice into an array. 修复像ind2这样的元组的一种方法是将每个slice扩展成一个数组。 I recently saw this done in np.insert . 我最近在np.insert看到了这一点。

np.arange(*ind2[1].indices(3))

expands : to [0,1,2] . 扩展:[0,1,2] But the replacement has to have the right shape. 但是替换必须具有正确的形状。

ind=list(ind2)
ind[1]=np.arange(*ind2[1].indices(3)).reshape(1,-1,1)
A[ind]

I'm leaving off the details of determining which term is a slice, its dimension, and the relevant reshape. 我将省略确定哪个术语是一个切片,其尺寸以及相关重塑的详细信息。 The goal is to reproduce i1 . 目的是复制i1

If indices were generated by something other than ix_ , reshaping this slice could be more difficult. 如果索引不是由ix_生成的,则重塑ix_难度可能更大。 For example 例如

A[np.array([0,1])[None,:,None],:,np.array([0,2])[None,None,:]] # (1,2,2,3)
A[np.array([0,1])[None,:,None],np.array([0,1,2])[:,None,None],np.array([0,2])[None,None,:]]
# (3,2,2)

The expanded slice has to be compatible with the other arrays under broadcasting. 扩展的片必须与广播中的其他阵列兼容。

Swapping axes after indexing is another option. 索引后交换轴是另一种选择。 The logic, though, might be more complex. 但是,逻辑可能更复杂。 But in some cases transposing might actually be simpler: 但是在某些情况下,移置实际上可能更简单:

A[np.array([0,1])[:,None],:,np.array([0,2])[None,:]].transpose(2,0,1)
# (3,2,2)
A[np.array([0,1])[:,None],:,np.array([0,2])[None,:]].transpose(0,2,1)
# (2, 3, 2)

This is the closer I can get to your specs, I haven't been able to devise a solution that can compute the correct indices without knowing A (or, more precisely, its shape...). 这是我能更接近您的规格的信息,我无法设计出一种在不知道A (或更确切地说,其形状...)的情况下可以计算正确索引的解决方案。

import numpy as np  

def index(A, s):
    ind = []
    groups = s.split(';')
    for i, group in enumerate(groups):
        if group == ":":
            ind.append(range(A.shape[i]))
        else:
            ind.append([int(n) for n in group.split(',')])
    return np.ix_(*ind)

A = np.arange(3*3*3).reshape((3,3,3))

ind2 = index(A,"0,1;:;0,2")
print A[ind2]

A shorter version 较短的版本

def index2(A,s):return np.ix_(*[range(A.shape[i])if g==":"else[int(n)for n in g.split(',')]for i,g in enumerate(s.split(';'))])

ind3 = index2(A,"0,1;:;0,2")
print A[ind3]

In restricted indexing cases like this using ix_ , it is possible to do the indexing in successive steps. 在使用ix_这样的受限索引情况下,可以ix_索引。

A[ind1]

is the same as 是相同的

A[i1][:,i2][:,:,i3]

and since i2 is the full range, 由于i2是完整范围,

A[i1][...,i3]

If you only have ind2 available 如果您只有ind2

A[ind2[0].flatten()][[ind2[2].flatten()]

In more general contexts you have to know how j0,j1,j2 broadcast with each other, but when they are generated by ix_ , the relationship is simple. 在更一般的上下文中,您必须知道j0,j1,j2如何相互广播,但是当它们由ix_生成时,关系很简单。

I can imagine circumstances in which it would be convenient to assign A1 = A[i1] , followed by a variety of actions involving A1 , including, but not limited to A1[...,i3] . 我可以想象一下这样的情况:分配A1 = A[i1]并随后进行涉及A1的各种动作(包括但不限于A1[...,i3] You have to be aware of when A1 is a view, and when it is a copy. 您必须知道什么时候A1是视图,什么时候是副本。

Another indexing tool is take : 另一个索引工具是take

A.take(i0,axis=0).take(i2,axis=2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM