2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2024-07-31

はじめに

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

開発環境と使用データ

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

今回求めたいこと

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

補足

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

実装

pandasのみを使用してデータ分析をしました。

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:"リピート率"})

まとめ

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

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?