Ranking tablicy numpy z możliwymi duplikatami

Mam tablicę liczbową floatów / intów i chcę zmapować jej elementy do ich rang.

Jeśli tablica nie ma duplikatów, problem można rozwiązać za pomocą następującego kodu

In [49]: a1
Out[49]: array([ 0.1,  5.1,  2.1,  3.1,  4.1,  1.1,  6.1,  8.1,  7.1,  9.1])

In [50]: a1.argsort().argsort()
Out[50]: array([0, 5, 2, 3, 4, 1, 6, 8, 7, 9])

Teraz chcę rozszerzyć tę metodę na tablice z możliwymi duplikatami, tak aby duplikaty były mapowane do tej samej wartości. Na przykład chcę tablicę a

a2 = np.array([0.1, 1.1, 2.1, 3.1, 4.1, 1.1, 6.1, 7.1, 7.1, 1.1])

być zmapowane do jednego z nich

0 1 4 5 6 1 7 8 8 1

lub

0 3 4 5 6 3 7 9 9 3

lub

0 2 4 5 6 2 7 8.5 8.5 2

W pierwszym / drugim przypadku mapujemy duplikaty do minimalnej / maksymalnej rangi wśród nich, jeśli zastosujemy po prostu a2.argsort (). Argsort (). Trzeci przypadek to tylko średnia z dwóch pierwszych przypadków.

Jakieś sugestie?

EDIT (wymagania dotyczące wydajności)

W początkowym opisie zapomniałem o tym wspomniećwymagania czasowe. Szukam rozwiązania w zakresie funkcji numpy / scipy, które pozwolą uniknąć „czystego narzutu Pythona”. Aby to wyjaśnić, rozważ rozwiązanie zaproponowane przez Richarda, które faktycznie rozwiązuje problem, ale jest dość powolne:

def argsortdup(a1):
  sorted = np.sort(a1)
  ranked = []
  for item in a1:
    ranked.append(sorted.searchsorted(item))
  return np.array(ranked)

In [86]: a2 = np.array([ 0.1,  1.1,  2.1,  3.1,  4.1,  1.1,  6.1,  7.1,  7.1,  1.1])

In [87]: %timeit a2.argsort().argsort()
1000000 loops, best of 3: 1.55 us per loop

In [88]: %timeit argsortdup(a2)
10000 loops, best of 3: 25.6 us per loop

In [89]: a = np.arange(0.1, 1000.1)

In [90]: %timeit a.argsort().argsort()
10000 loops, best of 3: 24.5 us per loop

In [91]: %timeit argsortdup(a)
1000 loops, best of 3: 1.14 ms per loop

In [92]: a = np.arange(0.1, 10000.1)

In [93]: %timeit a.argsort().argsort()
1000 loops, best of 3: 303 us per loop

In [94]: %timeit argsortdup(a)
100 loops, best of 3: 11.9 ms per loop

Z powyższej analizy jasno wynika, że ​​argsortdup jest 30-50 razy wolniejszy niż a.argsort (). Argsort (). Głównym powodem jest użycie pętli Pythona i list.

questionAnswers(3)

yourAnswerToTheQuestion