Si hallas algún fallo con tu código o trabajo, recuerda probar siempre en un ambiente de testing antes aplicar el código al proyecto final.
Solución:
Usando el conjunto de datos de ejemplo del artículo de Wikipedia:
df = pd.DataFrame('C1': 'A': 5, 'B': 2, 'C': 3, 'D': 4,
'C2': 'A': 4, 'B': 1, 'C': 4, 'D': 2,
'C3': 'A': 3, 'B': 4, 'C': 6, 'D': 8)
df
Out:
C1 C2 C3
A 5 4 3
B 2 1 4
C 3 4 6
D 4 2 8
Para cada rango, el valor medio se puede calcular con lo siguiente:
rank_mean = df.stack().groupby(df.rank(method='first').stack().astype(int)).mean()
rank_mean
Out:
1 2.000000
2 3.000000
3 4.666667
4 5.666667
dtype: float64
Entonces la Serie resultante, rank_mean
se puede usar como un mapeo para los rangos para obtener los resultados normalizados:
df.rank(method='min').stack().astype(int).map(rank_mean).unstack()
Out:
C1 C2 C3
A 5.666667 4.666667 2.000000
B 2.000000 2.000000 3.000000
C 3.000000 4.666667 4.666667
D 4.666667 3.000000 5.666667
Ok, implementé el método yo mismo con una eficiencia relativamente alta.
Después de terminar, esta lógica parece un poco fácil pero, de todos modos, decidí publicarla aquí para que cualquiera se sienta confundido como yo cuando no pude buscar en Google el código disponible.
El código está en github: Quantile Normalize
Una cosa que vale la pena notar es que tanto el código de ayhan como el de shawn usan la media de rango más pequeña para los empates, pero si usa el núcleo del proceso del paquete R normalize.quantiles()
usaría la media de las medias de rango para los empates.
Usando el ejemplo anterior:
> df
C1 C2 C3
A 5 4 3
B 2 1 4
C 3 4 6
D 4 2 8
> normalize.quantiles(as.matrix(df))
C1 C2 C3
A 5.666667 5.166667 2.000000
B 2.000000 2.000000 3.000000
C 3.000000 5.166667 4.666667
D 4.666667 3.000000 5.666667