売上を伸ばす方法をデータから考える。
はじめに
データを分析して売上を伸ばしたり、商品開発に取り入れたりする仕事ってやりがいありそうだなと思い、Aidemyのデータ分析コースを始めました。
文系の大学生で、講義では主に商いについて学んでいました。講義内でプログラミングは触ったことはありません。IT初心者です。
「このブログはAidemy Premiumのカリキュラムの一環で、受講修了条件を満たすために公開しています。」
ブログ作成の目的
Aidemyで学んだことでこんな事が出来るようになりましたという紹介、また学んだことの復習も兼ねて今回のデータ分析を行っています。
今回はkaggleのDatasetsにあらかじめ格納されたデータを使用して売上を伸ばす為にデータ分析をし、方法を考えます。
環境
Google chrome
Google Colaboratory
データセット
kaggle「Supermarket sales」
1. データの読み込み
Google Driveに保存したCSVファイルをGoogle colaboratoryに読み込み。
#google colaboratoryでcsvファイルの読み込み
from google.colab import drive
drive.mount('/content/drive')
#データがちゃんと読み込みされているか、またその確認。
import pandas as pd
df = pd.read_csv('/content/drive/MyDrive/supermarket_sales - Sheet1.csv')
df = pd.DataFrame(df)
df.head()
#print(df.info(()))
#欠損は発生していませんでした。
#print(df.duplicated())
#データの重複も確認できませんでした。
2.データの整理
分析に使わなそうなデータが多く、また表を見やすくしたかったのでまとめて削除。
本当はBranch(支店)とCustomer typeを説明変数に入れたかったが文字列を入れるとエラーが出たため、削除。
#今回はこのお店ではどういったものがよく売れているのか見たかったため、必要なさそうなデータは削除し、見やすくしました。
df = df.drop(["Invoice ID", "Branch", "City", "Customer type", "Gender", "Product line", "Tax 5%", "Date", "Time", "Payment", "cogs", "gross margin percentage"], axis=1)
df.head()
3.訓練用データとテストデータの分割
テストセットが20%、トレーニングセットは80%に設定。
目的変数はgross income(総収入)を選択。
from sklearn.model_selection import train_test_split
#特徴量とターゲット変数の選択
X = df.drop("gross income", axis=1)
y = df['gross income']
#トレーニングセットとテストセットにデータを分割しました。
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2, random_state=0, shuffle=False)
4.データ分析
今回は回帰分析を行う。
1.線形重回帰分析
from sklearn.linear_model import LinearRegression
#線形重回帰を行いました。
model = LinearRegression()
model.fit(train_X, train_y)
model.score(test_X, test_y)
#test_Xに対する予測の値は1でした。
予測値は1だった。
この結果は正しい分析が出来ていないと判断。過学習されていると仮定し、正則化を行う。今回はL2正則化を行いたいため、リッジ回帰と、ElasticNet回帰を行う。
2.リッジ回帰
#リッジ回帰
from sklearn.linear_model import Ridge
model = Ridge()
model.fit(train_X, train_y)
model.score(test_X, test_y)
予測値は0.9999999999999951だった。
3.ElasticNet回帰
#ElasticNet回帰
from sklearn.linear_model import ElasticNet
model = ElasticNet()
model.fit(train_X, train_y)
model.score(test_X, test_y)
予測値は0.9999999651559404だった。
この結果を受けて過学習されているという仮定を取り下げ、データが少な過ぎるのではないかと改めて仮定。やはりBranch(支店)とCustomer typeを説明変数に取り入れる方向で考える。
調べるとOne-Hot Encodingという方法で文字列を数値データへと変換とのことなので試してみる。
4.One-Hot Encodingの実装
df = df.drop(["Invoice ID", "City", "Gender", "Product line", "Tax 5%", "Date", "Time", "Payment", "cogs", "gross margin percentage"], axis=1)
df.head()
#One-Hot Encodingを使ってBranchとCustomer typeを文字列から数値データへと変換
encoded_df = pd.get_dummies(df, columns=['Branch', 'Customer type'])
df = df.drop(["Branch", "Customer type"], axis=1)
df = pd.concat([df, encoded_df], axis=1)
df.head()
実装後の結果だけ書くと
線形重回帰の予測値は1、
リッジ回帰は0.9999999999999989、
ElasticNet回帰は0.999999969939087だった。
どうした物かと思考し、説明変数を見直すことにした。
5.説明変数の見直し
トライ・アンド・エラーを繰り返し、ようやく納得できる結果を得ることが出来た。
※コードは上記のを書き換えた程度なので割愛
目的変数
・Gross income(総収入)
説明変数
・Customer type(顧客タイプ)
・Gender(性別)
・Unit Price(単価)
・Quantity(数量)
結果
重回帰:0.8752055839681624
リッジ回帰:0.8752072155211817
ElasticNet回帰:0.8733800998404004
どのモデルからも高い予測値を得ることが出来た。
今回はリッジ回帰のモデルを使うことにする。
5.精度の確認
次に精度の確認を行う。
平均二乗誤差と平均絶対誤差、決定係数を使用する。
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score
#平均二乗誤差
mse = mean_squared_error(y, model.predict(X))
print(f"Mean Squared Error: {mse}")
#平均絶対誤差
mae = mean_absolute_error(y, model.predict(X))
print(f"Mean Absolute Error: {mae}")
#決定係数
r_squared = r2_score(y, model.predict(X))
print(f"Coefficient of Determination (R^2): {r_squared}")
平均二乗誤差が15.12という値の場合、これはモデルの予測が実際の値から平均して15.12だけズレていることを示している。平均二乗誤差は予測のばらつきを示す指標であり、値が小さいほどモデルの予測精度が高いことを意味する。
平均絶対誤差が2.99という値の場合、これはモデルの予測が実際の値から平均して2.99だけズレていることを示している。平均絶対誤差も予測の精度を示す指標であり、こちらも値が小さいほどモデルの予測精度が高いことを示している。
決定係数が0.891という値の場合、これはモデルがデータを89.1%程度説明できることを示していまる。決定係数はモデルがデータをどれだけ説明できるかを表す指標で、1に近いほど良いモデルであることを示します。
よって、与えられた結果からは、モデルが比較的高い精度で予測を行っており、データのパターンをかなり正確に捉えていることが分かる。これらの評価指標からモデルの性能が高いことが示されている。
6.考察
特徴量の重要度をグラフで可視化し、考察する。
import matplotlib.pyplot as plt
import numpy as np
# 特徴量の係数を取得
feature_importance = np.abs(model.coef_)
# 個々の特徴量の名前を取得
feature_names = X.columns
# 特徴量の重要度を可視化
plt.figure(figsize=(10, 6))
plt.barh(feature_names, feature_importance)
plt.xlabel('Feature Importance (Absolute Coefficient Values)')
plt.ylabel('Features')
plt.title('Feature Importance of Ridge Regression Model')
plt.show()
意外なことにCustomer typeの重要度は全くと行っていいほどに高くなかった。性別も単価もそこまで重要度は高くなく、数量だけが高かった。
7.結論
この店舗においては会員であるかそうでないかという点においてはそこまで売上に影響はないのかもしれない。購入量という点においては影響が大きかったため、会員と非会員関係なく購入量を増やせるようなキャンペーンを行うことがこの店舗の売上を伸ばす方法なのかもしれない。
例)合計1000円以上購入してくれた方には卵を1パック150円で販売します。
反省
売上予測をするなら説明変数を事前に考えてデータセットを選ぶべきだった。作業している段階で別のデータセットに変更しようかとも考えたが、それは逃げなのではないかと思い、なんとか作業を進めようと四苦八苦していた(結果は納得の行くものではなかったが)。しかし、上手くいかなかったからこその気付きや発見があったとも思うのでこれはこれでいい経験なのではないかと思うことにする。
感想
今回始めて自分でデータ分析を行ってみたが、スッキリとした結論には至らなかった。購入量が売り上げに繋がることなんて誰でも少し考えれば分かるようなことを長々と行っただけのような感じがしてしまう。
しかし、結果はさておき学習してきたことのアウトプットという意味ではやって良かったと思った。やはりインプットの時よりもアウトプットしている今回の方が色々と記憶に残っている。自己学習は勿論だが、就職して実践経験を積むことが一番ためになると感じた。
これからまず統計検定と英語、そしてkaggleを使って勉強しようと思う。