Ranking de matriz numpy con posibles duplicados

Tengo una gran cantidad de flotadores / ints y quiero asignar sus elementos a sus filas.

Si una matriz no tiene duplicados, el problema se puede resolver con el siguiente código

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

Ahora quiero extender este método a matrices con posibles duplicados, para que los duplicados se asignen al mismo valor. Por ejemplo, quiero una matriz

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

para ser asignado a cualquiera

0 1 4 5 6 1 7 8 8 1

o para

0 3 4 5 6 3 7 9 9 3

o para

0 2 4 5 6 2 7 8.5 8.5 2

En el primer / segundo caso, asignamos duplicados al rango mínimo / máximo entre ellos si solo aplicamos a2.argsort (). Argsort (). El tercer caso es solo el promedio de los dos primeros casos.

¿Alguna sugerencia?

EDITAR (requisitos de eficiencia)

En la descripción inicial se me olvidó mencionar sobrerequisitos de tiempo. Estoy buscando una solución en términos de funciones numpy / scipy que permitan evitar la "sobrecarga de python pura". Solo para dejarlo claro, considere la solución propuesta por Richard que, de hecho, resuelve el problema pero es bastante lenta:

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

Del análisis anterior se desprende claramente que argsortdup es 30-50 veces más lento que a.argsort (). Argsort (). La razón principal es el uso de bucles y listas de python.

Respuestas a la pregunta(3)

Su respuesta a la pregunta