Ranking des Numpy-Arrays mit möglichen Duplikaten

Ich habe eine ganze Reihe von Floats / Ints und möchte deren Elemente in ihre Reihen einordnen.

Wenn ein Array keine Duplikate enthält, kann das Problem durch den folgenden Code behoben werden

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])

Jetzt möchte ich diese Methode auf Arrays mit möglichen Duplikaten erweitern, damit Duplikate auf den gleichen Wert abgebildet werden. Zum Beispiel möchte ich ein Array

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

entweder zugeordnet werden

0 1 4 5 6 1 7 8 8 1

oder zu

0 3 4 5 6 3 7 9 9 3

oder zu

0 2 4 5 6 2 7 8.5 8.5 2

Im ersten / zweiten Fall ordnen wir Duplikate dem minimalen / maximalen Rang unter ihnen zu, wenn wir nur a2.argsort (). Argsort () anwenden. Der dritte Fall ist nur der Durchschnitt der ersten beiden Fälle.

Irgendwelche Vorschläge?

EDIT (Effizienzanforderungen)

In der Erstbeschreibung habe ich vergessen zu erwähnenZeitbedarf. Ich bin auf der Suche nach einer Lösung in Bezug auf Numpy / Scipy-Funktionen, mit der "reiner Python-Overhead" vermieden werden kann. Betrachten Sie zur Verdeutlichung die von Richard vorgeschlagene Lösung, die das Problem tatsächlich löst, aber recht langsam ist:

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

Aus der obigen Analyse geht hervor, dass argsortdup 30-50-mal langsamer ist als a.argsort (). Argsort (). Der Hauptgrund ist die Verwendung von Python-Loops und -Listen.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage