web-dev-qa-db-ja.com

Pythonでリフトチャート(別名ゲインチャート)を作成する方法は?

私はscikit-learnを使用して、クライアントが何らかのオファーに応答する可能性を推定するモデルを作成しました。今、モデルを評価しようとしています。そのために、リフトチャートをプロットします。私はリフトの概念を理解していますが、実際にPythonでそれを実装する方法を理解するのに苦労しています。

16
Abhishek Arora

リフト/累積ゲインチャートは、モデルを評価するための良い方法ではありません(モデル間の比較に使用できないため)。代わりに、リソースが有限の場合の結果を評価する手段です。各結果(マーケティングシナリオで)を実行するためのコストがあるため、または一定数の保証された有権者を無視し、フェンスにあるもののみを実行するためです。モデルが非常に優れており、すべての結果に対して高い分類精度を備えている場合、自信を持って結果を順序付けすることであまり効果が得られません。

import sklearn.metrics
import pandas as pd

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

メソッドは次のようになります。最初にデータをビンにソートし、信頼度順に並べます。このメソッドは、視覚化に使用されるデータフレームを返します。

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

累積ゲインチャートをプロットするには、次のコードを使用できます。

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

リフトを視覚化するには:

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

結果は次のようになります。

Cumulative Gains Chart

これらのWebサイトは参照に役立つことがわかりました。

編集:

MSリンクはその説明でやや誤解を招くものでしたが、Paul Te Braakリンクは非常に有益です。コメントに回答するには;

上記の累積ゲインチャートの@Tanguyでは、すべての計算はその特定のモデルの精度に基づいています。 Paul Te Braakリンクが指摘しているように、私のモデルの予測精度はどのようにして100%(チャートの赤い線)に達することができますか?最良のシナリオ(緑の線)は、赤線が母集団全体で達成するのと同じ精度にどれだけ早く到達できるか(たとえば、最適な累積ゲインシナリオ)です。青色は、母集団の各サンプルの分類をランダムに選択した場合です。したがって、累積ゲインとリフトチャートは、purelyであり、そのモデル(およびそのモデルのみ)が、私がいるシナリオでより大きな影響を与える方法を理解するために人口全体とやり取りするつもりはありません。

累積ゲインチャートを使用したシナリオの1つは、上位Xパーセントについて、基本的に無視または優先順位付けできるアプリケーションの数(モデルが予測できることを知っているため)を知りたい詐欺の場合です。その場合、「平均モデル」では、代わりに実際の順序付けされていないデータセットから分類を選択しました(既存のアプリケーションがどのように処理されているか、モデルを使用して、アプリケーションの種類に優先順位を付けることができます)。

したがって、モデルを比較するには、ROC/AUCに固執し、選択したモデルに満足したら、累積ゲイン/リフトチャートを使用して、データに対する反応を確認します。

16
Ian

scikit-plot パッケージを使用して、面倒な作業を行うことができます。

skplt.metrics.plot_cumulative_gain(y_test, predicted_probas)


# 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()

これにより、次のようなプロットが表示されます。 enter image description here

24
Jonny Brooks