LoginSignup
40
17

More than 1 year has passed since last update.

はじめに

最近、機械学習ネタを書いていなかったので、久々に、機械学習で記事を書こうとPyCaretを触っていたら色々新機能が増えており、中でも意外と便利な 「ゲインチャート」 が加わっていたので、使い方をご紹介してみたいと思います。

やること

ツールの使い方だけでは面白みが無いので、「ダイレクトマーケティングの効率化」 をお題(想定)としてゲインチャートがどう使えるか?を見て行きます。

設定

販促でお客様にカタログを送付するシナリオを考えます。
特に何も考えなければ、すべてのお客様にカタログを郵送すると思うのですが、やはり
コストがかかります。

本当は、

  • 買う!、買うかも。なお客様にはカタログを郵送。
  • 買わない。なお客様にはカタログは郵送しない。

がうまくコントロール出来ると、コストも下げられますし、エコですし、これを実現したい。
(ユーザ視点でも、不要なカタログは送付不要ですので、CS的にも良いかもです!)

使うデータセット

とは言え、適切なデータセットがあるわけではないので、Kaggleの下記データセットを一部いじって、「ダイレクトマーケティング」 っぽいデータを使った機械学習を進めていきたいと思います。

デモグラフィックデータで、「顧客特性」と「購入金額」を含み、このお題で使えそうです。
データ項目を簡単に確認しておきます。

  • 元々は、#1~#9 の説明変数を用いて、目的変数の#10 支出額を説明、導出する為のデータセットですが
  • 今回のテーマに合わせ分類問題としたいので、、
    一定額以上の高額な支出が 見込めるか?否か? の2値分類としたいと思います。
# 列名 説明 データ
1 Age 顧客の年齢 年配/中年/若年
2 Gender 性別 男性/女性
3 OwnHome 住居 持ち家 or 賃貸
4 Married 結婚 独身 or 既婚
5 Location 家~店舗の距離 遠い/近い
6 Salary 所得 連続値(ドル)
7 Children 子供の人数 連続値(人数)
8 History 過去の購入量 低/中/高
9 Catalogs カタログ送付数 連続値(送付数)
10 AmountSpent 支出額 (目的変数) 連続値(ドル)

では、始めます

Kaggleのデータということで、KaggleのNotebook(Kernel)で進めたいと思います。
Google Colabとかを使う方は、データをダウンロードして頂ければと。

準備

KaggleのNotebookに、PyCaretをpipします。
相性の問題か、3.0RCや2.3の最近のVerだとうまくいかなかったので、2.3.6を使います。

pip install pycaret==2.3.6

そして、必要なものを一式、importしておきます。

import numpy as np
import pandas as pd 
import seaborn as sns
import pycaret
print(pycaret.__version__) # 2.3.6ならOK

データ確認と前処理

まずは、pandasでロードし、データを確認します。
質的データは文字列、量的データは数値で表現されているので、そのままで大丈夫そうです。

df = pd.read_csv("/kaggle/input/direct-marketing/DirectMarketing.csv")
df

image.png

とりあえず、describeしておきます。

df.describe()

image.png

が、目的変数のAmountSpentを観るのに、四分位だと荒いので、、
5%刻みでのパーセンタイルを確認してみようと思います。

df["AmountSpent"].quantile(
    np.arange(
        0.75, #  75%タイルから
        1,    # 100%タイルまで
        0.05  #   5%刻みで表示
    )
)

image.png

sns.histplot(
    df["AmountSpent"],
    bins=20
)

なんとなく、購買金額の上位5%程度の顧客を買う!、買うかも。と見なすとリアリティがありそうです。

image.png

なので、AmountSpent > 3052 のユーザについて、購買フラグ(target)を立てます。

df["Target"] = df["AmountSpent"] > 3052
df["Target"].value_counts()

image.png

最後に、今回は目的変数がAmountSpentではなく、Targetですので、AmountSpentを消しておきます。
合わせて、こういったダイレクトマーケティング向けのデモグラフィーで、顧客の年収(Salary) が入手できているのも正直、違和感はあるのと、リークしそうなので合わせて削除しておきます。

df_train = df.drop(
    columns=
    [
       "AmountSpent",
       "Salary"
    ],
    axis=1
)
df_train

image.png

これで前処理完了です!

PyCaretでモデル作成

では、ここからPyCaretを動かして行きます。まずは、setupなのですが、、
量的変数を正しく認識できるように、numeric_featuresにて、カラム名を指定しておきます。

from pycaret.classification import *
s = setup(
    data=df_train,
    target="Target",
    numeric_features=
    [
        "Children",
        "Catalogs"
    ],
)

image.png

Data Typeが正しいことを確認したので、Enterを押下し、ステップを進めます。
モデルをfittingしていくのですが、評価指標としては、 F-measure(F1)を指定します。

best = compare_models(
    sort="F1"
)
  • 要件として、Precision/Recallのバランスを取りたいので、その調和平均であるF-measureを使います1
  • 今回の学習データは、正例:負例=1:19といった不均衡データで注意が必要ですが、マイノリティを正例としているのでF-measureでも正しく評価できます。
  • なお、そういった事を気にしたく無い場合 MCC(マシューズ相関係数/Matthews Correlation Coefficient) を指定するという方法もあります。

詳細は、下記をご確認ください。

image.png

そして、best estimatorである勾配ブースティング分類器を可視化していきます。

evaluate_model(
    estimator=best
)

これでやっと、今回使いたい、累積ゲインチャートを描く事ができました!

image.png

累積ゲインチャートについて

上記のゲインチャートの縦軸、横軸ですが、下記の通りです。

  • 横軸 : 分類器が予測した「購入しそうな順2」に並んだ顧客
  • 縦軸 : その「顧客」までの累積の反応率(真陽性率・Recall)

image.png

反応率(真陽性率・Recall)とは

実際にP(買う)の顧客のうち、P(買う)と正しく予測できた割合です。


Recall = \frac{TP}{TP + FN} 
= \frac{\color{red}{①正しくP(買う)と予測できた数}}{\color{blue}{②実際にP(買う)の顧客の全量}}

混同行列で見ていくと、、

こんな感じです。ここで、TPとFNの意味について考えてみたいと思います。

  • $ TP $:実際に「買う」お客さんで、予測として「買う」と予測できた。
  • $ FN $:実際に「買う」お客さんだが、予測としては「買わない」と予測してしまった。

となります。では、Recallが100%とはどういった状況でしょうか。

Recallが100% = \frac{TP}{TP + FN}  = \frac{100}{100 + 0}  \Leftrightarrow   FN = 0

式でみれば自明ですが、$ FN $が0人のとき、Recallが100%となります。
つまり、Recall100%で$FN=0$とは、

  • A)実際に、「買う」お客さんの全員を、「買う」と予測した集合($TP + FP$)に含む。
  • B)実際には「買わない」のお客さんだが、「買う」と予測してしまう誤り($FP$)は特に意識しない

ダイレクトマーケティングに応用する

Recallが高い予測モデルを利用すれば、実際に「買う」お客さんを逃すことなく、 DM、カタログ、クーポン等の販促施策を実行できます。
仮に、Recallが高い予測モデルにて、$ P $(買う)と予測された顧客全員に販促施策を実行します。
そのとき、この販促施策はどういった特性を持つかを、先述のA,Bに対応づけて考えると、

  • A)実際に、「買う」お客さんの全員に、DM、カタログ等の販促施策が実行可能
  • B)実際には「買わない」お客さんにも、DM、カタログ等を送ってしまうが、それはしょうがない。

つまり、Aの特性を優先し、想定見込み客の全量に対して販促施策を打つことを優先する。
そういった活用が可能です。

読み解きかた

読み解くのに必要な知識は説明できたので、実際にこのチャートを読み解いていきます。

①上位10%に販促を打つと、ターゲットの60%をカバー可能

まずは、下記を読み解いていきます。
横軸は、分類器が予測した「購入しそうな順」に並んだ顧客ですので、左側の「0.0~0.1」の範囲には、「購入しそうな顧客」のTop10%(優良そうな顧客)が含まれています。
この顧客のトップ10%に、販促を打ったら、「実際に買う」とラベル付された顧客の何%をカバー出来るでしょうか?

そうです、0.1のところの縦軸の値を読み取れば良いのです。
縦軸の値は0.6。つまり、Top10%の顧客での累積のRecallは0.6ですので、販促でターゲットとしたい、実際に購入につながる顧客の60%をカバー出来ることを意味します。

image.png

②上位20%に販促を打つと、ターゲットのすべてをカバー可能3

Top20%に販促を打つと、「実際に買う」とラベル付された顧客の何%をカバー可能でしょうか?
0.2のときの累積Recallは1.0ですので、このモデルにおいてはすべてのターゲットをカバー可能です。3

image.png

③理想の完璧な分類器だと

今回の設定では、P「買う」のラベルのデータは、全体の5%だったので、、
完璧な分類器では、上位5%に販促を打った時点で、Recall100%となります。
つまり、下記の赤線の様な累積ゲインチャートが描かれるのですが、、、

image.png

そんな完璧な分類器は現実的に作成困難で、リークしている可能性が高いので、
今回の結果をどう読み解けばよいかというと、

  • Recall100%を上位5%で言い当てる完璧モデルと比べると、上位20%でRecall100%になる今回のモデルは見劣りするかもしれませんが、、
  • 何も考えずに、すべての顧客に販促を打つ状況から比較すると、上位20%への販促でもRecall100%で全数販促と効果は一緒ですので、カタログ費用や郵送費用は80%削減(出来るかもしれない)

と考えることが出来るのでは無いでしょうか?

まとめ

  • PyCaretのVerUpに伴い追加された、累積ゲインチャートについて説明しました。
  • グラフの見方だけを説明してもつまらないので、ダイレクトマーケティングのトイデータを用いて、販促業務の改善といった例題で、累積ゲインチャートの使い方を見ていきました。
  • トイデータの特性か、かなり性能の良いモデルができてしまい、上位20%でそれまでの累積Recall100%という状況でしたが、考え方はお伝え出来たと思います。
  • ぜひ、皆さんの身近なテーマで、PyCaretを活用いただければと思います。
  • なお、反響があれば、類するテーマで別の記事も書いてみたいと思います。

補足

今回は簡単のために、問題を単純化して扱いましたが、実際には、

  • モデルが重視する特徴量が、現場のマーケターの感覚と一致するか(納得性)
  • 過去の累積データは、今回対象とする商材のマーケティングを説明可能か、適切か?
  • 累積顧客データは基本的に過去からの蓄積されたデータであり、集計期間をどう取扱か?
  • 施策を繰り返す場合に、前回の販促の介入効果を割り引いた検討が必要(差の差等)
  • LTVを考慮した場合の販促検討

等々、色々検討すべき事項はあると思います。

実際の累積ゲイン曲線

利用したトイデータの特性か、今回作ったモデルは、よく出来すぎていました。
実際には、こんな感じとなります。

image.png

つまり、

  • ML予測結果に基づき上位20%に販促を打てば、ターゲットの80%がカバー可能
  • カバー率100%にするためには、残りの80%の顧客(ほぼ全数)に販促を打つ必要があり
    • 残20%のターゲットへの販促は諦める。
    • もしくは、残20%のターゲット向けの販促は別手段(Email等)で実施する。

等々の議論があるかと思います。

image.png

リンク

以前に書いたPyCaretの記事をリンクしておきます。

  1. ダイレクトマーケティングでの活用であれば、Recallが稼げていると、真に購買につながる顧客をカバー出来ていると解釈することができます。一方で、Recallのみを追求すると、Precisionが劣化しクーポンや販促の無駄撃ちが増えるため、モデル構築時は、その両者の調和平均であるF-measureを指定しておきます。

  2. 「購入しそうな順」は、正しくは、モデルのpredict_probaの順を意図しています。

  3. データの特性か、モデルとして良く出来すぎていて、ちょっとリアリティが無いので、気になる方は末尾の補足をご確認ください。 2

40
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
17