Python実践機械学習100本ノック3章(with JupyterLab)
Python実践機械学習100本ノック3章(with JupyterLab)
Python実践機械学習システム100本ノック の3章「可視化の仕組みを構築する10本ノック」に ipywidgets
を使ったコード例がありますが、Jupyter NotebookやGoogle Colabではきちんとウィジェットが表示されるものの、JupyterLabでは上手く動いてくれませんでした。
ここでは、JupyterLabで書籍で示されているものと(おおむね)同じウィジェット操作ができるようなコードを紹介します。
環境と事前の準備
Windows環境
- Windows 10 Pro/Home 1909 64bit
- Python 3.9.1
- pip 20.3.3
- pipenv 2020.11.15
- Node.js 14.15.3
JupyterLab起動環境
- Python 3.8.7
- JupyterLab 3.0.4
- Jupyterlab-widgets 1.0.0
カーネル
JupyterLab起動環境がカーネルを兼ねている場合は、不足しているパッケージを上の環境にインストールしてください。
- Python 3.8.7
- ipykernel 5.4.2
- ipywidgets 7.6.2
- pandas 1.2.0
- matplotlib 3.3.3
- japanize-matplotlib 1.1.3
ipywidgets
の各種ウィジェットについて
下準備
モジュールのインポートとデータの読み込みを行います。
# Notebookで使うモジュールのインポート
import datetime
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
from ipywidgets import (interact, Dropdown, SelectMultiple,
IntSlider, ToggleButtons, DatePicker)
# ここは本の通り。
# まずcsvファイルのデータを読み込む。
m_store = pd.read_csv("m_store.csv")
m_area = pd.read_csv("m_area.csv")
# データをマージする。
order_data = pd.read_csv("tbl_order_202004.csv")
order_data = pd.merge(order_data, m_store, on="store_id", how="left")
order_data = pd.merge(order_data, m_area, on="area_cd", how="left")
# 読みやすくするためのデータを追加。
order_data.loc[order_data["takeout_flag"]==0, "takeout_name"] = "デリバリー"
order_data.loc[order_data["takeout_flag"]==1, "takeout_name"] = "お持ち帰り"
order_data.loc[order_data["status"]==0, "status_name"] = "受付"
order_data.loc[order_data["status"]==1, "status_name"] = "お支払済み"
order_data.loc[order_data["status"]==2, "status_name"] = "お渡し済み"
order_data.loc[order_data["status"]==3, "status_name"] = "キャンセル"
order_data.head() # 出力結果は省略。
ノック21: 店舗を絞り込んで可視化できるようにしてみよう
ここではドロップダウンリストで店舗名を絞り込んで、pandas.DataFrame.head()
や折れ線グラフを表示します。
以降のノックにも共通しますが、ipywidgets
の Dropdown
クラスのインスタンスを、表示を行う関数のデコレーターである interact()
に渡します。
DataFrame
の表示
ドロップダウンで店舗名を絞り込んだ store_list = m_store["store_name"].tolist()
drop_down_0 = Dropdown(
options=store_list,
description="store_name",
)
@interact(store_name=drop_down_0)
def order_by_store(store_name):
pick_data = order_data.loc[
(order_data["store_name"] == store_name)
& (order_data["status"].isin([1, 2]))
]
return pick_data.head()
セルを実行すると下記のように抽出されたデータの先頭が表示されます。また、ドロップダウンの別の店舗名を選択すると表示される内容が即座に変わることが確認できます。
出力
ドロップダウンで店舗名を絞り込んだ折れ線グラフの表示
drop_down_1 = Dropdown(
options=store_list,
description="store_name",
)
@interact(store_name=drop_down_1)
def graph_by_store(store_name):
pick_data = order_data.loc[
(order_data["store_name"] == store_name)
& (order_data["status"].isin([1, 2]))
]
temp = pick_data[["order_accept_date", "total_amount"]].copy()
temp.loc[:, "order_accept_date"] = pd.to_datetime(temp["order_accept_date"])
temp.set_index("order_accept_date", inplace=True)
temp.resample("D").sum().plot(grid=True)
出力
ドロップダウン補足
なお、上のふたつの例は Dropdown
クラスを使わなくても、
store_list = m_store["store_name"].tolist()
@interact(store_name=store_list)
def order_by_store(store_name):
# 以下略
のように直接店舗名リストを渡しても同様の結果となります。
ノック22: 複数店舗の詳細を可視化できるようにしてみよう
DataFrame
の表示
複数選択した項目で店舗名を絞り込んだ m_store_list_0 = SelectMultiple(
options=store_list,
discription="store_names"
)
@interact(store_names=m_store_list_0)
def order_by_multi(store_names):
pick_data = pick_data = order_data.loc[
(order_data["store_name"].isin(store_names))
& (order_data["status"].isin([1, 2]))
]
return pick_data.head()
出力
複数選択した項目で店舗名を絞り込んだ折れ線グラフの表示
m_store_list_1 = SelectMultiple(
options=store_list,
discription="store_names"
)
@interact(store_names=m_store_list_1)
def graph_by_multi(store_names):
fig = plt.figure(figsize=(17, 4))
plt.subplots_adjust(wspace=0.25, hspace=0.6)
n = len(store_names)
i = 0
for trg in store_names:
pick_data = order_data[
(order_data["store_name"] == trg)
& (order_data["status"].isin([1, 2]))
]
temp = pick_data[["order_accept_date",
"total_amount",
"store_name"]].copy()
temp.loc[:, "order_accept_date"] = pd.to_datetime(temp["order_accept_date"])
temp.set_index("order_accept_date", inplace=True)
i += 1
# y軸を共通化して比較しやすくしてみた。
if i == 1:
ax = fig.add_subplot(1, n, i)
_ax = ax
else:
ax = fig.add_subplot(1, n, i, sharey=_ax)
ax.plot(temp.resample("D").sum())
ax.set_title(trg)
ax.grid()
出力
ノック23: スライドバーを用いてオーダー件数を調べてみよう
スライドバーで閾値を指定して、閾値未満または閾値より大きいオーダー件数の店舗名を表示します。
slider_0 = IntSlider(
value=1100,
min=1000,
max=2000,
step=100,
description="件数:"
)
@interact(th=slider_0)
def store_lower(th):
temp = order_data.groupby("store_name")
print(temp.size()[temp.size() < th])
出力
slider_1 = IntSlider(
value=1600,
min=1000,
max=2000,
step=100,
description="件数:"
)
@interact(th=slider_1)
def store_upper(th):
temp = order_data.groupby("store_name")
print(temp.size()[temp.size() > th])
出力
ノック24: トグルボタンで地域データを抽出しよう
DataFrame
の表示
トグルボタンで選択した地域で絞り込んだ area_list = m_area["wide_area"].unique()
toggle_buttons_0 = ToggleButtons(
options=area_list
)
@interact(area=toggle_buttons_0)
def order_by_area(area):
pick_data = order_data.loc[
(order_data["wide_area"] == area)
& (order_data["status"].isin([1, 2]))
]
return pick_data.head()
出力
トグルボタンで選択した地域で絞り込んだ折れ線グラフの表示
toggle_buttons_1 = ToggleButtons(
options=area_list
)
@interact(area=toggle_buttons_1)
def graph_by_area(area):
pick_data = pick_data = order_data.loc[
(order_data["wide_area"] == area)
& (order_data["status"].isin([1, 2]))
]
temp = pick_data[["order_accept_date", "total_amount"]].copy()
temp.loc[:, "order_accept_date"] = pd.to_datetime(temp["order_accept_date"])
temp.set_index("order_accept_date", inplace=True)
temp.resample("D").sum().plot(grid=True)
出力
ノック25: 日付を指定してデータを抽出してみよう
カレンダーのようなUIから日付を指定するための DatePicker
を使って日付指定を行います。
order_data.loc[:, "order_date"] = \
pd.to_datetime(order_data["order_accept_date"]).dt.date
date_picker_0 = DatePicker(
value=datetime.datetime(2020, 4, 1)
)
@interact(date=date_picker_0)
def order_by_date(date):
pick_data = order_data.loc[
(order_data["order_date"] == date)
& (order_data["status"].isin([1, 2]))
]
print(f"{len(pick_data)=}\n")
return pick_data.head()
出力
date_picker_1 = DatePicker(
value=datetime.date(2020, 4, 1)
)
date_picker_2 = DatePicker(
value=datetime.date(2020, 4, 30)
)
@interact(start=date_picker_1, end=date_picker_2)
def order_between_date(start, end):
pick_data = order_data.loc[
(order_data["order_date"] >= start)
& (order_data["order_date"] <= end)
& (order_data["status"].isin([1, 2]))
]
print(f"{len(pick_data)=}\n")
return pick_data.head()
出力
まとめ
ひととおり書籍3章で扱われているウィジェットをJupyterLabでも使えるようにできました。書籍本文のよりもコード記述量が少なくなり、シンプルになりますね!やはりJupyterLabはイケてる👍
Discussion