J'ai deux colonnes de données représentant la même quantité; une colonne provient de mes données d'entraînement, l'autre de mes données de validation.
Je sais comment calculer efficacement le classement en centiles des données de formation en utilisant:
pandas.DataFrame(training_data).rank(pct = True).values
Ma question est la suivante: comment puis-je efficacement obtenir un ensemble similaire de classements en centiles de la colonne de données de validation relative à la colonne de données de formation? C'est-à-dire que, pour chaque valeur de la colonne de données de validation, comment puis-je connaître son classement en centiles par rapport à toutes les valeurs de la colonne de données d'apprentissage?
J'ai essayé de faire ça:
def percentrank(input_data,comparison_data):
rescaled_data = np.zeros(input_data.size)
for idx,datum in enumerate(input_data):
rescaled_data[idx] =scipy.stats.percentileofscore(comparison_data,datum)
return rescaled_data/100
Mais je ne suis pas sûr que ce soit correct, et en plus, c'est incroyablement lent, car il effectue de nombreux calculs redondants pour chaque valeur de la boucle for.
Toute aide serait grandement appréciée!
Voici une solution: Triez les données d'entraînement. Ensuite, utilisez searchsorted sur les données de validation.
import pandas as pd
import numpy as np
# Generate Dummy Data
df_train = pd.DataFrame({'Values': 1000*np.random.Rand(15712)})
#Sort Data
df_train = df_train.sort_values('Values')
# Calculating Rank and Rank_Pct for demo purposes
#but note that it is not needed for the solution
# The ranking of the validation data below does not depend on this
df_train['Rank'] = df_train.rank()
df_train['Rank_Pct']= df_train.Values.rank(pct=True)
# Demonstrate how Rank Percentile is calculated
# This gives the same value as .rank(pct=True)
pct_increment = 1./len(df_train)
df_train['Rank_Pct_Manual'] = df_train.Rank*pct_increment
df_train.head()
Values Rank Rank_Pct Rank_Pct_Manual
2724 0.006174 1.0 0.000064 0.000064
3582 0.016264 2.0 0.000127 0.000127
5534 0.095691 3.0 0.000191 0.000191
944 0.141442 4.0 0.000255 0.000255
7566 0.161766 5.0 0.000318 0.000318
Maintenant, utilisez searchsorted pour obtenir le Rank_Pct des données de validation
# Generate Dummy Validation Data
df_validation = pd.DataFrame({'Values': 1000*np.random.Rand(1000)})
# Note searchsorted returns array index.
# In sorted list rank is the same as the array index +1
df_validation['Rank_Pct'] = (1 + df_train.Values.searchsorted(df_validation.Values))*pct_increment
Voici les premières lignes du fichier de données final df_validation:
print df_validation.head()
Values Rank_Pct
0 307.378334 0.304290
1 744.247034 0.744208
2 669.223821 0.670825
3 149.797030 0.145621
4 317.742713 0.314218
Une petite amélioration par rapport à la solution de Nice ci-dessus consiste à faire la moyenne des positions trouvées en effectuant une recherche à gauche et à partir de la droite:
df_validation['Rank_Pct'] = (0.5 + 0.5*df_train.Values.searchsorted(df_validation.Values, side='left') + 0.5*df_train.Values.searchsorted(df_validation.Values, side='right'))*pct_increment
Ce changement est important dans les cas où une valeur apparaît plusieurs fois. Considérez la recherche de 2 dans [1,2,2,2,4] - la recherche à gauche donne 1, alors que la recherche à droite donne 3. La moyenne des deux donne le même classement en centile que les pandas .rank (pct = True) routine.