Pandasでスマレジ解析

前回、スマレジからCSV形式でデータを取り出すことができました。このデータを眺めていたら、OpenWeatherMapのデータと組み合わせて需要予測が可能ではないかと思いつきました。つまり、ここで書いてあることを実地で検証できるかも、というところです。

Palpanの様子を見ていると、1日以外は営業日の夕方には殆んど商品が残っておらず、効率がよいと言うより「済みません、本日は売り切れました!」っと、商機を逸している状況が見受けられるようです。そこで、需要予測を行い、予測成績がよければこれに従って製造プランを提示しようというわけです。ただし、作れば売れるのを目指すのではなく、ブーランジェでもある娘の製造能力を超えずに最低限度の売り上げを確保することが必要です。売上だけで見ると、売れなかったものが何だったのかが判然としませんので、様々な要因を組み合わせながら統計的手法を用いようというものです。

私自身には統計学的素養は全くもって持ち合わせていませんが、近年のAIブームのおかげでWebには用語の解説やアプリケーション、学習済みデータ、サンプルコードが溢れています。素人の私にとって、なかなか理解し難いものですが、無期限ハンズオンの精神で体をはって学習していくことにします。まず、入り口を乗り越えるための一番低い壁は、と探していたら、データ解析の定番はPython+Pandasのようでした。

pandasを利用するにはpythonとpipのインストールが必要です。私の現在の環境は次のとおりです。

$ python -V
Python 3.6.2

$ pip -V
pip 9.0.1 from /home/shige/.pyenv/versions/3.6.2/lib/python3.6/site-packages (python 3.6)

pipが古いので先に更新を行います。

$ pip install --upgrade pip
Cache entry deserialization failed, entry ignored
Collecting pip
  Using cached https://files.pythonhosted.org/packages/c2/d7/90f34cb0d83a6c5631cf71dfe64cc1054598c843a92b400e55675cc2ac37/pip-18.1-py2.py3-none-any.whl
Installing collected packages: pip
  Found existing installation: pip 9.0.1
    Uninstalling pip-9.0.1:
      Successfully uninstalled pip-9.0.1
Successfully installed pip-18.1

$ pip -V
pip 18.1 from /home/shige/.pyenv/versions/3.6.2/lib/python3.6/site-packages/pip (python 3.6)

さらに、pandasのインストールを行います。

$ pip install pandas
Collecting pandas
  Using cached https://files.pythonhosted.org/packages/e1/d8/feeb346d41f181e83fba45224ab14a8d8af019b48af742e047f3845d8cff/pandas-0.23.4-cp36-cp36m-manylinux1_x86_64.whl
Requirement already satisfied: numpy>=1.9.0 in /home/shige/.pyenv/versions/3.6.2/lib/python3.6/site-packages (from pandas) (1.15.4)
Requirement already satisfied: pytz>=2011k in /home/shige/.pyenv/versions/3.6.2/lib/python3.6/site-packages (from pandas) (2018.7)
Requirement already satisfied: python-dateutil>=2.5.0 in /home/shige/.pyenv/versions/3.6.2/lib/python3.6/site-packages (from pandas) (2.7.5)
Requirement already satisfied: six>=1.5 in /home/shige/.pyenv/versions/3.6.2/lib/python3.6/site-packages (from python-dateutil>=2.5.0->pandas) (1.11.0)
Installing collected packages: pandas
Successfully installed pandas-0.23.4

データ解析の前にpandasの機能を知らなければ使いこなしもできませんが、そこは習うより慣れろです。python自体もこの十数年、触ったこともありません。まずは、手になじませることが重要ですので、チュートリアルを参考にしながら、自分なりに解釈して行きます。pythonの良いところは1ステップずつ実行しながら確認ができるので、学習するにはぴったりです。

pythonのコンソールに入ってpandasを読み込みます。

$ python
Python 3.6.2 (default, Dec 18 2018, 12:58:14) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas as pd
>>> 

チュートリアルではlunch_box.csvを読むようになっていますので、これを先日作成したhead.csvに変えれば良いでしょう。

df = pd.read_csv('./head.csv', sep=',')
df.head(3)
   1  2018-12-02 10:36:26   920.0  Unnamed: 3  920.0.1   68.0
0  2  2018-12-02 10:42:14   630.0         NaN    630.0   46.0
1  3  2018-12-02 10:43:30   700.0         NaN    700.0   51.0
2  4  2018-12-02 10:46:12  1660.0       166.0   1494.0  110.0

むむむ、sqliteで抽出したデータにはヘッダが付いていませんでしたので、先頭行がヘッダ行として解釈されています。これは失敗。pandasにヘッダが無いことを教えてあげます。

>>>  df = pd.read_csv('./head.csv', sep=',',header=None)
>>>  df.head(3)
   0                    1      2   3      4     5
0  1  2018-12-02 10:36:26  920.0 NaN  920.0  68.0
1  2  2018-12-02 10:42:14  630.0 NaN  630.0  46.0
2  3  2018-12-02 10:43:30  700.0 NaN  700.0  51.0

これでは何のデータか判りませんので、カラム名をつけます。

>>> df.columns=['No','販売時刻','合計','値引','金額','税額']
>>> df.head()
   No                 販売時刻      合計     値引      金額     税額
0   1  2018-12-02 10:36:26   920.0    NaN   920.0   68.0
1   2  2018-12-02 10:42:14   630.0    NaN   630.0   46.0
2   3  2018-12-02 10:43:30   700.0    NaN   700.0   51.0
3   4  2018-12-02 10:46:12  1660.0  166.0  1494.0  110.0
4   5  2018-12-02 10:47:44   900.0    NaN   900.0   66.0

開店用のチラシに10%割引券を付けておきましたので、値引フィールドに数値のある人は割引券を使った人たちです。

 >>> df.count()
No      415
販売時刻    415
合計      415
値引      130
金額      415
税額      415
dtype: int64

count関数ではNanの行を集計しませんので、値引行だけが少くカウントされます。1/3は割引券を使っていますので、チラシ作戦はうまくいったようです。割引券を使ったお客さんの平均購入金額はつぎのようにして出せます。

>>> df_disc = df.dropna()
>>> print(df_disc['金額'].sum() / df_disc['金額'].count())
858.3

意外と沢山購入していただいているようで、有り難いことです。値引きしなかったお客さんについても、平均購入金額を出してみます。

>>> df_non_disc = df[df.isnull().any(axis=1)]
>>> print(df_non_disc['金額'].sum() / df_non_disc['金額'].count())
852.8315789473684

うん、殆ど変化がありません。割引券を使ったお客さんは多めに買っていただいたようですね。この結果をどう見るかが今後の運営の方針となります。つまり、値引きしてもしなくても同じなら値引きする必要はなかったのか、1回目で割引券を使ったので、2回目以降の割引券を使わないお客さんが多かったのか、それとも、、、

開店して何日かのデータですので、全然見えてきませんが、とりあえずpandasの威力はすごいものだとわかりました。次は、OpenWeatherMapとの組み合わせを考えてみます。