🏀

【Python】実践機械学習システム100本ノック 第1章

2024/04/14に公開

この記事は、実際のビジネスの現場を想定した課題に取り組む中で、小規模で継続的にデータ分析や機械学習を回す仕組みを構築する方法を学ぶことができる「Python 実践機械学習システム100本ノック(秀和システム社)」で学んだことをまとめています。この本の記事一覧はこちら

ただし、本を参考にして自分なりに構成やコードを変更している部分が多々あるためご注意ください。また、この本を真に活かす学び方は、各章ごとに想定するプロジェクトの状況を理解しながら学ぶことだと思います。よって記事を読んでじっくりと学びたいと思った方は、是非本をお手に取って読まれてください。

目的

システムから出力したデータを人間が分析しやすい形に加工する手順を学ぶ。

Import

import os
import glob
import numpy as np
import pandas as pd
from gc import collect                                # ガーベッジコレクション
from colorama import Fore, Style, init                # Pythonの文字色指定ライブラリ
from IPython.display import display_html, clear_output
import matplotlib.pyplot as plt
%matplotlib inline
# テキスト出力の設定
def PrintColor(text:str, color = Fore.GREEN, style = Style.BRIGHT):
    print(style + color + text + Style.RESET_ALL);

# displayの表示設定
pd.set_option('display.max_columns', 50);
pd.set_option('display.max_rows', 50); 

Knock1:データを読み込む

"""データ読み込み"""
m_store     = pd.read_csv('m_store.csv')
m_area      = pd.read_csv('m_area.csv')
tbl_order_4 = pd.read_csv('tbl_order_202004.csv')
tbl_order_5 = pd.read_csv('tbl_order_202005.csv')    # Knock2で使用
#tbl_order_6 = pd.read_csv('tbl_order_202006.csv')   

"""読み込んだデータを確認"""
PrintColor(f'\n m_store:店舗マスタ')
display(m_store.head())

PrintColor(f'\n m_area:地域マスタ')
display(m_area.head())

PrintColor(f'\n tbl_order_4:4月の注文データ')
display(tbl_order_4.head())

PrintColor(f'\n tbl_order_5:5月の注文データ')
display(tbl_order_5.head())

Knock2:データを結合する

tbl_order_4とtbl_order_5を縦に結合(ユニオン)していきます。

order_all = pd.concat([tbl_order_4,
                       tbl_order_5
                      ],
                      ignore_index = True    # ラベルを振り直す
                     )

# 確認用
PrintColor(f'\n order_all')
display(order_all.head())

結合した件数があっているかどうかを確認します。

check = (len(order_all) == len(tbl_order_4) + len(tbl_order_5))

PrintColor(f'order_allの結合前後の件数確認:{check}')

Knock3:フォルダ内のファイル名を一覧化する

PythonライブラリのOSモジュールを用いてカレントディレクトリを取得します。

[参考資料]

# カレントディレクトリを取得し格納する
current_dir = os.getcwd()

# 確認用
PrintColor(f'\n current_dir')
display(current_dir)

次にディレクトリの中のファイルやフォルダを確認してみます。

os.listdir(current_dir)

ディレクトリ内のtbl_orderのファイルのみを表示させるために、以下のようにos.path.joinメソッドを用いてパスを結合します。

# パスの結合
tbl_order_file = os.path.join(current_dir, 'tbl_order_*.csv')

# 確認用
PrintColor(f'\n tbl_order_file')
display(tbl_order_file)

glob.globメソッドを用いて指定したパターンにマッチするパス名を要素とするリストを格納します。

# パターンにマッチするパス名を要素とするリストを格納する
tbl_order_files = glob.glob(tbl_order_file)

# 確認用
tbl_order_files

Knock4:複数データを結合する

Knock3で作成した注文データファイルの一覧を用いて、結合を繰り返し処理にて実行します。
しかしまずは確認として1件だけ処理を行うコードを作成します。

# 試験用のシステム
order_all  = pd.DataFrame()        # データフレームの作成
file       = tbl_order_files[0]    # パス名を要素とするリストから一つ取り出し格納
order_data = pd.read_csv(file)     # データを読み込んで格納

print(f'{file} : {len(order_data)}')
order_all = pd.concat([order_all, order_data], ignore_index = True)

# 確認用
PrintColor(f'\n order_all(試験用)')
display(order_all)

問題なく処理ができているようなので、このコードをもとに繰り返し処理ができるコードを作成します。

"""繰り返しシステムの構築"""
# 結合元のデータフレームを作成
order_all = pd.DataFrame()

for file in tbl_order_files:
    order_data = pd.read_csv(file)
    print(f'{file} : {len(order_data)}')
    order_all = pd.concat([order_all, order_data], ignore_index = True)
# 確認用
PrintColor(f'\n order_all')
display(order_all)

Knock5:データの統計量を確認する

纏めた注文データの中身を確認していきます。

# 欠損値の確認
PrintColor(f'\n order_allの欠損値')
display(order_all.isnull().sum())
# 基本統計量を表示
order_all.describe()
# 日付の最小・最大値を確認
PrintColor(f'\n order_accept_dateの最小値')
display(order_all['order_accept_date'].min())

PrintColor(f'\n order_accept_dateの最大値')
display(order_all['order_accept_date'].max())

PrintColor(f'\n delivered_dateの最小値')
display(order_all['delivered_date'].min())

PrintColor(f'\n delivered_dateの最大値')
display(order_all['delivered_date'].max())

Knock6:不要なデータを除外する

保守担当用の店舗がstore_id:999で設定されているため、保守担当店舗の注文データを除去していきます。

order_data = order_all.loc[order_all['store_id'] != 999]

# 確認用
PrintColor(f'\n ordar_data:保守担当店舗の注文データを除去')
display(order_data)
# 基本統計量を表示
order_data.describe()
# 日付の最小・最大値を確認
PrintColor(f'\n order_accept_dateの最小値')
display(order_data['order_accept_date'].min())

PrintColor(f'\n order_accept_dateの最大値')
display(order_data['order_accept_date'].max())

PrintColor(f'\n delivered_dateの最小値')
display(order_data['delivered_date'].min())

PrintColor(f'\n delivered_dateの最大値')
display(order_data['delivered_date'].max())

Knock7:マスターデータを結合する

まずはじめに、order_dataとm_storeをstore_idをキーとして結合(ジョイン)します。

order_data = pd.merge(order_data,
                      m_store,
                      on  = 'store_id',
                      how = 'left'
                     )

# 確認用
PrintColor(f'\n order_data(店舗マスタを結合)')
display(order_data)

次に、order_dataとm_areaをarea_cdをキーとして結合(ジョイン)します。

order_data = pd.merge(order_data,
                      m_area,
                      on  = 'area_cd',
                      how = 'left'
                     )

# 確認用
PrintColor(f'\n order_data(地域マスタを結合)')
display(order_data)

Knock8:マスタが存在しないコードに名称を設定する

例えば今回はtakeout_flagとstatusのマスタがないため、値が何を意味するかを読み取ることができません。今回はそれぞれの値の意味が判明したという仮定の下で、値を意味に置き換えていきます。

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'] == 9, 'status_name'] = 'キャンセル'

# 確認用
PrintColor(f'\n order_data')
display(order_data)

Knock9:分析基礎テーブルを出力する

注文データの加工が完了したので、ファイルに出力していきます。

output_dir = os.path.join(current_dir, 'output_data')

os.makedirs(output_dir, exist_ok = True)
output_file = os.path.join(output_dir, 'order_data.csv')

order_data.to_csv(output_file, index = False)

Knock10:セルを整理して使いやすくする

これまでに行ったことを一つのセルにまとめて、見やすく使いやすい形に整理します。

# ファイルの読み込み
m_store = pd.read_csv('m_store.csv')
m_area  = pd.read_csv('m_area.csv')

# オーターデータの読み込み
current_dir     = os.getcwd()
tbl_order_file  = os.path.join(current_dir, 'tbl_order_*.csv')
tbl_order_files = glob.glob(tbl_order_file)
order_all       = pd.DataFrame()

for file in tbl_order_files:
    order_data = pd.read_csv(file)
    print(f'{file} : {len(order_data)}')
    order_all  = pd.concat([order_all, order_data], ignore_index = True)

# 不要なデータを除去
order_data = order_all.loc[order_all['store_id'] != 999]

# マスタデータの結合
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'] == 9, 'status_name'] = 'キャンセル'

# ファイルの出力
output_dir = os.path.join(current_dir, 'output_data')
os.makedirs(output_dir, exist_ok = True)
output_file = os.path.join(output_dir, 'order_data.csv')
order_data.to_csv(output_file, index = False)

Discussion