web-dev-qa-db-fra.com

Comment calculer le classement en pourcentage d'une colonne de données par rapport à une autre colonne à l'aide de python

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!

5
Doodles

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
9
B. Shieh

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.

1
user3098048