はじめに
今回は、Pythonの強力なデータ分析ライブラリであるPandasとSeabornを使って、小売データを分析する方法をご紹介します。50行以上のデータを使用し、15の章に分けて詳しく解説していきます。各章では、コードと共に丁寧な説明を加えていきますので、初心者の方でも安心してお読みいただけます。
第1章:環境設定とデータの読み込み
まずは、必要なライブラリをインポートし、サンプルデータを読み込みましょう。Pandasは表形式のデータを扱うのに適しており、Seabornはデータの可視化を簡単に行えるライブラリです。
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# サンプルデータの作成
data = {
'日付': pd.date_range(start='2023-01-01', periods=60),
'商品名': ['A商品', 'B商品', 'C商品'] * 20,
'売上': [100, 150, 200] * 20,
'数量': [5, 3, 2] * 20,
'顧客ID': list(range(1, 61))
}
df = pd.DataFrame(data)
print(df.head())
この章では、PandasとSeabornをインポートし、60行のサンプルデータを作成しました。pd.DataFrameを使ってデータフレームを作成し、head()メソッドで最初の5行を表示しています。これにより、データの構造を簡単に確認できます。
第2章:基本的なデータ探索
データを読み込んだら、まずは基本的な情報を確認しましょう。Pandasには、データの概要を簡単に把握できる便利な関数があります。
print(df.info())
print("\n統計情報:")
print(df.describe())
print("\nユニークな値の数:")
print(df.nunique())
info()関数はデータの型や欠損値の有無を教えてくれます。describe()関数は数値データの基本統計量を表示し、nunique()関数は各列のユニークな値の数を示します。これらの関数を使うことで、データの全体像を素早く把握できます。
第3章:時系列データの分析
小売データでは、時系列での売上推移を見ることが重要です。Pandasの強力な日付処理機能を使って、月ごとの売上を集計してみましょう。
df['月'] = df['日付'].dt.to_period('M')
月別売上 = df.groupby('月')['売上'].sum().reset_index()
plt.figure(figsize=(12, 6))
sns.lineplot(x='月', y='売上', data=月別売上)
plt.title('月別売上推移')
plt.xticks(rotation=45)
plt.show()
ここでは、日付データから月情報を抽出し、groupby関数を使って月ごとの売上を集計しています。Seabornのlineplot関数を使って、簡単に時系列グラフを作成できます。このグラフを見ることで、売上の季節変動や傾向を視覚的に把握できます。
第4章:商品別の分析
次に、商品ごとの売上や数量を分析してみましょう。これにより、どの商品が最も人気があるか、または利益を生んでいるかを把握できます。
商品別集計 = df.groupby('商品名').agg({
'売上': 'sum',
'数量': 'sum'
}).reset_index()
商品別集計['平均単価'] = 商品別集計['売上'] / 商品別集計['数量']
print(商品別集計)
plt.figure(figsize=(10, 6))
sns.barplot(x='商品名', y='売上', data=商品別集計)
plt.title('商品別売上')
plt.show()
この章では、groupby関数とagg関数を使って商品ごとの集計を行っています。また、売上を数量で割ることで平均単価も計算しています。Seabornのbarplot関数を使って、商品別の売上をグラフ化しています。これにより、どの商品が最も売上に貢献しているかが一目で分かります。
第5章:顧客分析
顧客ごとの購買行動を分析することで、重要な顧客を特定したり、マーケティング戦略を立てたりすることができます。
顧客別集計 = df.groupby('顧客ID').agg({
'売上': 'sum',
'数量': 'sum'
}).reset_index()
顧客別集計['平均購入額'] = 顧客別集計['売上'] / 顧客別集計['数量']
print(顧客別集計.sort_values('売上', ascending=False).head())
plt.figure(figsize=(12, 6))
sns.scatterplot(x='数量', y='売上', data=顧客別集計)
plt.title('顧客別 数量vs売上')
plt.show()
ここでは、顧客IDごとに売上と数量を集計し、平均購入額も計算しています。sort_values関数を使って、売上の高い順に並べ替えて上位5件を表示しています。また、Seabornのscatterplot関数を使って、数量と売上の関係を散布図で表現しています。これにより、高額購入をする顧客や頻繁に購入する顧客を視覚的に識別できます。
第6章:相関分析
変数間の関係を理解するために、相関分析を行いましょう。Pandasとseabornを使えば、簡単に相関係数を計算し、ヒートマップで視覚化できます。
数値データ = df[['売上', '数量']]
相関係数 = 数値データ.corr()
print("相関係数:")
print(相関係数)
plt.figure(figsize=(8, 6))
sns.heatmap(相関係数, annot=True, cmap='coolwarm')
plt.title('相関係数ヒートマップ')
plt.show()
corr()関数を使って相関係数を計算し、Seabornのheatmap関数でヒートマップを作成しています。annot=Trueを指定することで、各セルに相関係数の値を表示しています。cmap='coolwarm'は、正の相関を赤、負の相関を青で表現するカラーマップを指定しています。このヒートマップを見ることで、変数間の関係性を一目で把握できます。
第7章:時間帯別分析
小売業では、時間帯によって売上や客数が変動することがあります。時間帯別の分析を行って、ピーク時間を把握しましょう。
df['時間'] = df['日付'].dt.hour
時間帯別集計 = df.groupby('時間').agg({
'売上': 'mean',
'数量': 'mean'
}).reset_index()
plt.figure(figsize=(12, 6))
sns.lineplot(x='時間', y='売上', data=時間帯別集計)
plt.title('時間帯別平均売上')
plt.xlabel('時間')
plt.ylabel('平均売上')
plt.show()
ここでは、日付データから時間情報を抽出し、時間ごとの平均売上と平均数量を計算しています。Seabornのlineplot関数を使って、時間帯別の平均売上をグラフ化しています。これにより、どの時間帯が最も売上が高いかを視覚的に確認できます。この情報は、スタッフのシフト管理や販促活動の計画に役立ちます。
第8章:曜日別分析
曜日によって売上パターンが異なることも多いです。曜日別の分析を行って、週間のトレンドを把握しましょう。
df['曜日'] = df['日付'].dt.day_name()
曜日別集計 = df.groupby('曜日').agg({
'売上': 'mean',
'数量': 'mean'
}).reset_index()
曜日順序 = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
曜日別集計['曜日'] = pd.Categorical(曜日別集計['曜日'], categories=曜日順序, ordered=True)
曜日別集計 = 曜日別集計.sort_values('曜日')
plt.figure(figsize=(12, 6))
sns.barplot(x='曜日', y='売上', data=曜日別集計)
plt.title('曜日別平均売上')
plt.xticks(rotation=45)
plt.show()
この章では、日付データから曜日情報を抽出し、曜日ごとの平均売上と平均数量を計算しています。pd.Categoricalを使って曜日の順序を指定し、適切な順序でグラフを表示しています。Seabornのbarplot関数を使って、曜日別の平均売上を棒グラフで表現しています。これにより、週末に売上が増加するなどのパターンを簡単に確認できます。
第9章:季節性分析
小売業では季節によって売上が大きく変動することがあります。四半期ごとの分析を行って、季節性を把握しましょう。
df['四半期'] = df['日付'].dt.quarter
四半期別集計 = df.groupby('四半期').agg({
'売上': 'sum',
'数量': 'sum'
}).reset_index()
plt.figure(figsize=(10, 6))
sns.barplot(x='四半期', y='売上', data=四半期別集計)
plt.title('四半期別総売上')
plt.xlabel('四半期')
plt.ylabel('総売上')
plt.show()
ここでは、日付データから四半期情報を抽出し、四半期ごとの総売上と総数量を計算しています。Seabornのbarplot関数を使って、四半期別の総売上を棒グラフで表現しています。これにより、年間を通じての売上の季節変動を把握できます。この情報は、在庫管理や販促計画の立案に役立ちます。
第10章:ABC分析
ABC分析は、商品を売上高や利益率に基づいて分類する手法です。これを使って、重要度の高い商品を特定しましょう。
商品別売上 = df.groupby('商品名')['売上'].sum().sort_values(ascending=False).reset_index()
商品別売上['累積比率'] = 商品別売上['売上'].cumsum() / 商品別売上['売上'].sum()
商品別売上['分類'] = pd.cut(商品別売上['累積比率'],
bins=[0, 0.8, 0.95, 1],
labels=['A', 'B', 'C'])
print(商品別売上)
plt.figure(figsize=(10, 6))
sns.barplot(x='商品名', y='売上', hue='分類', data=商品別売上)
plt.title('ABC分析')
plt.xticks(rotation=45)
plt.show()
この章では、商品ごとの売上を集計し、累積比率を計算しています。pd.cut関数を使って、累積比率に基づいてA、B、Cの3つのカテゴリーに分類しています。Seabornのbarplot関数を使って、分類結果を色分けして表示しています。これにより、重要度の高い商品(Aクラス)を視覚的に識別できます。
第11章:顧客セグメンテーション
顧客をRFM(Recency, Frequency, Monetary)分析に基づいてセグメント化し、重要顧客を特定しましょう。
最新日 = df['日付'].max()
rfm = df.groupby('顧客ID').agg({
'日付': lambda x: (最新日 - x.max()).days, # Recency
'顧客ID': 'count', # Frequency
'売上': 'sum' # Monetary
})
rfm.columns = ['Recency', 'Frequency', 'Monetary']
rfm['R_Segment'] = pd.qcut(rfm['Recency'], q=3, labels=['3', '2', '1'])
rfm['F_Segment'] = pd.qcut(rfm['Frequency'], q=3, labels=['1', '2', '3'])
rfm['M_Segment'] = pd.qcut(rfm['Monetary'], q=3, labels=['1', '2', '3'])
rfm['RFM_Score'] = rfm['R_Segment'].astype(str) + rfm['F_Segment'].astype(str) + rfm['M_Segment'].astype(str)
print(rfm.head())
plt.figure(figsize=(10, 6))
sns.scatterplot(x='Recency', y='Monetary', size='Frequency', data=rfm)
plt.title('顧客セグメンテーション')
plt.show()
この章では、RFM分析を行っています。Recency(最新購入日からの経過日数)、Frequency(購入頻度)、Monetary(総購入金額)を計算し、それぞれを3段階にセグメント化しています。pd.qcut関数を使って、各指標を3つのセグメントに分けています。最後に、Seabornのscatterplot関数を使って、RecencyとMonetaryの関係を散布図で表現し、Frequencyをポイントの大きさで表現しています。これにより、高価値顧客(Recencyが低く、MonetaryとFrequencyが高い)を視覚的に識別できます。
第12章:バスケット分析
バスケット分析は、どの商品が一緒に購入されやすいかを分析する手法です。これを使って、クロスセリングの機会を見つけましょう。
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
# 顧客IDと商品名でピボットテーブルを作成
バスケット = pd.crosstab(df['顧客ID'], df['商品名'])
# アプリオリアルゴリズムを適用
頻出アイテムセット = apriori(バスケット, min_support=0.1, use_colnames=True)
# アソシエーションルールを生成
ルール = association_rules(頻出アイテムセット, metric="lift", min_threshold=1)
print(ルール.sort_values('lift', ascending=False).head())
# 上位5つのルールを可視化
plt.figure(figsize=(10, 6))
sns.scatterplot(x='support', y='confidence', size='lift', data=ルール.head())
plt.title('アソシエーションルール')
for i, row in ルール.head().iterrows():
plt.annotate(f"{row['antecedents']} -> {row['consequents']}",
(row['support'], row['confidence']))
plt.show()
この章では、mlxtendライブラリを使ってアプリオリアルゴリズムを適用し、商品間の関連性を分析しています。pd.crosstab関数を使って、顧客IDと商品名のクロス集計表を作成し、それをバスケットデータとして使用しています。アソシエーションルールを生成し、liftの高い順にソートして表示しています。さらに、Seabornのscatterplot関数を使って、上位5つのルールをsupport、confidence、liftの3次元で可視化しています。これにより、どの商品の組み合わせが強い関連性を持っているかを把握できます。
第13章:売上予測
過去のデータを使って、将来の売上を予測してみましょう。ここでは、簡単な時系列予測モデルを使用します。
from statsmodels.tsa.arima.model import ARIMA
# 日付ごとの総売上を計算
日別売上 = df.groupby('日付')['売上'].sum().reset_index()
日別売上 = 日別売上.set_index('日付')
# ARIMAモデルを適用
model = ARIMA(日別売上['売上'], order=(1,1,1))
results = model.fit()
# 次の7日間を予測
forecast = results.forecast(steps=7)
plt.figure(figsize=(12, 6))
plt.plot(日別売上.index, 日別売上['売上'], label='実績')
plt.plot(forecast.index, forecast, color='red', label='予測')
plt.title('売上予測')
plt.legend()
plt.show()
print("次の7日間の予測売上:")
print(forecast)
この章では、statsmodelsライブラリのARIMAモデルを使って売上予測を行っています。まず、日付ごとの総売上を計算し、それをARIMAモデルに適用しています。モデルを学習した後、次の7日間の売上を予測しています。matplotlib.pyplotを使って、実績データと予測データを同じグラフ上にプロットしています。これにより、売上トレンドと将来の予測を視覚的に確認できます。この情報は、在庫管理や人員配置の計画に役立ちます。
第14章:価格弾力性分析
価格変更が売上にどのような影響を与えるかを分析するために、価格弾力性を計算してみましょう。
# 単価を計算
df['単価'] = df['売上'] / df['数量']
# 商品ごとに集計
価格弾力性 = df.groupby('商品名').agg({
'単価': 'mean',
'数量': 'sum',
'売上': 'sum'
}).reset_index()
# 価格弾力性を計算 (簡易的な方法)
価格弾力性['価格弾力性'] = (価格弾力性['数量'].pct_change() / 価格弾力性['単価'].pct_change()) * -1
print(価格弾力性)
plt.figure(figsize=(10, 6))
sns.scatterplot(x='単価', y='数量', size='売上', hue='商品名', data=価格弾力性)
plt.title('価格と数量の関係')
plt.xlabel('平均単価')
plt.ylabel('総数量')
plt.show()
この章では、単価と数量の関係から簡易的に価格弾力性を計算しています。まず、売上を数量で割って単価を計算し、商品ごとに平均単価、総数量、総売上を集計しています。価格弾力性は、数量の変化率を価格の変化率で割ることで計算しています(ここでは簡易的な方法を使用)。Seabornのscatterplot関数を使って、単価と数量の関係を散布図で表現し、売上を点の大きさで、商品名を色で表現しています。これにより、価格変更が需要にどのような影響を与えるかを視覚的に把握できます。
第15章:ダッシュボードの作成
最後に、これまでの分析結果をまとめたダッシュボードを作成しましょう。複数のグラフを1つの画面に配置することで、全体像を把握しやすくなります。
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(20, 15))
gs = gridspec.GridSpec(3, 2)
# 月別売上推移
ax1 = fig.add_subplot(gs[0, 0])
sns.lineplot(x='月', y='売上', data=月別売上, ax=ax1)
ax1.set_title('月別売上推移')
ax1.set_xticklabels(ax1.get_xticklabels(), rotation=45)
# 商品別売上
ax2 = fig.add_subplot(gs[0, 1])
sns.barplot(x='商品名', y='売上', data=商品別集計, ax=ax2)
ax2.set_title('商品別売上')
# 時間帯別平均売上
ax3 = fig.add_subplot(gs[1, 0])
sns.lineplot(x='時間', y='売上', data=時間帯別集計, ax=ax3)
ax3.set_title('時間帯別平均売上')
# 曜日別平均売上
ax4 = fig.add_subplot(gs[1, 1])
sns.barplot(x='曜日', y='売上', data=曜日別集計, ax=ax4)
ax4.set_title('曜日別平均売上')
ax4.set_xticklabels(ax4.get_xticklabels(), rotation=45)
# RFM分析
ax5 = fig.add_subplot(gs[2, 0])
sns.scatterplot(x='Recency', y='Monetary', size='Frequency', data=rfm, ax=ax5)
ax5.set_title('顧客セグメンテーション')
# 価格と数量の関係
ax6 = fig.add_subplot(gs[2, 1])
sns.scatterplot(x='単価', y='数量', size='売上', hue='商品名', data=価格弾力性, ax=ax6)
ax6.set_title('価格と数量の関係')
plt.tight_layout()
plt.show()
この最終章では、matplotlib.gridspecを使って、6つのグラフを1つの大きな図に配置しています。月別売上推移、商品別売上、時間帯別平均売上、曜日別平均売上、RFM分析による顧客セグメンテーション、価格と数量の関係を一つのダッシュボードにまとめています。これにより、ビジネスの様々な側面を一目で把握することができます。
以上で、PandasとSeabornを使った小売データの分析が完了しました。これらの分析結果を活用することで、在庫管理の最適化、販促活動の効果的な計画、顧客サービスの向上など、様々な業務改善につなげることができます。データ分析は継続的に行い、常に最新の傾向を把握することが重要です。皆様のビジネスの成功を心よりお祈りしています。