はじめに
自分が今、Saasベンダーに勤めております。
初めて自社製品を利用するユーザー向けに新しいオンボーディングのガイドを設計することが現在の主な仕事です。
したがって、現在のオンボーディングにおける各設定項目の中でどの項目がPaid率への影響が大きいかを分析し、メインの改善内容に示唆だしたいと思います。
分析の目的
オンラインユーザー活躍度とPaid率を向上させるため、優先的に取り掛かるべき行動を見出すことです。
実行環境
パソコン:MacBook Pro
開発環境:Google Coraboratory
言語:Python
ライブラリ:Pandas、Numpy、Matplotlib
分析の流れ
- csvデータの準備
- モデルの選択
- データの前処理
- ロジステック分析の実行
- グラフによる可視化
1. csvデータの準備
オンボーディングの各項目の設定状況とPaidステータスのデータは自社BIツールからダウンロードしたものです。
利用するデータ(一部抜粋)
全部で8450本記録です。
※一部モザイクをかけています。
2. モデルの選択
分析したい内容:各項目の設定状況がPaidの有無にどれぐらい影響あるか
説明変数:各項目の設定状況
目的変数:Paid状態
目的変数のPaid状態はPaidとUnPaid2つしかないので、ロジスティック回帰を使うことにしました。
3. データの前処理
必要なライブラリをインポートする
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
ファイルを読み込む
df = pd.read_csv('/content/onbo.csv')
df
データを出力してみると、*FirstOrderDate* の欄に空値があることがわかりました。
左から4列目からは各項目になります。中にはUndone,BeforePaid,AfterPaidの値が入っています。
念の為、その他の列に空値があるかを確認します。
空値の確認
df.isnull().sum()
出力結果は以下になります。
FirstOrderDate以外に、ProjectCreatTime列にも空値があります。
ただし、今回の説明変数にProjectCreatTimeを使いませんので、特に処理しなくても良いです。
データの変換
FirstOrderDateの列は
・値がある=Paidした
・空値=Paidしていない
また、項目の列は
・Undone=設定していない
・BeforePaid=Paidになる前で設定した
・AfterPaid=Paidになった後で設定した
そこで、FirstOrderDateの空値を0に、空値ではないところを1に変換します。
df['First Order Start Date'] = df['First Order Start Date'].apply(lambda x: 0 if pd.isnull(x) else 1)
各項目の列に、以下の様にデータを変換します。
・Undoneを0に
・BeforePaidを1に
・AfterPaidを2に
df = df.replace({'Undone':0,'Before Paid':1,'After Paid':2})
分析する際に、ProjectIDとProjectCreateTimeの2列を使わないので、削除します。
FirstOrderDateの名前をPaidStatusに変更します。
df = df.drop(['Project ID',' Project Create Time'], axis = 1)
df = df.rename(columns = {'First Order Start Date':'Paid Status'})
df.head()
このようにきれいなデータが完成です。
4. ロジステック分析の実行
データの分割
モデルの選択節では、以下を説明しましたので、
その通り説明変数と目的変数を定義し、データを学習用と検証用に分割します。
説明変数:各項目の設定状況
目的変数:Paid状態
x = df.drop('Paid Status', axis = 1)
y = df['Paid Status']
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3, random_state= 5)
説明変数の標準化
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(x_train)
x_train_std = sc.transform(x_train)
x_test_std = sc.transform(x_test)
分析を実行
model = LogisticRegression()
model.fit(x_train_std, y_train)
print(model.coef_)
print(model.intercept_)
Datacenterの項目を完了したユーザーがPaidに至る確率は高い傾向が見受けられます。
モデルを評価する
model.score(x_train, y_train)
ロジスティック回帰の場合、mode.score()ではAccuracyを返します。
一見したところAccuracyが高いです。
他の指標も使ってモデルを評価してみます。
from sklearn.metrics import (
confusion_matrix,
precision_score,
recall_score,
roc_auc_score,
f1_score)
print(confusion_matrix(y_test,model.predict(x_test_std)))
print(f'precision: {precision_score(y_test,model.predict(x_test_std))}')
print(f'recall: {recall_score(y_test,model.predict(x_test_std))}')
print(f'roc_auc: {roc_auc_score(y_test,model.predict(x_test_std))}')
print(f'f1_score: {f1_score(y_test,model.predict(x_test_std))}')
出力の結果
適合率は微妙ですが、ROC-AUCは高い傾向が見受けられます。
Precision(適合率): 0.916 (92%)
陽性と予測したもののうち、実際に陽性だった割合
Recall(再現率): 0.422 (42%)
実際の陽性のうち、正しく陽性と予測できた割合
ROC-AUC: 0.710 (71%)
モデルの全体的な識別能力
F1スコア: 0.578 (58%)
PrecisionとRecallの調和平均
次はROC曲線を出してみます。
from sklearn.metrics import roc_curve, auc
#検証データがクラス1に属する確率
y_score = model.predict_proba(x_test_std)[:, 1]
#ROC曲線のデータを計算
fpr, tpr, thresholds = roc_curve(y_true=y_test, y_score=y_score)
#ROC曲線のプロット
plt.plot(fpr, tpr, label='roc curve (area = %0.3f)' % auc(fpr, tpr))
plt.plot([0, 1], [0, 1], linestyle='--', label='random')
plt.plot([0, 0, 1], [0, 1, 1], linestyle='--', label='ideal')
#グラフの設定
plt.legend()
plt.xlabel('false positive rate')
plt.ylabel('true positive rate')
plt.show()
指標 | 値 | 解釈 |
---|---|---|
AUC (曲線下面積) | 0.931 | 優れた識別能力 |
理想曲線との乖離 | 小さい | ほぼ最適に近い性能 |
ランダム予測差 | 43% | (0.930 - 0.5) × 100 |
5. グラフによる可視化
feature_names = x.columns
feature_importance = pd.DataFrame({'feature': feature_names, 'importance': model.coef_[0]})
feature_importance = feature_importance.sort_values('importance', ascending=False)
plt.figure(figsize=(10, 6))
sns.barplot(x='importance', y='feature', data=feature_importance)
plt.title('Feature Importance')
plt.show()
print("\n各項目の重要性:")
print(feature_importance)
出力結果
結論
目的変数のPaidに対して、Datacenterは最も重要度が高く、Heatmapの重要度が低いという結果になりました。
ただし、heatmapは自社製品の主軸機能になりますので、オンボーディング段階では捨てるわけにはいけません。
-0.01という結果から、オンボーディングにおけるheatmap項目の改善を急ぐべきという示唆が得られると思います。