Programing

NumPy 2d 배열의 슬라이스 또는 nxn 배열에서 mxm 하위 행렬을 어떻게 추출합니까 (n> m)?

lottogame 2020. 6. 1. 07:40
반응형

NumPy 2d 배열의 슬라이스 또는 nxn 배열에서 mxm 하위 행렬을 어떻게 추출합니까 (n> m)?


NumPy nxn 배열을 슬라이스하고 싶습니다. 해당 배열의 m 행과 열을 임의로 선택 하여 추출합니다 (즉, 행 / 열 수에 패턴이 없음). 새로운 mxm 배열이됩니다. 이 예제에서는 배열이 4x4라고 가정하고 2x2 배열을 추출하고 싶습니다.

배열은 다음과 같습니다.

from numpy import *
x = range(16)
x = reshape(x,(4,4))

print x
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]

제거 할 행과 열이 동일합니다. 가장 쉬운 경우는 시작 또는 끝에있는 2x2 하위 행렬을 추출하려는 경우입니다.

In [33]: x[0:2,0:2]
Out[33]: 
array([[0, 1],
       [4, 5]])

In [34]: x[2:,2:]
Out[34]: 
array([[10, 11],
       [14, 15]])

그러나 다른 행 / 열 혼합을 제거해야하는 경우 어떻게해야합니까? 첫 번째와 세 번째 줄 / 행을 제거하여 하위 행렬을 추출해야하는 경우 어떻게해야 [[5,7],[13,15]]합니까? 행 / 라인의 구성이있을 수 있습니다. 행과 열 모두에 대한 배열 / 인덱스 목록을 사용하여 배열을 색인화 해야하는 곳을 읽었지만 작동하지 않는 것 같습니다.

In [35]: x[[1,3],[1,3]]
Out[35]: array([ 5, 15])

한 가지 방법을 찾았습니다.

    In [61]: x[[1,3]][:,[1,3]]
Out[61]: 
array([[ 5,  7],
       [13, 15]])

이것의 첫 번째 문제는 읽을 수는 없지만 읽을 수는 없다는 것입니다. 누군가가 더 나은 해결책을 가지고 있다면 분명히 듣고 싶습니다.

또 다른 것은 포럼 에서 배열을 사용하여 배열을 인덱싱하면 NumPy가 원하는 배열의 사본을 만들도록 강요하므로 큰 배열로 처리 할 때 문제가 될 수 있다는 것입니다. 그 이유는 무엇입니까 /이 메커니즘은 어떻게 작동합니까?


Sven이 언급했듯이 x[[[0],[2]],[1,3]]1 및 3 열과 일치하는 0 및 2 행을 x[[0,2],[1,3]]반환하고 배열의 값 x [0,1] 및 x [2,3]을 반환합니다.

내가 준 첫 번째 예제를 수행하는 데 유용한 기능이 있습니다 numpy.ix_. 을 사용하여 첫 번째 예제와 동일한 작업을 수행 할 수 있습니다 x[numpy.ix_([0,2],[1,3])]. 이렇게하면 추가 대괄호를 모두 입력하지 않아도됩니다.


이 질문에 답하기 위해 Numpy에서 다차원 배열의 색인 생성 방식을 살펴 봐야합니다. 먼저 x질문 에서 배열이 있다고 가정 해 봅시다 . 할당 된 버퍼 x는 0에서 15까지 16 개의 오름차순 정수를 포함합니다. 한 요소에 액세스하는 경우 x[i,j]NumPy는 버퍼의 시작과 관련하여이 요소의 메모리 위치를 파악해야합니다. 이것은 실제로 계산 i*x.shape[1]+j하고 실제 메모리 오프셋을 얻기 위해 int 크기를 곱하여 수행됩니다 .

과 같은 기본 슬라이싱으로 하위 배열을 추출 y = x[0:2,0:2]하면 결과 객체는 기본 버퍼를와 공유합니다 x. 그러나 당신이 액세스하면 어떻게됩니까 y[i,j]? NumPy는 i*y.shape[1]+j속한 데이터 y가 메모리에서 연속적이지 않기 때문에 배열에 대한 오프셋을 계산하는 데 사용할 수 없습니다 .

NumPy는 보폭 을 도입하여이 문제를 해결합니다 . 에 액세스하기위한 메모리 오프셋을 계산할 때 x[i,j]실제로 계산되는 것은 실제로 i*x.strides[0]+j*x.strides[1]int 크기에 대한 요소를 포함합니다.

x.strides
(16, 4)

경우 y위와 같이 추출하고, NumPy와 새로운 버퍼를 생성하지 않지만 않는 동일한 완충액 (다르게 참조 새로운 어레이 오브젝트 생성 y단지 동일 할 것이다 x그럼.) 새로운 어레이 오브젝트가 다른 형상을 가질 것이다 x어쩌면 다른 시작 버퍼로 오프셋되지만 보폭을 x(이 경우 적어도) 공유합니다 .

y.shape
(2,2)
y.strides
(16, 4)

이런 식으로 메모리 오프셋을 계산 y[i,j]하면 올바른 결과를 얻을 수 있습니다.

But what should NumPy do for something like z=x[[1,3]]? The strides mechanism won't allow correct indexing if the original buffer is used for z. NumPy theoretically could add some more sophisticated mechanism than the strides, but this would make element access relatively expensive, somehow defying the whole idea of an array. In addition, a view wouldn't be a really lightweight object anymore.

This is covered in depth in the NumPy documentation on indexing.

Oh, and nearly forgot about your actual question: Here is how to make the indexing with multiple lists work as expected:

x[[[1],[3]],[1,3]]

This is because the index arrays are broadcasted to a common shape. Of course, for this particular example, you can also make do with basic slicing:

x[1::2, 1::2]

I don't think that x[[1,3]][:,[1,3]] is hardly readable. If you want to be more clear on your intent, you can do:

a[[1,3],:][:,[1,3]]

I am not an expert in slicing but typically, if you try to slice into an array and the values are continuous, you get back a view where the stride value is changed.

e.g. In your inputs 33 and 34, although you get a 2x2 array, the stride is 4. Thus, when you index the next row, the pointer moves to the correct position in memory.

Clearly, this mechanism doesn't carry well into the case of an array of indices. Hence, numpy will have to make the copy. After all, many other matrix math function relies on size, stride and continuous memory allocation.


If you want to skip every other row and every other column, then you can do it with basic slicing:

In [49]: x=np.arange(16).reshape((4,4))
In [50]: x[1:4:2,1:4:2]
Out[50]: 
array([[ 5,  7],
       [13, 15]])

This returns a view, not a copy of your array.

In [51]: y=x[1:4:2,1:4:2]

In [52]: y[0,0]=100

In [53]: x   # <---- Notice x[1,1] has changed
Out[53]: 
array([[  0,   1,   2,   3],
       [  4, 100,   6,   7],
       [  8,   9,  10,  11],
       [ 12,  13,  14,  15]])

while z=x[(1,3),:][:,(1,3)] uses advanced indexing and thus returns a copy:

In [58]: x=np.arange(16).reshape((4,4))
In [59]: z=x[(1,3),:][:,(1,3)]

In [60]: z
Out[60]: 
array([[ 5,  7],
       [13, 15]])

In [61]: z[0,0]=0

Note that x is unchanged:

In [62]: x
Out[62]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

If you wish to select arbitrary rows and columns, then you can't use basic slicing. You'll have to use advanced indexing, using something like x[rows,:][:,columns], where rows and columns are sequences. This of course is going to give you a copy, not a view, of your original array. This is as one should expect, since a numpy array uses contiguous memory (with constant strides), and there would be no way to generate a view with arbitrary rows and columns (since that would require non-constant strides).


With numpy, you can pass a slice for each component of the index - so, your x[0:2,0:2] example above works.

If you just want to evenly skip columns or rows, you can pass slices with three components (i.e. start, stop, step).

Again, for your example above:

>>> x[1:4:2, 1:4:2]
array([[ 5,  7],
       [13, 15]])

Which is basically: slice in the first dimension, with start at index 1, stop when index is equal or greater than 4, and add 2 to the index in each pass. The same for the second dimension. Again: this only works for constant steps.

The syntax you got to do something quite different internally - what x[[1,3]][:,[1,3]] actually does is create a new array including only rows 1 and 3 from the original array (done with the x[[1,3]] part), and then re-slice that - creating a third array - including only columns 1 and 3 of the previous array.


I have a similar question here: Writting in sub-ndarray of a ndarray in the most pythonian way. Python 2 .

Following the solution of previous post for your case the solution looks like:

columns_to_keep = [1,3] 
rows_to_keep = [1,3]

An using ix_:

x[np.ix_(rows_to_keep, columns_to_keep)] 

Which is:

array([[ 5,  7],
       [13, 15]])

I'm not sure how efficient this is but you can use range() to slice in both axis

 x=np.arange(16).reshape((4,4))
 x[range(1,3), :][:,range(1,3)] 

참고URL : https://stackoverflow.com/questions/4257394/slicing-of-a-numpy-2d-array-or-how-do-i-extract-an-mxm-submatrix-from-an-nxn-ar

반응형