파이썬에서 정렬 된 배열의 인덱스를 얻는 방법


199

숫자 목록이 있습니다.

myList = [1, 2, 3, 100, 5]

이제이 목록을 정렬하면 얻을 수 [1, 2, 3, 5, 100]있습니다. 내가 원하는 것은 정렬 된 순서대로 원래 목록의 요소 인덱스입니다. 즉 [0, 1, 2, 4, 3] , 값과 인덱스를 모두 반환하는 ala MATLAB의 정렬 함수입니다.



@unutbu 이것은 속임수가 아닙니다 (IMO). 이 질문은 Numpy.argsort ()를 사용하여 모순되지 않습니다
amit

@amit : "모순되지 않는다"는 무슨 뜻입니까?
unutbu

@unutbu Numpy.argsort ()는이 질문에 대한 훌륭한 답변입니다. 다른 스레드 링크 (당신은 또한 닫히고 가지고 있지 않아야 함)에 속할 수도 있지만 Numpy와 같이 언급 한 스레드에는 속하지 않을 수 있습니다. argsort ()는이 두 가지에 대한 정답이지만 참조 한 것은 아닙니다.
amit

1
불행히도,이 질문은 예를 선택할 때 심각한 결함이 있습니다. 질문을 읽는 두 가지 다른 방법은 입력이 정렬 된 순서를 벗어난 전치 일 때 동일한 대답을 제공하기 때문입니다.

답변:



147

다음과 같은 것 :

>>> myList = [1, 2, 3, 100, 5]
>>> [i[0] for i in sorted(enumerate(myList), key=lambda x:x[1])]
[0, 1, 2, 4, 3]

enumerate(myList) (색인, 값)의 튜플을 포함하는 목록을 제공합니다.

[(0, 1), (1, 2), (2, 3), (3, 100), (4, 5)]

목록을 전달 sorted하고 정렬 키 (각 튜플의 두 번째 요소; 추출 대상)를 추출하는 함수를 지정 하여 목록을 정렬합니다 lambda. 마지막으로, 정렬 된 각 요소 의 원래 색인은 [i[0] for i in ...]목록 이해를 사용하여 추출됩니다 .


7
itemgetter(1)람다 함수 대신 사용할 수 있습니다
John La Rooy

4
@gnibbler는 모듈 의 itemgetter함수 operator인 FYI를 참조합니다. 그래서 from operator import itemgetter그것을 사용하십시오.
Lauritz V. Thaulow

1
우편 번호를 사용하여 정렬 된 목록과 지수를 얻을 수 있습니다.sorted_items, sorted_inds = zip(*sorted([(i,e) for i,e in enumerate(my_list)], key=itemgetter(1)))
Charles L.

@RomanBodnarchuk이 작동하지 않습니다 x = [3,1,2]; numpy.argsort(x)[1,2,0].
shahar_m


24

대답 enumerate은 훌륭하지만 개인적으로 값으로 정렬하는 데 사용되는 람다를 좋아하지 않습니다. 다음은 색인과 값을 반대로하여 정렬합니다. 따라서 먼저 값을 기준으로 정렬 한 다음 색인을 기준으로 정렬합니다.

sorted((e,i) for i,e in enumerate(myList))

11

enumerate및로 업데이트 된 답변 itemgetter:

sorted(enumerate(a), key=lambda x: x[1])
# [(0, 1), (1, 2), (2, 3), (4, 5), (3, 100)]

목록을 함께 압축하십시오 : 튜플의 첫 번째 요소는 색인이고 두 번째는 값입니다 (그런 다음 튜플의 두 번째 값을 사용하여 정렬하십시오) x[1] x는 튜플입니다)

또는 모듈 itemgetter에서 사용 operator:

from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))

1
이 경우에는 zip보다 더 적합한 것으로 열거
njzk2

10

perfplot (내 프로젝트) 으로 이것 에 대한 빠른 성능 검사를 수행 했으며 numpy 이외의 다른 것을 추천하기가 어렵다는 것을 알았습니다 (로그 스케일 참고).

여기에 이미지 설명을 입력하십시오


줄거리를 재현하는 코드 :

import perfplot
import numpy


def sorted_enumerate(seq):
    return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]


def sorted_enumerate_key(seq):
    return [x for x, y in sorted(enumerate(seq), key=lambda x: x[1])]


def sorted_range(seq):
    return sorted(range(len(seq)), key=seq.__getitem__)


def numpy_argsort(x):
    return numpy.argsort(x)


perfplot.save(
    "argsort.png",
    setup=lambda n: numpy.random.rand(n),
    kernels=[sorted_enumerate, sorted_enumerate_key, sorted_range, numpy_argsort],
    n_range=[2 ** k for k in range(15)],
    xlabel="len(x)",
)

6

numpy를 사용하지 않으려면

sorted(range(len(seq)), key=seq.__getitem__)

여기에 표시된 것처럼 가장 빠릅니다 .


5

기본적으로 argsort외부 라이브러리 (예 : NumPy)를 사용하려는 경우 또는 의존하지 않고 순수한 파이썬을 유지하려는 경우 필요한 구현이 필요합니다.

스스로에게 물어보아야 할 질문은 다음과 같습니다.

  • 배열 / 목록을 정렬하는 인덱스
  • 요소가 정렬 된 배열 / 목록에있을 것이라는 지수

불행히도 문제의 예는 원하는 결과를 명확하게 나타내지 못합니다.

>>> arr = np.array([1, 2, 3, 100, 5])

>>> np.argsort(np.argsort(arr))
array([0, 1, 2, 4, 3], dtype=int64)

>>> np.argsort(arr)
array([0, 1, 2, 4, 3], dtype=int64)

선택 argsort구현

NumPy를 마음대로 사용할 수 있다면 단순히 함수 numpy.argsort또는 방법을 사용할 수 있습니다numpy.ndarray.argsort .

NumPy가없는 구현은 이미 다른 답변에서 언급되었으므로 벤치 마크 답변 에 따라 가장 빠른 솔루션을 요약 해 보겠습니다 .

def argsort(l):
    return sorted(range(len(l)), key=l.__getitem__)

배열 / 목록을 정렬 할 인덱스 가져 오기

배열 / 목록을 정렬하는 인덱스를 얻으려면 간단히 argsort배열 또는 목록을 호출 하면됩니다. 여기 NumPy 버전을 사용하고 있지만 Python 구현은 동일한 결과를 제공해야합니다

>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(arr)
array([1, 2, 0, 3], dtype=int64)

결과에는 정렬 된 배열을 얻는 데 필요한 인덱스가 포함됩니다.

정렬 된 배열은 [1, 2, 3, 4]argsorted 배열이므로 원본에 이러한 요소의 인덱스가 포함됩니다.

  • 가장 작은 값은 원본의 1색인 1에 있으므로 결과의 첫 번째 요소는 1입니다.
  • 2인덱스이며 2결과의 두 번째 요소는 그래서 일본어로 2.
  • 3인덱스이며 0결과의 세번째 요소는 그래서 일본어로 0.
  • 가장 큰 값 4이며 3원본의 색인 에 있으므로 결과의 마지막 요소는 3입니다.

요소가 정렬 된 배열 / 목록에 가질 수있는 지수 얻기

이 경우 argsort 두 번 적용해야합니다 .

>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(np.argsort(arr))
array([2, 0, 1, 3], dtype=int64)

이 경우 :

  • 원본의 첫 ​​번째 요소는 3세 번째로 큰 값이므로 2정렬 된 배열 / 목록에 색인 이 있으므로 첫 번째 요소는2 입니다.
  • 원본의 두 번째 요소는 1가장 작은 값이므로 0정렬 된 배열 / 목록에 색인 이 있으므로 두 번째 요소는 0입니다.
  • 원본의 세 번째 요소 2는, 두 번째로 작은 값이므로 1정렬 된 배열 / 목록에 인덱스 가 있으므로 세 번째 요소는 1입니다.
  • 원본의 네 번째 요소는 4가장 큰 값이므로 3정렬 된 배열 / 목록에 색인 이 있으므로 마지막 요소는 3입니다.

4

다른 답변은 잘못되었습니다.

argsort한 번만 실행 하는 것이 해결책이 아닙니다. 예를 들어, 다음 코드는

import numpy as np
x = [3,1,2]
np.argsort(x)

수율 array([1, 2, 0], dtype=int64)우리가 원하는 것이 아니다.

답은 argsort두 번 실행해야합니다 .

import numpy as np
x = [3,1,2]
np.argsort(np.argsort(x))

array([2, 0, 1], dtype=int64)예상대로 제공합니다 .


귀하의 주장은 x[2](3) 가장 작은 요소와 x[1](1) 가장 큰 요소입니다 (정수를 정렬하면 가장 작은 값에서 가장 큰 값으로 정렬되므로). 또한 OPs 예제에서 단일 np.argsort([1, 2, 3, 100, 5])수익률 array([0, 1, 2, 4, 3])은 OP가 원하는 인덱스로 나타납니다.
0 1

1
@ 0 0 귀하의 예는 특정한 경우입니다. 우리 arr = [1,2,3,100, 5, 9] res = np.argsort(arr) print(res)가 달리면 [0 1 2 4 5 3]어느 것이 잘못되었는지 알게 됩니다.
shahar_m

나는 무엇이 잘못되었는지 불명확하다 : arr[res]yields array([ 1, 2, 3, 5, 9, 100])는 결과 배열이 (증가하는) 순서이기 때문에 완벽하게 괜찮은 것처럼 보인다.
0 0

@ 0 0의 arr=[1,2,3,100, 5, 9]경우 출력이이라고 예상합니다 inds=[0,1,2,5,3,4]. 왜냐하면 요소를 주문하는 순서 (증가)-1은 0, 2는 1, ..., 5는 4 위, 3 위, 9 위 그 출력 ( inds) 을 얻으려면 argsort언급 한 것처럼 두 번 실행해야합니다 .
shahar_m

따라서이 지수는 배열 요소 (0 위, 1 위 등)의 순위입니다. MATLAB에sort 대한 OP의 언급을 감안할 때 OP np.argsort는 일반적으로 사용되는 것과 비슷한 다른 기능을 원한다고 생각합니다 ( arr[np.argsort[arr]]마지막 MATLAB 예제에서와 같이 정렬 된 배열을 얻는 데 사용할 수 있음 ). 귀하의 답변 대신 이 사례 / 질문에 적용됩니다 .
0시

0

numpy를 np로 가져 오기

색인

S=[11,2,44,55,66,0,10,3,33]

r=np.argsort(S)

[output]=array([5, 1, 7, 6, 0, 8, 2, 3, 4])

argsort S의 인덱스를 정렬 된 순서로 반환

가치를 위해

np.sort(S)

[output]=array([ 0,  2,  3, 10, 11, 33, 44, 55, 66])

0

0에서 n-1 사이의 다른 인덱스 배열을 만든 다음 이것을 원래 배열로 압축 한 다음 원래 값을 기준으로 정렬합니다

ar = [1,2,3,4,5]
new_ar = list(zip(ar,[i for i in range(len(ar))]))
new_ar.sort()

`

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.