【Python】決定木を使って広告トラフィックから売上を予測するモデルを作成しよう

  • 2022年2月11日
  • 2022年2月11日
  • 統計学

この記事では、プログラミング言語のPythonを使って、売上を目的変数、広告施策からの流入(セッション)を説明変数にした回帰モデルの作成方法を解説しています。データサイエンスの知識をマーケティングに応用したいという方はぜひ参考にご一読ください。

決定木(回帰木)によるモデリングの解説

決定木は、英語で「decision tree(ディシジョンツリー)」と呼ばれ、樹形図の形で分析を行う手法です。決定木には、「分類木」と「回帰木」があり、「商品Aを買うか/買わないか」という区分を行う場合は「分類木」。「○円の商品を買う」といった数値で予測する場合は「回帰木」を用います。

今回の「広告からのセッションから売上を予測する」といった場合は、数値の予測になるので「回帰木」を用いることになります。

具体的には、次のようなイメージで樹形図をもとに予測がされていきます。(※今回扱うダミーデータでは、説明変数となる広告セッションが2よりも多くありますが、ここでの説明を簡略化するために広告A、Bの2つの説明変数として解説します。)

縦軸に「広告Aからのセッション」、横軸に「広告Bからのセッション」、●(ドット)は各広告セッションのときの売上(単位:万円)を表しています。広告Aは5,000セッション、広告Bは2,000と3,000セッションが分岐点となって次のような樹形図で売上が決定されていきます。

決定木での売上の予測の流れがイメージできましたでしょうか。では、ここからは今回のダミーデータをケースにpythonでモデリングをしていきます。

目的の設定(説明変数と目的変数の設定)

pythonでコードを書いていく前に、まず今回の分析の定義をします。下記のように各変数を定義して、回帰モデルを作成します。今回は、約1年間分の日別のマーケティングデータをダミーで用意して分析します。

– 目的変数:「日別売上」
– 説明変数:「各種広告施策から発生したセッション」

ディスプレイ広告や記事広告など様々な広告施策でサイトへのセッション(流入)を作るのですが、お客さんはすぐに購入するわけではなく、そのサービスについて調べて検討をして最終的に購入することが多いはずです。そのため、各広告施策で作ったセッションが最終的にどれだけ売上に影響していたのかを回帰モデルで表してみたいと思います。

分析データの用意

まず、日別売上と各種広告セッションのデータが入ったcsvデータ(ファイルパス名:marketing)を読み込みます。Pythonのライブラリであるpandasをインポートし、read_csv関数を用いて読み込みます。そして読み込んだデータをhead関数で最初の5行を確認してみましょう。

import pandas as pd
data = pd.read_csv('marketing')
data.head()

その結果がこちらです。

正しくテーブルデータが読み込めていることを確認できました。

前処理:欠損値の除去

データ内に欠損値(何も値が入っていない項目)があるかをisna関数を用いて調べてみます。

#insa関数で欠損値を特定し、sum関数でその総計値を出す
data.isna().sum()

結果は次のようになり、”Google_Ad”に7つの欠損値が発見されました。

今回は、「Google_Ad」に含まれている欠損値を中央値で埋めて対応します。

#filna関数でGoogle_Adにある欠損値をmedian(中央値)で埋める。結果を反映したデータを変数「marketing2」に代入
marketing2= marketing.fillna(data['Google_Ad'].median()

説明変数と目的変数の分割

次にデータを説明変数と目的変数に分けて用意します。データを分割する際は、drop関数を使います。

#説明変数X: drop関数でdateとSalesの列を削除し、説明変数となる広告セッションだけのデータにする
X_marketing2 = marketing2.drop(['date','Sales'], axis=1)
#目的変数y: 目的変数であるSalesだけの列を抽出する
y_marketing2 = marketing2['Sales']

#正しく分割できたかを確かめる
display(X_marketing2.head())
print(y_marketing2.head())

正しく分割できていることが確認できました。

学習用データと訓練用データの用意

今回はデータを学習用と検証用に分けるシンプルな「ホールドアウト法」で検証します。説明変数と目的変数にも分けたデータを更に「学習用(train)」と「検証用(test)」にデータを分けます。学習用データでモデルを作り、検証用データで予測と精度の評価を行います。(目的変数とどれくらい差があったのか)

機械学習ライブラリのsklearnのmodel_selectionモジュールの中のtrain_test_split関数を使い、学習用と検証用にデータを分けます。その結果を.shape関数で確認します。

#ライブラリの宣言
from sklearn.model_selection import train_test_split

#説明変数と目的変数をそれぞれ,trainのX,testのX,trainのy,testのyに分ける
X_marketing2_train , X_marketing2_test , y_marketing2_train , y_marketing2_test = train_test_split(X_marketing2 , y_marketing2 , random_state=0)

#trainとtestの形を確認して分けられていることを確認
print(marketing2.shape)
print(X_marketing2_train.shape , X_marketing2_test.shape , y_marketing2_train.shape , y_marketing2_test.shape)

出力結果は次のようになりました。(※解説がわかりやすいように実際の出力結果にコメントを加えています。)
(328, 8) ・・・marketing2.shape
(246, 6) ・・・X_marketing2_train.shape
(82, 6) ・・・X_marketing2_test.shape
(246,) ・・・y_marketing2_train.shape
(82,) ・・・y_marketing2_test.shape

(行、列)と読むので、train:学習データは246行、test:訓練データは82行に分けられたことがわかります。

モデルの学習

次にモデルを定義して学習をします。ランダムフォレストの回帰のライブラリの「RandomForestRegressor」をインポートします。モデルを定義して学習用データに対して学習させます。モデルの精度を学習用と検証用でそれぞれ出します。モデルの精度を評価するために.score関数を使いますが、このときのスコア結果は決定係数(R2)を表します。

#ライブラリの宣言をします
from sklearn.ensemble import RandomForestRegressor
# モデルを定義して,学習させます.
model_marketing2 = RandomForestRegressor(n_estimators=100,random_state=0)
model_marketing2.fit(X_marketing2_train,y_marketing2_train)
#モデルの精度を出します
print("学習用データのスコアは",model_marketing2.score(X_marketing2_train,y_marketing2_train))
print("検証用データのスコアは",model_marketing2.score(X_marketing2_test,y_marketing2_test))
  • 学習用データのスコアは 0.9281548656583569
  • 検証用データのスコアは 0.5216972689478341

学習用データでは、0.928と高い精度になっていますが、検証用データでは、0.521と下がりかなり差が出てしまいました。精度の改善策としては、説明変数の数を減らし、より当てはまりの良いモデルに調整していくということが考えられます。

また、決定係数意外にも評価指標として以下のようなものもあります。
・平均二乗誤差(MSE) mean_squared_error関数
・RMSE:MSEの平方根
・平均絶対値誤差(MAE)mean_absolute_error関数

おまけ:交差検証

最後におまけとして、交差検証の方法も紹介しておきます。

#ライブラリの宣言
from sklearn.model_selection import cross_val_score
#交差検証をする
cv_model_marketing2 = cross_val_score(model_marketing2,X_marketing2,y_marketing2,cv=5)
print(cv_model_marketing2)
#結果を評価する
print(cv_model_marketing2.mean())
print(cv_model_marketing2.std())
[0.20348769 0.42764434 0.37839869 0.27021866 0.12382514]
0.2807149047815202
0.11119261975945274

平均28%、標準偏差が±1%のブレということがわかりました。残念ながらこれも今回はあまり良い精度が出ませんでしたね。