인덱스 목록을 사용하여 행당 특정 열 인덱스를 선택하는 NumPy


90

NumPy행렬의 행당 특정 열을 선택하는 데 어려움을 겪고 있습니다.

다음과 같은 행렬이 있다고 가정합니다 X.

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

또한 list호출 할 모든 행마다 열 인덱스가 있습니다 Y.

[1, 0, 2]

값을 가져와야합니다.

[2]
[4]
[9]

listwith indexes 대신에 모든 열이 0-1 값 범위에서 / 인 Y것과 동일한 모양의 행렬을 생성하여 이것이 필수 열인지 여부를 나타낼 수도 있습니다.Xboolint

[0, 1, 0]
[1, 0, 0]
[0, 0, 1]

배열을 반복하고 필요한 열 값을 선택하면이 작업을 수행 할 수 있습니다. 그러나 이것은 대규모 데이터 배열에서 자주 실행되므로 가능한 한 빨리 실행해야합니다.

따라서 더 나은 해결책이 있는지 궁금합니다.

감사합니다.


당신에게 더 나은 대답이 있습니까? stackoverflow.com/a/17081678/5046896
GoingMyWay

답변:


102

부울 배열이있는 경우이를 기반으로 직접 선택할 수 있습니다.

>>> a = np.array([True, True, True, False, False])
>>> b = np.array([1,2,3,4,5])
>>> b[a]
array([1, 2, 3])

초기 예제와 함께 진행하려면 다음을 수행 할 수 있습니다.

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> b = np.array([[False,True,False],[True,False,False],[False,False,True]])
>>> a[b]
array([2, 4, 9])

arange부울 배열을 생성하는 방법과 코드가 YMMV처럼 보이는 방식에 따라을 추가 하고 직접 선택할 수도 있습니다 .

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> a[np.arange(len(a)), [1,0,2]]
array([2, 4, 9])

도움이 되었기를 바라며 더 궁금한 점이 있으면 알려주세요.


11
을 사용하는 예제의 경우 +1 arange. 이것은 여러 행렬에서 다른 블록을 검색하는 데 특히 유용했습니다 (기본적으로이 예제의 3D 경우)
Griddo

1
안녕하세요, 왜 arange대신 사용해야하는지 설명해 주 :시겠습니까? 나는 당신의 방식이 작동하고 내 방식은 그렇지 않다는 것을 알고 있지만 그 이유를 이해하고 싶습니다.
marcotama

@tamzord는 바닐라 파이썬 목록이 아니라 numpy 배열이기 때문에 :구문이 같은 방식으로 작동하지 않습니다.
Slater Victoroff

1
@SlaterTyranus, 응답 해 주셔서 감사합니다. 제가 이해 한 바에 따르면 :고급 인덱싱과의 혼합 은 "모든 하위 공간에 :대해 주어진 고급 인덱싱을 적용 "한다는 의미 입니다. 내 이해가 맞습니까?
marcotama

당신이 "하위 공간"무슨 뜻인지 설명 @tamzord
슬레이터 Victoroff에게

35

다음과 같이 할 수 있습니다.

In [7]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [8]: lst = [1, 0, 2]

In [9]: a[np.arange(len(a)), lst]
Out[9]: array([2, 4, 9])

다차원 배열 색인화에 대한 추가 정보 : http://docs.scipy.org/doc/numpy/user/basics.indexing.html#indexing-multi-dimensional-arrays


1
단순히 ':'또는 범위 대신 범위가 필요한 이유를 이해하기 위해 고군분투합니다.
MadmanLee 19 년

@MadmanLee Hi, using :은 결과를 여러 len(a)번 출력하는 대신 각 행의 인덱스가 예상 결과를 인쇄 함을 나타냅니다.
GoingMyWay

1
이것이 바로이 문제를 해결하는 옳고 우아한 방법이라고 생각합니다.
GoingMyWay

6

간단한 방법은 다음과 같습니다.

In [1]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [2]: y = [1, 0, 2]  #list of indices we want to select from matrix 'a'

range(a.shape[0]) 돌아올 것이다 array([0, 1, 2])

In [3]: a[range(a.shape[0]), y] #we're selecting y indices from every row
Out[3]: array([2, 4, 9])

1
설명을 추가해보세요.
souki

@souki 지금 설명을 추가했습니다. 감사합니다
Dhaval Mayatra

6

최신 numpy버전에는 이 색인을 깔끔하게 수행 하는 take_along_axis(및 put_along_axis) 이 추가되었습니다 .

In [101]: a = np.arange(1,10).reshape(3,3)                                                             
In [102]: b = np.array([1,0,2])                                                                        
In [103]: np.take_along_axis(a, b[:,None], axis=1)                                                     
Out[103]: 
array([[2],
       [4],
       [9]])

다음과 같은 방식으로 작동합니다.

In [104]: a[np.arange(3), b]                                                                           
Out[104]: array([2, 4, 9])

하지만 축 처리가 다릅니다. 특히 argsort및 의 결과를 적용하는 데 목적이 argmax있습니다.


3

반복자를 사용하여 할 수 있습니다. 이렇게 :

np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)

시각:

N = 1000
X = np.zeros(shape=(N, N))
Y = np.arange(N)

#@Aशwini चhaudhary
%timeit X[np.arange(len(X)), Y]
10000 loops, best of 3: 30.7 us per loop

#mine
%timeit np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)
1000 loops, best of 3: 1.15 ms per loop

#mine
%timeit np.diag(X.T[Y])
10 loops, best of 3: 20.8 ms per loop

1
OP는 대형 어레이에서 빠르게 실행되어야한다고 언급 했으므로 벤치 마크가 그다지 대표적이지 않습니다. 마지막 방법이 (훨씬) 더 큰 배열에서 어떻게 수행되는지 궁금합니다!

@moarningsun : 업데이트되었습니다. np.diag(X.T[Y])너무 느립니다 ...하지만 np.diag(X.T)너무 빠릅니다 (10us). 이유를 모르겠습니다.
Kei Minagawa

0

또 다른 영리한 방법은 먼저 배열을 전치하고 그 후에 색인을 생성하는 것입니다. 마지막으로, 항상 정답 인 대각선을 취하십시오.

X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
Y = np.array([1, 0, 2, 2])

np.diag(X.T[Y])

단계별 :

원래 배열 :

>>> X
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

>>> Y
array([1, 0, 2, 2])

올바른 색인을 생성 할 수 있도록 조옮김합니다.

>>> X.T
array([[ 1,  4,  7, 10],
       [ 2,  5,  8, 11],
       [ 3,  6,  9, 12]])

Y 순서로 행을 가져옵니다.

>>> X.T[Y]
array([[ 2,  5,  8, 11],
       [ 1,  4,  7, 10],
       [ 3,  6,  9, 12],
       [ 3,  6,  9, 12]])

이제 대각선이 명확 해집니다.

>>> np.diag(X.T[Y])
array([ 2,  4,  9, 12]

1
이것은 기술적으로 작동하고 매우 우아하게 보입니다. 그러나이 접근 방식은 대규모 어레이를 다룰 때 완전히 폭발적입니다. 제 경우에는 NumPy가 30GB의 스왑을 삼키고 SSD를 채웠습니다. 대신 고급 인덱싱 방식을 사용하는 것이 좋습니다.
5nefarious
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.