다음 코드를 고려하십시오.
avgDists = np.array([1, 8, 6, 9, 4])
ids = avgDists.argsort()[:n]
이것은 나에게 n
가장 작은 요소의 지표를 제공 합니다. 가장 높은 원소 argsort
의 인덱스를 얻기 위해 이것을 내림차순 으로 사용할 수 n
있습니까?
답변
배열을 무효화하면 가장 낮은 요소가 가장 높은 요소가되고 그 반대도 마찬가지입니다. 따라서 n
가장 높은 요소 의 지수는 다음 과 같습니다.
(-avgDists).argsort()[:n]
의견 에서 언급했듯이 이것에 대해 추론하는 또 다른 방법 은 큰 요소가 argsort 에서 마지막 에 오는 것을 관찰하는 것입니다. 따라서 argsort의 꼬리에서 읽어 n
가장 높은 요소 를 찾을 수 있습니다.
avgDists.argsort()[::-1][:n]
두 방법 모두 시간 복잡성에서 O (n log n) 입니다 argsort
. 여기서 호출은 지배적 인 용어 이기 때문 입니다. 그러나 두 번째 접근 방식은 배열 의 O (n) 부정을 O (1) 슬라이스로 대체합니다 . 루프 내부의 작은 배열을 사용하는 경우 해당 부정을 피함으로써 성능이 약간 향상 될 수 있으며, 큰 배열을 사용하는 경우 부정이 전체 배열의 복사본을 생성하므로 메모리 사용량을 절약 할 수 있습니다.
이러한 메소드가 항상 동등한 결과를 제공하지는 않습니다. argsort
예를 들어 키워드 인수를 전달하여 안정적인 정렬 구현이 요청 된 kind='mergesort'
경우 첫 번째 전략은 정렬 안정성을 유지하지만 두 번째 전략은 안정성을 잃습니다 (예 : 항목이 반전됩니다).
타이밍 예 :
100 개의 부동 소수점과 길이가 30 인 작은 배열을 사용하면 뷰 방법이 약 15 % 빨랐습니다.
>>> avgDists = np.random.rand(100)
>>> n = 30
>>> timeit (-avgDists).argsort()[:n]
1.93 µs ± 6.68 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> timeit avgDists.argsort()[::-1][:n]
1.64 µs ± 3.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> timeit avgDists.argsort()[-n:][::-1]
1.64 µs ± 3.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
더 큰 배열의 경우, argsort가 지배적이며 상당한 타이밍 차이가 없습니다.
>>> avgDists = np.random.rand(1000)
>>> n = 300
>>> timeit (-avgDists).argsort()[:n]
21.9 µs ± 51.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> timeit avgDists.argsort()[::-1][:n]
21.7 µs ± 33.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> timeit avgDists.argsort()[-n:][::-1]
21.9 µs ± 37.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
유의하시기 바랍니다 네딤에서 주석 아래 올바르지 않습니다. 역전 전후에 절단해야하는지 여부는 효율성에 차이가 없습니다. 두 작업 모두 어레이의보기 만 다르게 진행하고 실제로 데이터를 복사하지 않기 때문입니다.
답변
그냥 파이썬과 같은, 즉에 [::-1]
의해 반환 된 배열을 반전 argsort()
하고 [:n]
마지막 n 개의 요소를 제공합니다 :
>>> avgDists=np.array([1, 8, 6, 9, 4])
>>> n=3
>>> ids = avgDists.argsort()[::-1][:n]
>>> ids
array([3, 1, 2])
이 방법의 장점은 avgDists ids
의 관점 입니다.
>>> ids.flags
C_CONTIGUOUS : False
F_CONTIGUOUS : False
OWNDATA : False
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
( ‘거짓’인 ‘OWNDATA’는 이것이 사본이 아니라보기임을 나타냅니다)
이를 수행하는 다른 방법은 다음과 같습니다.
(-avgDists).argsort()[:n]
문제는 이것이 작동하는 방식이 배열의 각 요소에 대해 음수를 만드는 것입니다.
>>> (-avgDists)
array([-1, -8, -6, -9, -4])
ANd는이를 위해 사본을 작성합니다.
>>> (-avgDists_n).flags['OWNDATA']
True
따라서 매우 작은 데이터 세트로 각각 시간을 정하면 다음과 같습니다.
>>> import timeit
>>> timeit.timeit('(-avgDists).argsort()[:3]', setup="from __main__ import avgDists")
4.2879798610229045
>>> timeit.timeit('avgDists.argsort()[::-1][:3]', setup="from __main__ import avgDists")
2.8372560259886086
보기 방법이 훨씬 빠릅니다 (메모리의 1/2 사용 …)
답변
당신은 플립 명령을 사용할 수 있습니다 numpy.flipud()
또는 numpy.fliplr()
사용하여 정렬 한 후 내림차순으로 인덱스를 얻기 위해 argsort
명령을 사용합니다. 그게 내가 보통하는 일입니다.
답변
가장 낮은 / 가장 높은 n 요소의 인덱스 만 필요한 경우 np.argsort
사용 하는 대신 사용할 수 있습니다 np.argpartition
.
전체 배열을 정렬 할 필요는 없지만 필요한 부분 만 정렬 할 필요가 있지만 “파티션 내부의 순서”는 정의되어 있지 않으므로 올바른 인덱스를 제공하지만 올바르게 정렬되지 않을 수 있습니다.
>>> avgDists = [1, 8, 6, 9, 4]
>>> np.array(avgDists).argpartition(2)[:2] # indices of lowest 2 items
array([0, 4], dtype=int64)
>>> np.array(avgDists).argpartition(-2)[-2:] # indices of highest 2 items
array([1, 3], dtype=int64)
답변
배열의 복사본을 만든 다음 각 요소에 -1을 곱할 수 있습니다.
결과적으로 이전의 가장 큰 요소가 가장 작아집니다.
사본에서 n 개의 가장 작은 요소의 수는 원본에서 n 개의 가장 큰 요소입니다.
답변
@ Kanmani가 암시 한 것처럼 numpy.flip
다음과 같이 구현을 해석하기가 더 쉽습니다 .
import numpy as np
avgDists = np.array([1, 8, 6, 9, 4])
ids = np.flip(np.argsort(avgDists))
print(ids)
멤버 함수가 아닌 방문자 패턴을 사용하면 작업 순서를 쉽게 읽을 수 있습니다.
답변
예를 들면 다음과 같습니다.
avgDists = np.array([1, 8, 6, 9, 4])
n 최대 값의 인덱스를 구하십시오.
ids = np.argpartition(avgDists, -n)[-n:]
내림차순으로 정렬하십시오.
ids = ids[np.argsort(avgDists[ids])[::-1]]
결과 얻기 (n = 4의 경우) :
>>> avgDists[ids]
array([9, 8, 6, 4])
