web-dev-qa-db-fra.com

Comment construire un graphique d'ascenseur (a.k.a gains chart) en Python?

Je viens de créer un modèle à l'aide de scikit-learn qui estime la probabilité de réponse probable d'un client à une offre. Maintenant j'essaie d'évaluer mon modèle. Pour cela, je veux tracer le graphique d'ascenseur. Je comprends le concept de l'ascenseur, mais j'ai du mal à comprendre comment l'implémenter réellement en python.

16
Abhishek Arora

Les graphiques de gains/gains cumulatifs ne sont pas un bon moyen d'évaluer un modèle (car ils ne peuvent pas être utilisés pour la comparaison entre les modèles), mais sont plutôt un moyen d'évaluer les résultats lorsque vos ressources sont limitées. Soit parce qu'il y a un coût à l'action pour chaque résultat (dans un scénario marketing) ou que vous voulez ignorer un certain nombre d'électeurs garantis, et n'agir que sur ceux qui sont sur la clôture. Lorsque votre modèle est très bon et a une grande précision de classification pour tous les résultats, vous n'obtiendrez pas beaucoup d'efforts pour commander vos résultats en toute confiance.

import sklearn.metrics
import pandas as pd

def calc_cumulative_gains(df: pd.DataFrame, actual_col: str, predicted_col:str, probability_col:str):

La méthode ressemble à ce qui suit, triant d'abord les données dans des bacs et triant par confiance. La méthode renvoie une trame de données à utiliser pour la visualisation.

df.sort_values(by=probability_col, ascending=False, inplace=True)

subset = df[df[predicted_col] == True]

rows = []
for group in np.array_split(subset, 10):
    score = sklearn.metrics.accuracy_score(group[actual_col].tolist(),
                                               group[predicted_col].tolist(),
                                               normalize=False)

    rows.append({'NumCases': len(group), 'NumCorrectPredictions': score})

lift = pd.DataFrame(rows)

#Cumulative Gains Calculation
lift['RunningCorrect'] = lift['NumCorrectPredictions'].cumsum()
lift['PercentCorrect'] = lift.apply(
    lambda x: (100 / lift['NumCorrectPredictions'].sum()) * x['RunningCorrect'], axis=1)
lift['CumulativeCorrectBestCase'] = lift['NumCases'].cumsum()
lift['PercentCorrectBestCase'] = lift['CumulativeCorrectBestCase'].apply(
    lambda x: 100 if (100 / lift['NumCorrectPredictions'].sum()) * x > 100 else (100 / lift[
        'NumCorrectPredictions'].sum()) * x)
lift['AvgCase'] = lift['NumCorrectPredictions'].sum() / len(lift)
lift['CumulativeAvgCase'] = lift['AvgCase'].cumsum()
lift['PercentAvgCase'] = lift['CumulativeAvgCase'].apply(
    lambda x: (100 / lift['NumCorrectPredictions'].sum()) * x)

#Lift Chart
lift['NormalisedPercentAvg'] = 1
lift['NormalisedPercentWithModel'] = lift['PercentCorrect'] / lift['PercentAvgCase']

return lift

Pour tracer le graphique des gains cumulés, vous pouvez utiliser ce code ci-dessous.

import matplotlib.pyplot as plt
def plot_cumulative_gains(lift: pd.DataFrame):
    fig, ax = plt.subplots()
    fig.canvas.draw()

    handles = []
    handles.append(ax.plot(lift['PercentCorrect'], 'r-', label='Percent Correct Predictions'))
    handles.append(ax.plot(lift['PercentCorrectBestCase'], 'g-', label='Best Case (for current model)'))
    handles.append(ax.plot(lift['PercentAvgCase'], 'b-', label='Average Case (for current model)'))
    ax.set_xlabel('Total Population (%)')
    ax.set_ylabel('Number of Respondents (%)')

    ax.set_xlim([0, 9])
    ax.set_ylim([10, 100])

    labels = [int((label+1)*10) for label in [float(item.get_text()) for item in ax.get_xticklabels()]]

    ax.set_xticklabels(labels)

    fig.legend(handles, labels=[h[0].get_label() for h in handles])
    fig.show()

Et pour visualiser l'ascenseur:

def plot_lift_chart(lift: pd.DataFrame):
    plt.figure()
    plt.plot(lift['NormalisedPercentAvg'], 'r-', label='Normalised \'response rate\' with no model')
    plt.plot(lift['NormalisedPercentWithModel'], 'g-', label='Normalised \'response rate\' with using model')
    plt.legend()
    plt.show()

Le résultat ressemble à:

Cumulative Gains Chart

J'ai trouvé ces sites Web utiles comme référence:

Modifier:

J'ai trouvé le lien MS quelque peu trompeur dans ses descriptions, mais le lien Paul Te ​​Braak est très informatif. Pour répondre au commentaire;

@Tanguy pour le graphique des gains cumulés ci-dessus, tous les calculs sont basés sur la précision de ce modèle spécifique. Comme le note le lien Paul Te ​​Braak, comment la précision de prédiction de mon modèle peut-elle atteindre 100% (la ligne rouge dans le graphique)? Le meilleur scénario (la ligne verte) est la vitesse à laquelle nous pouvons atteindre la même précision que la ligne rouge atteint au cours de l'ensemble de la population (par exemple notre scénario de gains cumulatifs optimaux). Le bleu est si nous choisissons simplement au hasard la classification de chaque échantillon de la population. Ainsi, les gains cumulatifs et les graphiques de portance sont purement pour comprendre comment ce modèle (et ce modèle uniquement) me donnera plus d'impact dans un scénario où je suis ne va pas interagir avec l'ensemble de la population.

Un scénario que j'ai utilisé le graphique des gains cumulatifs concerne les cas de fraude, où je veux savoir combien d'applications nous pouvons essentiellement ignorer ou hiérarchiser (parce que je sais que le modèle les prédit aussi bien que possible) pour les X pour cent supérieurs. Dans ce cas, pour le `` modèle moyen '', j'ai plutôt sélectionné la classification dans l'ensemble de données réel non ordonné (pour montrer comment les applications existantes étaient traitées et comment - en utilisant le modèle - nous pourrions plutôt hiérarchiser les types d'application).

Donc, pour comparer les modèles, restez avec ROC/AUC, et une fois que vous êtes satisfait du modèle sélectionné, utilisez le graphique des gains/portance cumulés pour voir comment il répond aux données.

16
Ian

Vous pouvez utiliser le paquet scikit-plot pour faire le gros du travail.

skplt.metrics.plot_cumulative_gain(y_test, predicted_probas)

Exemple

# The usual train-test split mumbo-jumbo
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, 
test_size=0.33)
nb = GaussianNB()
nb.fit(X_train, y_train)
predicted_probas = nb.predict_proba(X_test)

# The magic happens here
import matplotlib.pyplot as plt
import scikitplot as skplt
skplt.metrics.plot_cumulative_gain(y_test, predicted_probas)
plt.show()

Cela devrait entraîner un tracé comme celui-ci: enter image description here

24
Jonny Brooks