인덱스 목록을 사용하여 행당 특정 열 인덱스를 선택하는 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.