こんにちは、のっくんです。
今日は機械学習を使って営業活動(マーケティング)が成功するか予測するためのコードを書いていきたいと思います。
年齢や学歴、結婚の有無、年間の支出、持ち家の有無などの個人情報から、銀行口座を開設したか(yes or no)を与えて機械学習を行うことで、統計的に営業活動が成功しやすい人としにくい人をAIで判別します。
収入が無い人に銀行口座の開設を進めても意味がないことは人間でも分かりますが、機械学習では更に高度な複数の要素を分析するのが得意です。
予めAIで営業活動が成功しやすいクライアントを予想することで、営業チームはクライアントを絞って営業活動をすることができるので無駄な営業を省略しやすくなります。
企業にとっては無駄なリソースの削減ができ、集中して有望なクライアントにフォーカスできるので営業成績が上がることも間違いありません。
それでは実際にどうやってやるのか見ていきましょう。
[toc]データセット
使用するデータは以下の通り。
UCIマシンラーニングレポジトリからデータを取得します。
アカウント作成をしなくても自由に誰でもダウンロードできます。

https://archive.ics.uci.edu/ml/datasets/bank+marketing
データ数は45211で、属性は17個です。
データが提供されたのが2012年2月14日です。
以下が属性の1部です。
1 - age (numeric) 2 - job : type of job (categorical: 'admin.','blue-collar','entrepreneur','housemaid','management','retired','self-employed','services','student','technician','unemployed','unknown') 3 - marital : marital status (categorical: 'divorced','married','single','unknown'; note: 'divorced' means divorced or widowed) 4 - education (categorical: 'basic.4y','basic.6y','basic.9y','high.school','illiterate','professional.course','university.degree','unknown') 5 - default: has credit in default? (categorical: 'no','yes','unknown') 6 - housing: has housing loan? (categorical: 'no','yes','unknown') 7 - loan: has personal loan? (categorical: 'no','yes','unknown')
- 年齢
- 仕事
- 結婚
- 学歴
- 債務履行の有無
- 持ち家の有無
- ローンの有無
ダウンロードしたデータのうち、bank_full.csvファイルを主に使っていきます。
データの読み込み
pandasにデータを読み込むときには`read_csv()`を使います。
import pandas as pd df = pd.read_csv('bank-full.csv', delimiter=';', decimal=',') df.head()

出力はこんな感じです。
属性情報の数が多いですね。
余談ですが、コードを書くときにはGoogle Colaboratoryを使っています。
Pandasの表がダークでカッコいいです。
Google Colabを使うとコーディングがクラウドでできるので、家でも会社でもコードがかけてとても便利です。
データの前処理
欠損したデータがないか確認します。
欠損地の有無は`isnull()`を使うと算出できます。
df.isnull().sum()
age 0 job 0 marital 0 education 0 default 0 balance 0 housing 0 loan 0 contact 0 day 0 month 0 duration 0 campaign 0 pdays 0 previous 0 poutcome 0 y 0 dtype: int64
欠損データは無さそうですね。
良いデータセットです。
次に学習に必要なさそうな属性データ(過去のキャンペーン活動の日付など)を削除します。
df.drop(['contact',"day","month","duration","campaign","pdays","previous","poutcome"], axis=1, inplace=True) df.head()

うん、シンプルになりました。
ちなみに、アメリカの学歴は、
- primary education, 小学校
- secondary education, 中学〜高校
- tertiary education, 大学、職業専門学校
となっています。
tertiary(ターシャリ)って何だろうと思って調べたら、「第3の」という意味らしいです。
3番目なので高校かと思いましたが、高校はセカンダリーになるみたい。
今回はこの8個の属性から、最後のy(定期預金の開設をしたかどうか)を予測するモデルを作っていきたいと思います。
ここで各カラムの型を見てみましょう。
型情報を得るには、`dtypes`で確認します。
df.dtypes
age int64 job object marital object education object default object balance int64 housing object loan object y object dtype: object
「age」と「balance」以外は、objectという抽象的なものになっています。
object型はラベルなどの文字列を指す場合が多いです。
機械学習では、基本的に数値(整数型(int)もしくは浮動小数点数型(float))を扱うのでobject型を整数型に変更する必要があります。
pandasの`factorize()`を使って整数型に変換します。
ラベルが例えば”yes”と”no”であれば、それぞれ1,0に変更します。
obuject型のカラム名をリストに含めて、繰り返し数値に変換するようにコードを書きます。
# ラベルを全て数値に変換する li = ["job","marital","education","default","housing","loan","y"] for column in li: labels, uniques = pd.factorize(df[column]) df[column] = labels
age int64 job int64 marital int64 education int64 default int64 balance int64 housing int64 loan int64 y int64 dtype: object
これでデータの準備が整いました。
機械学習
SVM
SVMを使って機械学習を行ってみます。
from sklearn.model_selection import train_test_split from sklearn import datasets,svm,metrics from sklearn.metrics import accuracy_score,classification_report y = df['y'] X = df.drop(columns='y') # データを学習用とテスト用に分割する X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2) # データを学習 clf = svm.LinearSVC() clf.fit(X_train, y_train) # 予測して精度を確認する y_pred = clf.predict(X_test) print(accuracy_score(y_test, y_pred)) print(classification_report(y_test,y_pred))
`accuracy_score`で正解率を求めています。
classification_report
では、学習機がどのようにクラス分けしたかを表示してくれます。
0.885104500718788 precision recall f1-score support 0 0.89 1.00 0.94 8004 1 0.00 0.00 0.00 1039 accuracy 0.89 9043 macro avg 0.44 0.50 0.47 9043 weighted avg 0.78 0.89 0.83 9043 /usr/local/lib/python3.6/dist-packages/sklearn/svm/base.py:929: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations. "the number of iterations.", ConvergenceWarning) /usr/local/lib/python3.6/dist-packages/sklearn/metrics/classification.py:1437: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. 'precision', 'predicted', average, warn_for)
正解率を見てみると、88.5%でした。
高精度、やったね!と喜びたいところですが、`classification_report’の内容を見ると1のprecisionが0.00になっています。
precisionというのは、精度を意味します。
つまり、学習器が0と予想した中で実際に0だった割合が89%、1と予想した中で実際に1だった割合が0%でした。
これでは実際に分類できているとは言えません。
例えば、0が5000個、1が100個あったとします。
全部のデータに対して0と答えれば、5000/5100 = 98%の割合で正解します。
これと同じことが今回の学習で起こっているかもしれません。
確認のために、ラベルの割合を見てみます。
# ラベルの数を表示する y_no = len(y[y==0]) y_yes = len(y[y==1]) print([y_no],[y_yes])
[39922] [5289]
マーケティング活動を行って、実際に銀行口座を開いてくれた人は僅かです。
ほとんどの人は開設していません。
つまり負例(0)が多く正例(1)が少ない状態です。
全て0と答えれば、39922/(39922+5289) = 88.3% で正解します。
このような学習データは釣り合っていないので不均衡データと呼ばれます。
オーバーサンプリング
今回ような極端に正例が少ない学習データに対してはオーバーサンプリングが有効です。
オーバーサンプリングには、SMOTEと呼ばれる手法を使います。
“SMOTE: synthetic minority over-sampling technique”は2002年の機械学習ジャーナルで発表されている実績のある手法です。
Pythonでは、imblearnパッケージの中にありますのでimportすることで使えるようになります。
from imblearn.over_sampling import SMOTE #正例が少なすぎるのでオーバーサンプリングして正例の数を増やす sm=SMOTE(ratio='auto', kind='regular') X_sampled,y_sampled=sm.fit_sample(X,y) Sampled_no = len(y_sampled[y_sampled==0]) Sampled_yes = len(y_sampled[y_sampled==1]) print([Sampled_no],[Sampled_yes])
[39922] [39922]
正例と負例の数が同じになりました。
再度学習をかけてみます。
# データを学習用とテスト用に分割する X_train,X_test,y_train,y_test = train_test_split(X_sampled,y_sampled,test_size=0.2) # データを学習 clf = svm.LinearSVC() clf.fit(X_train, y_train) # 予測して精度を確認する y_pred = clf.predict(X_test) print(accuracy_score(y_test, y_pred)) print(classification_report(y_test,y_pred))
0.5216356691088985 precision recall f1-score support 0 0.52 0.43 0.47 7896 1 0.52 0.61 0.56 8073 accuracy 0.52 15969 macro avg 0.52 0.52 0.52 15969 weighted avg 0.52 0.52 0.52 15969
52%の精度でした。
2値分類なので当てずっぽうでも50%は達成できます。
もう少し精度が欲しいところですね。
ランダムフォレスト
今度はオーバーサンプリングしたデータに対してランダムフォレストを適用してみます。
from sklearn.ensemble import RandomForestClassifier rfc = RandomForestClassifier(n_estimators=40) rfc.fit(X_train, y_train) # 予測して精度を確認する y_pred = rfc.predict(X_test) print(accuracy_score(y_test, y_pred)) print(classification_report(y_test,y_pred))
0.8288559083223745 precision recall f1-score support 0 0.84 0.80 0.82 7896 1 0.82 0.85 0.83 8073 accuracy 0.83 15969 macro avg 0.83 0.83 0.83 15969 weighted avg 0.83 0.83 0.83 15969
82%まで精度が上がりました。
今回の学習データでは、SVMよりもランダムフォレストの方が精度が高いことが分かりました。
今回学習したモデルを使えば、お客様の個人情報からマーケティングが成功する可能性が高いお客様かどうかを判別することができます。
AIが判定したお客様にフォーカスして営業活動すれば成績が上がること間違いなしですね。
終わり。
参考
Machine Learning Classification with Python for Direct Marketing: