本記事では学習のアウトプットとして、『Python実践データ分析100本ノック』に書かれている各ノックのコードのうち、難解と思われる部分の意味を解説していきます。 「本に書かれている解説だけでは理解が難しい(;一_一)」と感じた方、この記事を読んで理解の一助となれば幸いです。
Python実戦データ分析100本ノックは、データの集計や分析のためのpandasや、グラフ描画に使用するmatplotlib、機械学習を行うためのscikit-learnなど、データ分析に欠かせない要素を実際に自分で手を動かしながら学ぶことができる本です。
今回は第7回として、ノック31-35をやっていきます。
追記:現在第二版が2022年6月に出版されています。
本記事は第1版の内容の解説です。
第二版の解説記事もいずれ書かせていただこうと思っていますので今しばしお待ちください!
第4章 顧客の行動を予測する10本ノック
ノック31:データを読み込んで確認しよう
import pandas as pd
uselog=pd.read_csv('use_log.csv')
#読みこんんだuselogファイルの欠損値の合計値を調べています。
uselog.isnull().sum()
customer=pd.read_csv('customer_join.csv')
#読みこんんだcustomer_joinファイルの欠損値の合計値を調べています。
customer.isnull().sum()
これまでと同様にcsvファイルを読み込んで、まずは、欠損値がないかどうかを確認できました。
ノック32:クラスタリングで顧客をグループ化しよう
#customerデータのうちクラスタリングに用いる5つの変数を指定し、customer_clusteringという新しいテーブルに格納しています。
customer_clustering=customer[["mean","median","max","min","membership_period"]]
customer_clustering.head()
この2行の内容自体はこれまでも何度か行っている操作なので、意味の理解は簡単だと思います。
しかし、重要なのは、この後実施するクラスタリングに用いるデータの変数が5つあるということです。平均値、中央値、最大値、最小値、会員期間の5つです。
この値、よく考えると、単位が異なる変数だと思いませんか?このような単位がバラバラな変数どうしを用いても分析するための工夫がちゃんと存在します。
そのうちの一つが次のコード解説内で触れている”標準化“です。
標準化とは
標準化はデータセットのある系列について、平均が0、標準偏差が1になるようにデータセットを整えることです。標準化を行うことで特徴量の比率を揃えることが出来ます。
このような処理を行うことを前処理とも呼びます。標準化を行うことで、例えば、cm,kgと単位がバラバラになっているデータでも同じような評価基準で評価することができるようになります。
クラスタリング
ここからは、機械学習の一つであるクラスタリングという教師無し学習を行っていきます。
“このグループはここ!”のような正解(教師データ)を与えず、機械に自動で近しい属性を持つデータをグルーピングしてもらいます。
例えば、クラスタリングでメールを自動的に振り分けて、迷惑メールや広告メールと、重要なメールを振り分けるために用いられることがあります。
機械学習モデルを用いて分析を行う際には、ライブラリをインポートして、分析したいデータをインプットするだけという訳にはいきません。
モデル構築といって、モデルごとに設定を行い、トレーニングデータを用いてモデルを分析に適したものに育成していく必要があるんです。
「じゃあ、どんな事をしたらいいの?」という問いに対しては、「モデルごとに様々ですので、一概には回答できません( TДT)」しかし、大まかにいうと、パラメーターの設定(モデル定義ともいいます。)→データのフィッティング→検証という流れです。
もちろん、登場したモデルごとに解説の中で順に説明していきますので、ご心配なく(`・ω・´)
トレーニングデータとテストデータの違い
モデルを用いた分析のために知っておかなければいけないことは様々ありますが、まず、トレーニングデータとテストデータの違いから始めます。
トレーニングデータとは、モデルを自分が分析したいデータに合わせて最適化していくために使用するデータです。
それに対して、テストデータというのは、トレーニングデータを使用して育成したモデルが理想的なものになっているかをテストするためのデータです。
ただ、名前はそれぞれ違えど、自分が持っているデータセットをトレーニングデータとテストデータに分割するだけでOKなんです。(ただ、何割をトレーニングデータとテストデータで分けるかが難点です。)
今回はクラスタリングの中でもK-Means法という方法を用いていきます。
K-Means法とは
基本的には、以下の 3 つの手順でクラスタリングを行います。
- まず、各サンプルデータがどのクラスタ(グループ)に属するかをランダムで割り当てます。
- 各クラスタ内において、重心点を計算によって求めます。
- 各点から2で求めたクラスタの重心点との距離を求めます。各店はそれぞれ一番近かった重心点のクラスタに再度割り当てられます。このとき、すべての点が同じクラスタ内に割り当てられたら、処理は終了です。そうでなければ、2. ~ 3. を決められた回数繰り返し実行し、大きな変化がなくなるまで計算します。
#まず、機械学習ライブラリである sikit-learn をインポートします。
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
#StandardScalerはデータセットの標準化機能を提供しています。
sc=StandardScaler()
#fit()は引数で指定したデータの最大値、最小値、平均、標準偏差などの統計を取得して、内部メモリに保存します(フィッティング)。
#transform()は取得した統計データを使って、実際にデータを変換します。
#fit_transform()は上記の作業をいっきに実施します。
customer_clustering_sc=sc.fit_transform(customer_clustering)
#ここでK-Meansのモデル構築を行っていきます。
#n_clusters=:クラスタ(=グループ)数の設定。random_state=:乱数の固定化(分かりにくいかもしれませんが、乱数固定化は結果の再現性を確保するために必要です。)
kmeans=KMeans(n_clusters=4,random_state=0)
#モデルにデータをフィッティングし、クラスタリングを実施します。
clusters=kmeans.fit(customer_clustering_sc)
#model.labels_は各データのクラスタ番号をリストにします。
customer_clustering["cluster"] = clusters.labels_
print(customer_clustering["cluster"].unique())
customer_clustering.head()
print(customer_clustering[“cluster”].unique()) を見ると、データを0~4 の4つにグループ化出来ていることが分かります。
ノック33:クラスタリング結果を分析しよう
#分析結果を把握しやすくするために列の名前を変えていきます。
customer_clustering.columns=["月内平均値","月内中央値","月内最大値","月内最小値","会員期間","cluster"]
#クラスター毎にデータ件数の集計を行います。
customer_clustering.groupby("cluster").count()
#クラスターごとの平均を確認します。
customer_clustering.groupby("cluster").mean()
それぞれのクラスターの平均値を集計し、クラスターの平均値、中央値、最大値、最小値、会員期間の数値から、しっかりと4つのクラスターにわけられていることが分かりました。
ノック34:クラスタリング結果を可視化してみよう
ここからは、先ほどまでのノックで計算したクラスタリングの結果をプロットします。その際に、注意しないといけないのが、ノック32で触れた”変数が5つ”という点です。二次元で5つの変数を表示することは不可能なので、プロットの際、次元数を5→2に削減します(次元削減といいます)。次元削減は教師なし学習の1つで、情報をなるべく失わないように変数を削減することです。
今回は、次元削減の方法の一つ、主成分分析(PCA)を用います。
#まずは、PCAのインポートです。
from sklearn.decomposition import PCA
#Xにクラスタリングを実施したcustomer_clustering_scを代入します。
X=customer_clustering_sc
#モデル定義を行います。
#n_components=:で次元数を指定します。今回は二次元を指定しました。
pca=PCA(n_components=2)
#PCAを実施していきます。
#まず、XにPCAをフィッティングします。
pca.fit(X)
#変換を行い二次元に落とし込みます。
x_pca=pca.transform(X)
#二次元に圧縮したデータをpca_dfというデータフレームに格納しています。
pca_df=pd.DataFrame(x_pca)
#ノック32で算出したクラスタリング結果を格納します。
pca_df["cluster"]=customer_clustering["cluster"]
#ノック10から使用しているmatplotlibを使用します。
import matplotlib.pyplot as plt
%matplotlib inline
#for文でクラスターごとに散布図をプロットします。
for i in customer_clustering["cluster"].unique():
tmp=pca_df.loc[pca_df["cluster"]==i]
#plt.scatterは散布図を描くメソッドです。
#()でグラフに出力するデータを指定します。
#x軸y軸にそれぞれtmpの0番目と1番目を指定しているのは、上のコードのブロックでPCAによって二次元となっているクラスタリングのデータを指定するためです。
plt.scatter(tmp[0],tmp[1])
クラスター自体は5つのままなので混同してしまいそうですが、プロットするための変数が2つになっているので、横軸縦軸には当然2つの変数しか指定できませんよね。
ノック33で算出したクラスタリング結果に次元削減を施し、プロットしやすい次元に落とし込んだあと、散布図の形式で結果を表示できました。
ノック35:クラスタリング結果をもとに退会顧客の傾向を把握しよう
#ノック2で登場したconcatメソッドを使用して、クラスタリング結果とcustomerデータを結合します。
customer_clustering=pd.concat([customer_clustering,customer],axis=1)
#ノック8で登場したgroupbyメソッドを使用して、clusterとis_deletedごとにcluster、is_deleted、customer_idそれぞれの総和を集計します。
customer_clustering.groupby(["cluster","is_deleted"],as_index=False).count()[["cluster","is_deleted","customer_id"]]
#クラスターとroutine-flagごと、つまり、クラスター内で定期利用者(週4回以上来ている)とそうでない人を区別して集計します。
customer_clustering.groupby(["cluster","routine_flg"],as_index=False).count()[["cluster","routine_flg","customer_id"]]
クラスタリングによって分割したグループの継続顧客と退会顧客がどれだけいるのか、また、定期利用しているかを確認できました。
ここまでで、ノック31-35は完了です。お疲れ様でした。
今回は、クラスタリングという教師なし学習を用いて、データの分析を行いました。新しく登場する手法を含め、どんどんコードが複雑になっていきますが、細かい部分はそれまでのノックで登場した内容がほとんどです。復習しながら解読していけば、少しずつ理解できるようになるはずです。頑張りましょう。次回は第3章後半(利用回数の予測)に入ります。引き続きよろしくお願いいたします(^^)/