【Aidemy成果物】プログラミング初心者がデータ分析(クラスター分析)をやってみた

「このブログはAidemy Premiumのカリキュラムの一環で、受講修了条件を満たすために公開しています」


Ⅰ.はじめに 

1.自己紹介

  • 2024年現在、30代前半

  • メーカーの企画職(2社目)

  • プログラミング知識は皆無。業務でも使ったことがない状況。

  • 元々、理系科目に苦手意識があるにも関わらず、かっこ良さそうだからという理由で大学はデータ分析のゼミに所属、社会人になっても数値を扱う職種(経営企画)に所属。

2.受講に至った経緯

 企画系キャリアを積んできましたが、自分のキャリアやスキルの限界を感じました。転職や結婚を機に、今後の自分のキャリアや人生の自由度を上げる意味でも、企画系職種と親和性の高いと思っていたデータ分析と元々興味があったプログラミングの勉強をしてみようとAidemy受講を決めました。

Ⅱ.本記事の概要

1.どんな人に読んでほしいか

  • プログラミング初学者のうち、これからプログラミング言語を使ってデータ分析をしてみようかなという方

  • 文系出身で数学やプログラミングに苦手意識があるけど挑戦してみようかなという方

2.この記事で書くこと

  • 「プログラミング超絶初学者×文系卒」が四苦八苦しながらプログラミングを使ったデータ分析に挑戦してみた結果と過程

Ⅲ.作成したプログラム

■分析に使用した環境

  • GoogleColaboratory

■使用したデータ

Kaggleデータ

Mall Customer Segmentation Data

https://www.kaggle.com/datasets/vjchoudhary7/customer-segmentation-tutorial-in-python/code

■分析手順とコード

今回はKaggleの'Mall Customer Segmentation Data'のデータを取り込み顧客データの可視化と分析をしてみたいと思います。

今回の分析の目標は以下の2点としたいと思います。

  1. 各種グラフによるデータ間の相関関係の可視化と分析

  2. クラスター分析による顧客データ分析のグルーピング

1.データの取り込み・確認

データの取り込みとそれに必要なPandasをインポートします。

#Pandasをインポートします。
import pandas as pdimport numpy as np

#Kaggleからダウンロードしておいたデータを取り込みます
df=pd.read_csv('/content/Mall_Customers.csv')

データの確認をしていきます。

※データの内容を確認してみます
df


1000件の顧客データに対して、9個のカラムで構成

データのうち空白がないかを確認します。

#データのうち、空白(=null)がないか確認してみたいと思います。
df.info()


空白はないようです。

データ全体の統計量を見てみます。

df.describe()


重複する行がないかを確認します。

#重複する行がないかを確認します。
df.duplicated().sum()

ないようです。
ここまでのデータの確認で以下のようなデータがあることがわかりました。

  1. CustomerID: 各顧客の一意の識別子

  2. Gender: 顧客の性別 (男性、女性)

  3. Age: 顧客の年齢

  4. Annual Income: 顧客の年間収入 (USD)。

  5. Spending_Score: 顧客の行動と支出の性質に基づいてモールが割り当てたスコア (1 ~ 100)。

2.データの前処理

前節のデータの確認で分かるように、今回の分析では、Kaggleに蓄積している仮想データを使用しているので、前処理は必要ではありませんでした。

3.データの可視化と分析

データ分析においては、そもそも何を調べてどんな分析結果が欲しいのかという点が重要であるので、以下をこの分析のゴールとしたいと思います。

■この分析のゴール
企業によって直接的な価値がある「顧客ごとの支出スコアと他の変数の関係性を可視化・分析し、具体的な施策の示唆を得ること」

 それでは、1節でも確認できた目的変数を顧客の年間収入であるSpending_Scoreとして、ほかを説明変数として以下のような順序で可視化と分析を進めていきます。

  • 目的変数:Spending_Score

  • 説明変数:そのほかの変数

  1. 目的変数であるspending_scoreの分布、それぞれの説明変数の分布を可視化

  2. 目的変数と説明変数の相関係数をマトリクス・ヒートマップで表現

  3. 相関がある説明変数と目的変数をクロス集計し、どういった属性の顧客にアプローチするかを特定

可視化に使用するライブラリをインポートします

import matplotlib.pyplot as plt
import seaborn as sns
#目的変数であるSpending Score (1-100)の分布を調べてみます
sns.histplot(df,x='Spending Score (1-100)')


40-70台のスコアが多いようです。少しわかりにくいのでもう少しわかりやすくしたいですね。
#わかりやすくするために10ずつに区切ったカラムを作成し、棒グラフで表現してみます。
df['spending_score_group']=pd.cut(df['Spending Score (1-100)'],bins=range(0,110,10),labels=[f'{i}-'for i in range(0,100,10)],right=False)
sns.histplot(df,x='spending_score_group')


【spending_score】

  1. 40~50台に一番多いspending_scoreが一番多い

  2. 一方で上記を除くと0-100の間にもスコアはある

#顧客の性別の構成を円グラフで見てみます。
plt.pie(df['Gender'].value_counts(),labels=df['Gender'].value_counts().index,autopct='%1.1f%%')


【Gender】

  1. 女性のほうが多い

#年齢の分布を見ます
sns.histplot(df,x='Age')


#少しわかりにくいので年齢層別のカラムを作ってそれをdfに追加し、円グラフで見てみます。
df['age_group']=pd.cut(df['Age'],bins=range(0,100,10),labels=[f'group {i}'for i in range(0,90,10)],right=False)

#年代別でカウントして%で表現します。
plt.pie(df['age_group'].value_counts(),labels=df['age_group'].value_counts().index,autopct='%1.1f%%')


#次にFemaleの中でAge_group別で構成を見てみます。
plt.pie(df[df['Gender']=='Female']['age_group'].value_counts(),labels=df[df['Gender']=='Female']['age_group'].value_counts().index,autopct='%1.1f%%')


#次にMaleの中でAge_group別で構成を見てみます。
plt.pie(df[df['Gender']=='Male']['age_group'].value_counts(),labels=df[df['Gender']=='Male']['age_group'].value_counts().index,autopct='%1.1f%%')


【Age】

  1. 30代が一番多く3割を占める

  2. 20~40代で全体の7割を占める

  3. 20~50代で8割以上を占める

【Gender×Age】

  1. 男女とも20-40代の割合が多い

  2. 女性では20-40代の割合で8割近くを占める

  3. 男性は20-40代で6割を占めるが女性と比較すると10代と60代の比率が高い

#顧客の年間収入を見てみます
sns.histplot(df,x='Annual Income (k$)')


#これもわかりにくいのでレンジで切るカラムを追加し、再度棒グラフで見てみます。
df['income_group']=pd.cut(df['Annual Income (k$)'],bins=range(0,200,10),labels=[f'{i}-'for i in range(0,190,10)],right=False)
sns.histplot(df,x='income_group')


#Income_groupを円グラフで可視化してみます
plt.pie(df['income_group'].value_counts(),labels=df['income_group'].value_counts().index,autopct='%1.1f%%')


【income】

  1. 40~70台の年間収入の層が多く、この層で6割近くを占める

  2. 80台以上の層は少ない

【相関係数の可視化】
次に目的変数であるspending_scoreと各説明変数の関係性を見るためにヒートマップを使って可視化してみたいと思います。

ヒートマップにするためには、dfのカラムのうち、int型を変換する必要があります。

そのためには、genderとpreferred_categoryのカラムをLabel encodingで数値化します。

df


#GenderのカラムをLabel encodingで数値へ変換
from sklearn.preprocessing import LabelEncoder
le=LabelEncoder()
df['Gender_No']=le.fit_transform(df['Gender'])
le.classes_
df


#ヒートマップを使ってspending_scoreと各説明変数の関係性を可視化します。
sns.heatmap(df[['Spending Score (1-100)','Gender_No','Age','Annual Income (k$)']].corr(),vmax=1,vmin=1,annot=True)


これまでの可視化でわかったこと

【spending_score】

  1. spending_scoreは40~50台に一番多い

  2. 0-100の間のスコアにも分布はある

【Gender】

  1. 女性のほうが多い

【Age】

  1. 30代が一番多く3割を占める

  2. 20~40代で全体の7割を占める

  3. 20~50代で8割以上を占める

【Gender×Age】

  1. 男女とも30代の割合で3割近くで、20-40代の割合が多い

  2. 女性では20-40代の割合で8割近くを占める

  3. 男性は20-40代で6割を占めるが、女性と比較すると10代と60代の比率が高い

【income】

  1. 40~70台の年間収入の層が多く、この層で6割近くを占める

  2. 80台以上の層は少ない

【Heat Mapによる相関関係】

  1. Spending Scoreとほかの属性には明確な相関関係は確認できなかった

【上記踏まえた次のステップ】

  • 収入と支出を散布図にて可視化

  • 上記より、特に男女通じて30代で3割の顧客がいるため、30代の男女のincomeレベル、spending_scoreを分布図で確認し、可視化

  • 収入・支出の散布図のうち、全体のとターゲット層(30代の男女)の傾向を可視化

#X軸をAnnual Income (k$)、y軸をSpending Score (1-100)、Genderの男性が青、女性は赤に色分けし、散布図を作成
plt.scatter(df[df['Gender']=='Male']['Annual Income (k$)'],df[df['Gender']=='Male']['Spending Score (1-100)'],c='blue')
plt.scatter(df[df['Gender']=='Female']['Annual Income (k$)'],df[df['Gender']=='Female']['Spending Score (1-100)'],c='red')
#x軸をAnnual Income(k$),y軸をSpending Scoreとしてプロット
plt.title('Scatter plot of Annual Income v/s Spending Score', fontsize = 20)
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.show()


#gender_groupのgroup30のみを抜き出して散布図を作成する
plt.scatter(df[(df['Gender']=='Male') & (df['age_group']=='group 30')]['Annual Income (k$)'],df[(df['Gender']=='Male') & (df['age_group']=='group 30')]['Spending Score (1-100)'],c='blue')
plt.scatter(df[(df['Gender']=='Female') & (df['age_group']=='group 30')]['Annual Income (k$)'],df[(df['Gender']=='Female') & (df['age_group']=='group 30')]['Spending Score (1-100)'],c='red')
#x軸をAnnual Income(k$),y軸をSpending Scoreとしてプロット
plt.title('Scatter plot of Annual Income v/s Spending Score in gruop age30', fontsize = 10)
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.show()


散布図からわかったことと考察

  • 全体では支出スコア40-60かつ年収も40-60に分布が多い

  • 全体の3割をしめる30代では全体と比較すると、支出スコア70-100の間に多い

可視化からの示唆:

  • 30代の男女は全体に占める割合も3割程度と高く、支出のポイントも高いため、ターゲットとしては有望と推測される

  • 30代の男女の夫婦などの属性調査などし、効率的な販促実施が可能

4.クラスター分析

この分析のゴール

  • この分析では「顧客データをグルーピング、どのような顧客で構成されているかをセグメントにわけ、特徴に応じて分析・示唆を得ること」をゴールにKMeans法でクラスター分析を行います。

上記を達成するために、以下のような手順で進めます。

  1. X軸を収入、y軸を支出スコアとした全体の散布図を可視化

  2. エルボー法を用いてクラスター数をみてみる

  3. 2で導出したクラスター数でKmeansモデルに当てはめ

  4. クラスターごとに色分けして可視化

  5. それぞれのクラスターの特徴に応じて分析

#クラスター分析を行う収入と支出をXとしておきます
X = df[['Annual Income (k$)', 'Spending Score (1-100)']]
#1のx軸をAnnual Income(k$)、y軸をSpending Score(1-100)とした散布図を可視化
plt.scatter(X['Annual Income (k$)'],X['Spending Score (1-100)'])
plt.title('Scatter plot of Annual Income v/s Spending Score', fontsize = 15 )
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.show()


【読み取れること】

  • なんとなく5つのクラスターに分かれそう

#クラスター分析を行うべく、MinMaxScalerをインポート
from sklearn.preprocessing import MinMaxScaler

#特徴量を正規化
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
#エルボー法を用いたクラスター分析を行う
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
wcss = []
for i in range(1, 11):
    kmeans = KMeans(n_clusters=i, init='k-means++', random_state=42)
    kmeans.fit(X_scaled)
    wcss.append(kmeans.inertia_)
print(wcss)
#2.クラスターの数を折れ線グラフで表現
plt.figure(figsize=(10, 6)) 
plt.plot(range(1, 11), wcss, marker='o',linestyle='--', color='b')  
plt.title('Elbow Method')
plt.xlabel('Number of Clusters')
plt.ylabel('Within-Cluster Sum of Squares (WCSS)')
plt.xticks(range(1, 11))  
plt.grid(True) 
plt.show()


【読み取れること】

  1. クラスターの数が5個までは加速度的にwcssが低くなっていることがわかる(5個がいわゆるエルボーの部分か)

  2. クラスター数は5個で定義するとうまくグループ分けできそう

#K-Meanモデルにあてはめ
kmeans = KMeans(n_clusters=5, init='k-means++', random_state=42)
kmeans.fit(X_scaled)
#4.各クラスターを色分けして可視化してみる
plt.figure(figsize=(10, 8))
#5個のクラスターごとにそれぞれループ関数を使ってラベルをつける
for cluster_label in range(5):
    cluster_points = X[kmeans.labels_ == cluster_label]
    centroid = cluster_points.mean(axis=0)
    plt.scatter(cluster_points['Annual Income (k$)'], cluster_points['Spending Score (1-100)'], label=f'Cluster {cluster_label+1}')
    plt.scatter(centroid[0], centroid[1], marker='x', s=100,c='black',label=f'Centroid{cluster_label+1}')
plt.title('Clusters of Customers',fontsize=15)
plt.xlabel('Annual Income (k$)',fontsize=15)
plt.ylabel('Spending Score (1-100)',fontsize=15)
plt.legend()
plt.show()


■クラスター分析の結果と分析

  1. クラスター数を5個に設定し収入と支出スコアで比較的わかりやすくグループに分けられた

  2. グループごとの特徴(軸による特徴)

  • Cluster1(青):収入 中×支出 中

  • Cluster2(オレンジ):収入 高×支出 小

  • Cluster3(緑):収入 低×支出 少

  • Cluster4(赤):収入 低×支出 多

  • Cluster5(紫):収入 高×支出 多

  1. 特徴から導出される示唆と今後必要な手続き

  • ロイヤルティが高いと考えられる顧客グループはCluster4(赤)と5(紫)のグループ

  • 特に4グループがなぜ支出スコアが高いかを分析することでこのモールの強みを分析できると考えられる。

  • テコ入れが必要と考えられるグループはCluster2で、同様水準の収入だが支出スコアの高いグループ5との違いを分析し、施策につなげられる可能性が高い

  1. 施策案

  • 今後は例えばCluster2,4,5グループによく購入する店舗や商品を分析すること

  • メールマガジンなどで好きなジャンルなどの特徴がわかるようなアンケート調査と分析

 上記のような手続きを行って有効な施策を立案していくべきと考えられる

Ⅳ.おわりに

今回、Aidemyのデータ分析講座を受講し、できたこと、分かったことは以下の3つでした。

  • 機械学習、ディープラーニング、またそれを土台にしたデータ処理、分析とはどのようなものかを覗くことができた。データ分析の専門家になるにはそれ相応の努力や仕事に使う密度が必須。

  • プログラミングスキルは確かに難しいし、奥が深いもので深淵だが今回の受講によりやり方や勉強の仕方はわかった。また、ChatGPTといったAIのおかげでめちゃくちゃ学びやすく、業務に落とし込み効率化していくハードルは格段に下がっている

  • 仮説が大事である。最終課題を取り組む中であくまでデータを収集する段階の可視化とそこから導出できる仮説こそに価値があり、込み入った分析は仮説を証明していく手段に過ぎない

結果、総括するとプログラミングを土台にしたデータ分析を含む技術は、業務を飛躍的に向上させる手段として非常に有効だし、めちゃくちゃ特別な訓練が必要なわけではなく、生成AIが誕生した今はプログラミングを構築するハードル、学ぶハードルがめちゃくちゃ下がっていることを体感できました。
今後の自分の人生の中に仕事をする上での手札を増やすという意味で今回の受講は非常に有意義だと感じました。

この記事が気に入ったらサポートをしてみませんか?