파일 Python/NumPy를 사용하여 배열의 항목 순위 지정



파이썬 3차원 배열 (8)

나는 array-by-row (축 = 1)로 배열을 처리한다고 가정하고, 둘 이상의 차원의 배열 A에 대해 두 가지 솔루션을 확장하려고 시도했다.

행에 루프가있는 첫 번째 코드를 확장했습니다. 아마 그것은 향상 될 수있다.

temp = A.argsort(axis=1)
rank = np.empty_like(temp)
rangeA = np.arange(temp.shape[1])
for iRow in xrange(temp.shape[0]): 
    rank[iRow, temp[iRow,:]] = rangeA

그리고 두 번째 것은 k.rooijers 제안에 이어 다음과 같이됩니다.

temp = A.argsort(axis=1)
rank = temp.argsort(axis=1)

무작위로 모양이있는 400 개의 배열을 생성했습니다 (1000,100). 첫 번째 코드는 약 7.5, 두 번째 코드는 3.8을 차지했습니다.

배열 배열을 가지고 있고 첫 번째 배열의 각 항목의 순위를 나타내는 다른 배열을 만들고 싶습니다. 파이썬과 NumPy를 사용하고 있습니다.

예 :

array = [4,2,7,1]
ranks = [2,1,3,0]

다음은 내가 제안한 최선의 방법입니다.

array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]

배열을 두 번 정렬하는 것을 피하는 더 나은 / 더 빠른 방법이 있습니까?


Answer #1

먼저 argsort를 두 번 사용하여 배열의 순서를 얻은 다음 순위를 얻습니다.

array = numpy.array([4,2,7,1])
order = array.argsort()
ranks = order.argsort()

2D (또는 고차원) 배열을 다룰 때 argsort에 축 인수를 전달하여 올바른 축 위에 정렬해야합니다.


Answer #2

평균 순위의 벡터화 된 버전은 아래를 참조하십시오. 나는 np.unique를 좋아합니다. 정말 코드의 범위를 넓히고 효과적으로 벡터화 할 수 없습니다. 파이썬 for-loops를 피하는 것 외에도이 접근법은 'a'에 대한 암시 적 이중 루프를 피합니다.

import numpy as np

a = np.array( [4,1,6,8,4,1,6])

a = np.array([4,2,7,2,1])
rank = a.argsort().argsort()

unique, inverse = np.unique(a, return_inverse = True)

unique_rank_sum = np.zeros_like(unique)
np.add.at(unique_rank_sum, inverse, rank)
unique_count = np.zeros_like(unique)
np.add.at(unique_count, inverse, 1)

unique_rank_mean = unique_rank_sum.astype(np.float) / unique_count

rank_mean = unique_rank_mean[inverse]

print rank_mean

Answer #3

마지막 단계의 왼쪽에서 슬라이스 사용 :

array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.empty_like(temp)
ranks[temp] = numpy.arange(len(array))

이렇게하면 마지막 단계에서 순열을 뒤집어서 두 번 정렬하는 것을 피할 수 있습니다.


Answer #4

이 질문은 몇 년 전의 일이며 받아 들여진 답변은 훌륭하지만 다음 내용은 여전히 ​​가치가 있다고 생각합니다. scipy 대한 의존성에 신경 쓸 필요가 scipy.stats.rankdata 를 사용할 수 있습니다 :

In [22]: from scipy.stats import rankdata

In [23]: a = [4, 2, 7, 1]

In [24]: rankdata(a)
Out[24]: array([ 3.,  2.,  4.,  1.])

In [25]: (rankdata(a) - 1).astype(int)
Out[25]: array([2, 1, 3, 0])

rankdata 의 좋은 특징은 method 인수가 타이를 처리하기위한 몇 가지 옵션을 제공한다는 것입니다. 예를 들어, 20 개의 세 번 발생하고 b 에 40 개의 두 번 발생합니다.

In [26]: b = [40, 20, 70, 10, 20, 50, 30, 40, 20]

기본값은 평균 순위를 묶인 값에 할당합니다.

In [27]: rankdata(b)
Out[27]: array([ 6.5,  3. ,  9. ,  1. ,  3. ,  8. ,  5. ,  6.5,  3. ])

method='ordinal' 연속되는 등급을 지정합니다.

In [28]: rankdata(b, method='ordinal')
Out[28]: array([ 6.,  2.,  9.,  1.,  3.,  8.,  5.,  7.,  4.])

method='min' 은 모든 묶인 값에 연결된 값의 최소 순위를 지정합니다.

In [29]: rankdata(b, method='min')
Out[29]: array([ 6.,  2.,  9.,  1.,  2.,  8.,  5.,  6.,  2.])

더 많은 옵션은 문서화 문자열을 참조하십시오.


Answer #5

우아함과 솔루션의 부족함과는 별도로 성능 문제도 있습니다. 다음은 약간의 벤치 마크입니다.

import numpy as np
from scipy.stats import rankdata
l = list(reversed(range(1000)))

%%timeit -n10000 -r5
x = (rankdata(l) - 1).astype(int)
>>> 128 µs ± 2.72 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

%%timeit -n10000 -r5
a = np.array(l)
r = a.argsort().argsort()
>>> 69.1 µs ± 464 ns per loop (mean ± std. dev. of 5 runs, 10000 loops each)

%%timeit -n10000 -r5
a = np.array(l)
temp = a.argsort()
r = np.empty_like(temp)
r[temp] = np.arange(len(a))
>>> 63.7 µs ± 1.27 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

Answer #6

위의 방법을 시도했지만 실패했습니다. 그렇습니다. 부유물이 있어도 복제물이 중요 할 수 있습니다.

그래서 넥타이 검사 단계를 추가하여 수정 된 1D 솔루션을 작성했습니다.

def ranks (v):
    import numpy as np
    t = np.argsort(v)
    r = np.empty(len(v),int)
    r[t] = np.arange(len(v))
    for i in xrange(1, len(r)):
        if v[t[i]] <= v[t[i-1]]: r[t[i]] = r[t[i-1]]
    return r

# test it
print sorted(zip(ranks(v), v))

나는 그것이 가능한 한 효율적이라고 믿습니다.


Answer #7

argsort ()를 두 번 사용하면됩니다 :

>>> array = [4,2,7,1]
>>> ranks = numpy.array(array).argsort().argsort()
>>> ranks
array([2, 1, 3, 0])




numpy