実務で使える！Pythonで実践する飲食店のデータ分析

# はじめに
飲食業界は、常に変化し続ける市場環境や顧客の嗜好に対応するため、データ分析の重要性がますます高まっています。データを適切に活用することで、売上の向上や顧客満足度の向上、新たなビジネスチャンスの発見など、多くの利点を享受することができます。今回は飲食店の練習データを用いてデータ分析を行っていきます。

# 開発環境と使用データ
開発環境はGoogle Colabで実装していきます。
3種類のデータを分析に使用します。
決済データ、オーダーデータ、人件費データ

# 今回求めたいこと
・月ごとの売上、粗利額、人件費、営業利益額
・月ごと、曜日別の顧客単価、客数（大人、子供、合計）アンケート回答率、リピート率、滞在時間、商品カテゴリ別の売上、カテゴリ別の注文率
・顧客のリピート率と注文カテゴリの関係

# 補足
・原価率
　フード/ワイン：35%、上記以外：25%
・販売管理費
　人件費以外の固定費：33万/月、人件費以外の変動費：売上の10%

# 実装
pandasのみを使用してデータ分析をしました。
```python
from google.colab import drive
drive.mount("/content/drive/")

import pandas as pd

#expense:人件費データ,order:オーダーデータ,account:決済データ
expense = pd.read_csv("/content/drive/yourpath")
order = pd.read_csv("/content/drive/yourpath")
account = pd.read_csv("/content/drive/yourpath")

order = order.groupby(["決済ID","カテゴリ"])[["総売上高","数量"]].sum()

#注文開始時間を%H%Mに変換
account["注文開始時間"] = pd.to_datetime(account["注文開始時間"]).dt.strftime("%H%M").astype(int)
account.head()

#時間ごとに午前、昼、午後に分ける

def classify_day(dt):
  if dt < 1200:
    return "午前"
  elif 1200 <= dt < 1330:
    return "昼"
  else:
    return "午後"

account["時刻区分"] = account["注文開始時間"].apply(classify_day)
account = account.groupby(["決済ID","日付","注文開始時間","滞在時間","時刻区分","来店数アンケート"])[["大人","子供"]].sum

#account,orderを結合
ao = pd.merge(account,order,how = "left",on = "決済ID")

#出勤日を%Y-%mの形に変換し、年月ごとにgroupby
expense["出勤日"] = pd.to_datetime(expense["出勤日"])
expense["年月"] = expense["出勤日"].dt.strftime("%Y-%m")
pe = expense.groupby("年月")[["人件費合計"]].sum()

ao["日付"] = pd.to_datetime(ao["日付"])
ao["年月"] = ao["日付"].dt.strftime("%Y-%m")

pf = ao.groupby(["決済ID","年月"])[["総売上高"]].sum()

#aoで原価をそれぞれ求める

ao["原価1"] = ao.loc[(ao["カテゴリ"] == "フード") | (ao["カテゴリ"] == "ワイン")]["総売上高"] * 0.35
ao["原価2"] = ao.loc[(ao["カテゴリ"] == "ドリンク") | (ao["カテゴリ"] == "デザート") | (ao["カテゴリ"] == "コーヒー") | (ao["カテゴリ"] == "その他")]["総売上高"] * 0.25
ao = ao.fillna({"原価1":0})
ao = ao.fillna({"原価2":0})
ao["原価"] = ao["原価1"] + ao["原価2"]
ao = ao.drop(["原価1","原価2"],axis = 1)

#月ごとの原価を求め、それとpfを結合する
gp = ao.groupby(["年月"])[["原価"]].sum()
gp = pd.merge(pf,gp,how = "right",on = "年月")
gp["粗利額"] = gp["総売上高"] - gp["原価"]

#pfとpe(月ごとの人件費)を結合し、営業利益額を求める
op = pd.merge(pf,pe,how = "left",on = "年月")
op["粗利額"] = gp["粗利額"]
op["営業利益額"] = op["粗利額"] - (op["人件費合計"] + 330000 + op["総売上高"] * 0.1)

#月ごとの人件費の平均を求める
pem = expense.groupby("年月")[["人件費合計"]].mean()

#月ごとの総売上高の平均を求める
pfd = ao.groupby("日付")[["総売上高"]].sum()
pfd = pfd.reset_index()
pfd["年月"] = pfd["日付"].dt.strftime("%Y-%m")
pfd = pfd.groupby("年月")[["総売上高"]].mean()

#月ごとの原価の平均を求める
gpd = ao.groupby("日付")[["原価"]].sum()
gpd = gpd.reset_index()
gpd["年月"] = gpd["日付"].dt.strftime("%Y-%m")
gpd = gpd.groupby("年月")[["原価"]].mean()

d = ao.groupby("日付")[["総売上高"]].sum()
d = d.reset_index()
d["年月"] = d["日付"].dt.strftime("%Y-%m")

lists = []
for t in d["年月"].unique():
  a = len(d.loc[d["年月"] == t])
  lists.append(a)

#一日当たりの傾向を求めるため、営業利益額を日付で割る
op["日数"] = lists
op["一日の売り上げ"] = pfd
op["一日の人件費"] = pem
op["一日の粗利額"] = gpd
op["一日の営業利益額"] = op["営業利益額"] /lists

#月ごとの客人数
ao["客人数"] = ao["大人"] + ao["子供"]
cus = ao.groupby("年月")[["大人","子供","客人数"]].sum()
cus["単価"] = op["総売上高"] / cus["客人数"]

years = ao["年月"].unique()
lists = []

#アンケート回答率
for y in years:
  a = ao.loc[ao["年月"] == y]
  b = (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2])) / len(a)
  lists.append(b)

cus["アンケート回答率"] = lists

lists = []
for y in years:
  a = ao.loc[ao["年月"] == y]
  b = len(a[a["来店数アンケート"] == 2]) / (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2]))
  lists.append(b)

cus["リピート率"] = lists

#月ごとの滞在時間
time = ao.groupby("年月")[["滞在時間"]].mean()

cus["滞在時間"] = time

order = ao.groupby(["年月","カテゴリ"])[["総売上高"]].sum()
order = order.rename(columns = {"総売上高":"カテゴリ別売上"})

#月ごとのカテゴリ別売上
pfuni = pf["総売上高"].unique()

lists = [uni for uni in pfuni for _ in range(6)]
len(lists)

order["総売上高"] = lists
order["注文率"] = order["カテゴリ別売上"] / order["総売上高"]
order = order.drop(["総売上高"],axis = 1).reset_index()

#曜日を定義
ao["曜日"] = ao["日付"].dt.day_name()
week = ["Monday", 'Tuesday','Wednesday','Thursday','Friday', 'Saturday', 'Sunday']

#曜日ごとの重要指標A
wk = ao.groupby(["日付","曜日"])[["大人","子供","客人数","総売上高"]].sum().reset_index()
wk = wk.groupby("曜日")[["大人","子供","客人数","総売上高"]].mean()
wk = wk.reindex(index = week)
wk["顧客単価"] = wk["総売上高"] / wk["客人数"]

weeks = ao["曜日"].unique()
lists = []

for w in weeks:
  a = ao.loc[ao["曜日"] == w]
  b = (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2])) / len(a)
  lists.append(b)

wk["アンケート回答率"] = lists

lists = []
for w in weeks:
  a = ao.loc[ao["曜日"] == w]
  b = len(a[a["来店数アンケート"] == 2]) / (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2]))
  lists.append(b)

wk["リピート率"] = lists

hour = ao.groupby(["曜日"])[["滞在時間"]].mean()
wk = pd.merge(wk,hour,how = "left",on = "曜日")

#曜日ごとのカテゴリ別売上
wkc = ao.groupby(["日付","カテゴリ","曜日"])[["総売上高"]].sum()
wkc = wkc.groupby(["曜日","カテゴリ"])[["総売上高"]].mean()
wkc = wkc.rename(columns = {"総売上高":"カテゴリ別売上"})
wkc = wkc.reindex(week,level = "曜日")

wkp = wk["総売上高"].unique()
lists = [a for a in wkp for _ in range(6)]

wkc["総売上高"] = lists
wkc["注文率"] = wkc["カテゴリ別売上"] / wkc["総売上高"]
wkc = wkc.drop(["総売上高"],axis = 1)

#曜日別の総売上高、客人数
wp = ao.groupby(["日付","曜日"])[["総売上高"]].sum()
wp = wp.groupby("曜日")[["総売上高"]].mean()
wp = wp.reindex(index = week)
wp["客人数"] = ao.groupby("曜日")[["客人数"]].sum()

#午前昼午後別の重要指標A
cd = ao.groupby(["日付","時刻区分"])[["大人","子供","客人数","総売上高"]].sum()
cd = cd.groupby("時刻区分")[["大人","子供","客人数","総売上高"]].mean()
cd["顧客単価"] = cd["総売上高"] / cd["客人数"]

lists = []

for t in ao["時刻区分"].unique():
  a = ao.loc[ao["時刻区分"] == t]
  b = (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2])) / len(a)
  lists.append(b)

cd["アンケート率"] = lists

lists = []
for t in ao["時刻区分"].unique():
  a = ao.loc[ao["時刻区分"] == t]
  b = len(a[a["来店数アンケート"] == 2]) / (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2]))
  lists.append(b)

cd["リピート率"] = lists

t = ao.groupby("時刻区分")[["滞在時間"]].mean()
cd = pd.merge(cd,t,how = "left",on = "時刻区分")

#午前昼午後別のカテゴリ別売上
cc = ao.groupby(["時刻区分","カテゴリ"])[["総売上高"]].mean()
cc = cc.rename(columns = {"総売上高":"カテゴリ別売上"}).reset_index()

tc = cc.groupby("時刻区分")[["カテゴリ別売上"]].sum().reset_index()

lists = []
for h in cc["時刻区分"].unique():
  a = len(cc.loc[cc["時刻区分"] == h])
  lists.append(a)

t = []
for i,tu in zip(lists,tc["カテゴリ別売上"].unique()):
  a = [tu] * i
  t = t + a

cc["総売上高"] = t
cc["注文率"] = cc["カテゴリ別売上"] / cc["総売上高"]

cd = cd.drop(["総売上高"],axis = 1)
cc = cc.drop(["総売上高"],axis = 1)

cc = cc.groupby(["時刻区分","カテゴリ"])[["カテゴリ別売上","注文率"]].sum()

ao.groupby("カテゴリ")[["来店数アンケート"]].sum()
lists = []
for c in ao["カテゴリ"].unique():
  a = ao.loc[ao["カテゴリ"] == c]
  b = len(a[a["来店数アンケート"] == 2]) / (len(a[a["来店数アンケート"] == 1]) + len(a[a["来店数アンケート"] == 2]))
  lists.append(b)

rc = pd.DataFrame(index = ao["カテゴリ"].unique(),
                  data = lists)
rc = rc.rename(columns = {0:"リピート率"})
```

# まとめ
今回は飲食店のデータ分析を実装しました。
今後、実際の業務で飲食店のデータ分析をする機会があったら是非参考にしてみてください。