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.