俺、サービス売って家買うんだ

Swift, Vue.js, 統計, GCP / このペースで作ってればいつか2-3億で売れるのがポっと出来るんじゃなかろうか

実店舗の売上データで分析する。(タンタンタイガー)

あけましておめでとうございます! Hayatoです。
去年の暮に出したかったんですが惜しくも間に合わず、年を越した渾身の記事から今年のblogをスタートです!

友人が店主の担々麺屋でタンタンタイガーってのがあります。2016年8月に開店したので、まだ半年しか経ってないのですが、割りといい感じでお客さんが来てくれてます。今回は、そのお店の実際の売上データを、Pythonで分析していきます。

なかなか実店舗のガチデータを公開することはないので、貴重な機会ではないでしょうか。データ分析を練習中の人はもちろん、これから飲食店をやろうとしている人や、いま売上を伸ばすのに苦戦中な飲食店店主さんにも役に立つとうれしいです。

分析ノート(iPython notebook)はGithubにもあげているので、こちら気になる方は参考にしてください。(重いので携帯では見れないかもです)

github.com

Index

  1. データクリーニングと把握
  2. 分析計画
  3. 実際に分析

それでは早速やっていきましょう!

1. データクリーニングと把握

まずはデータをきれいにすることから始めます。今回は気象データが売上にどれくらい影響しているかを調べたかったので、気象庁のデータをこちらから持ってきて、日付で突き合わせました。データ量が少なかったので、スプレッドシートで処理しています。

実際の処理後のCSVデータはこちらにあるので、分析の練習や、お店のシュミレーションに使ってください!

処理が終わったら、どんなデータなのかを見ていきます。分析前に大まかな概要を掴んでおくのはとても大切です。

データの概要を把握

#必要なライブラリを予めすべてインポート
import pandas as pd
import numpy as np
import pylab as pl
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
%matplotlib inline
sns.set_style('whitegrid')
#CSVデータをDF形式で読み込み。 indexにdateを設定
rowdata = pd.read_csv('./data/tantantigerdata.csv', 
                      parse_dates=['日付'],index_col=['日付'], dayfirst=True)
#データ概要1:どういうカラムでどういうデータが入っているか確認
rowdata.sort_values(by='来客数', ascending=True).head(3) 
#データ概要2:平均値などを確認
rowdata.describe().astype(int)                     

結果: f:id:hayato1986:20170105205127p:plain f:id:hayato1986:20170105205135p:plain

なんとなくですが、

  • 前提:サンプル数は77 / 時系列データ。
  • 平均82人の来客数。単価平均は981円。
  • 52 ~ 112 人が95%の来客数範囲。この範囲を超えると何かあったと見て良いかも

くらいまでわかります。

2. 分析計画

データのクリーニングとその把握ができたら、実際の分析計画を立てていきましょう。 店主の東山さんと話して、以下のように計画を立てました。新規とリピーターの割合、天候と売上の相関に関して焦点を当てています。

1. 時系列における売上の推移はどうなっているか
 - 開店直後からの数値推移
 - 新規とリピーターの割合推移
 - リピーターと曜日の相関
2. 天候による売上の相関関係はどうなっているか
 - 気温と売上の相関
 - 天気と売上の相関

3. 実際に分析

それでは計画をもとに、分析をしていきましょう!
ようやく分析できる!ってところまで来ると、もう80%くらいは作業が終わってたりします笑

時系列における売上の推移はどうなっているか

開店直後からの数値推移 (新規顧客の推移 /リピーターの推移)

まずは単純に時系列の売上推移です。リピーター数と新規数も同時に出しています。
一日ごとのばらつきが結構大きく、全体を掴みづらいので14日の移動平均で算出しています。

rowdata_rolling = rowdata.rolling(window=14, min_periods=14).mean() #14日の移動平均

graph_num = 5
fig, axes = plt.subplots(nrows=graph_num, ncols=1, figsize=(16,12),  squeeze=False) #squeezeはsubplotsのおまじない

for i, col in enumerate(rowdata_rolling):
    rowdata_rolling[col].plot(ax=axes[i,0])
    axes[i,0].set_title(col, fontsize=14, fontweight='bold')
    i+=1
    if i == graph_num:
        break
plt.tight_layout() #スペース調整

結果: f:id:hayato1986:20170105205612p:plain

  • 10月がピークだった?
  • 全体数値は落ちてなさそう
  • 新規は落ちてそう
  • リピーターが増えてそう

くらいはわかりますね。実際にエリアチャートを使って視覚化していきましょう。

新規とリピーターの割合推移

rowdata_rolling.loc[:,['リピート数','新規合計']].plot(
    legend=True, figsize=(16, 8), y=['リピート数','新規合計']
          , kind='area', stacked=True, alpha=0.5
)

結果: f:id:hayato1986:20170105205749p:plain

  • リピーター数は伸びている
  • 新規は10月22日のTVCMで大きく増えたが少し右肩下がり
  • リピーター数が伸びているので新規の落ち込みをカバーしている。全体では減ってない

あたりは明確に言えそうですね。次は曜日ごとの数値の関係性を見ていきましょう。

リピーターと曜日の相関

#Pivot Table で分析 / aggfunc='mean' , columns='リピート数 の SUM'
rowdata.pivot_table(index="曜日",aggfunc='mean').astype(int)

#Group by で分析
week_group = rowdata[['リピート数','新規数']].groupby(rowdata['曜日'])
#week_group.mean()
week_group.mean().plot(legend=True, figsize=(16, 4), kind="bar", stacked=True)

結果: f:id:hayato1986:20170105212915p:plain

  • 日曜は新規客が売上を支えている
  • やや木曜日のお客さんの伸びが悪い
  • リピーターはどの曜日でもかわらない

といったことが言えそうです。タンタンタイガーはBlogで集客していたので、日曜日に遠方からのお客さんがちらほら来ていただけるのが大きいですね。

天候による売上の相関関係はどうなっているか

変数が多いので、関係ありそうなところだけを恣意的にピックして、相関関係を見ていこうと思います。

fig, ax = plt.subplots(figsize=(10,10)) #Sizeを定義する
data = rowdata.drop(['最高気温','最低気温','日照時間', '平均風速', '蒸気圧(hPa)'], axis=1)
sns.heatmap(data.corr() ,annot=True, linewidths=.5, ax=ax)

f:id:hayato1986:20170105210538p:plain

ここで注意しなければならないのは、新規のお客さんは時系列で少しづつ減っていて、リピーターが伸びていることです。相関係数だけを見ると、 来客数と気温に相関がありそうですが、開店直後から現在まででリピーター数が比例し、新規客が反比例するのはある種当たり前なので、一概に比例関係にあるとは言いづらくなっています。

その中でも言えそうなのは

  • リピート数と単価平均に相関が見られそう
  • 雨と来店数はあんまり関係なさそう
  • 風はすべての数値にほとんど関係ない

くらいでしょうか。段々と暖かくなってきたら、ここらへんはまた分析して本当の相関を見ていけると思います。 店長の東山さんが「今日は天気が悪かったからお客さんが少なかった」とよく言うので、おまけで平均気温と来客数の相関を視覚的な面から追っていきましょう。

気温と売上の相関を詳しく見てみる

sns.jointplot('平均気温', '来客数', data=rowdata, kind="scatter")

f:id:hayato1986:20170105211313p:plain 散布図上の見た目では、やはりそこまで相関はなさそうです。念のため、見逃している相関が無いかどうか散布図とカーネルグラフを描画します。

returns_fig = sns.PairGrid(data)
returns_fig.map_upper(plt.scatter, color='purple')
returns_fig.map_lower(sns.kdeplot, cmap='cool_d')
returns_fig.map_diag(plt.hist,bins=10)

f:id:hayato1986:20170105211418p:plain

やはりあんまり特徴的な関係性は見られませんでした。

まとめ

飲食店のデータは分析しがいがありますね笑。本当ならこの分析結果から、TODOを決めてってところまでやるのですが、Blogでは分析までということにさせてください!これからもタンタンタイガーのデータを定期的に分析していこうと思います。

オラッオラオラオラッ(ΦωΦ)