

データサイエンティスト協会の100本ノックがGitHubに公開しているデータとPythonコードを初心者にでも分かるように解説していきます。
今回は89~92本です。内容は主に、データから新たなデータを作成する「データのサンプリングと正規化の方法」について解説していきます。
Pythonの環境設定は以下の記事を参考にして下さい。
【2021年最新】M1 mac でanacondaをインストールする方法
【2021年最新】WindowsでAnacondaをインストールする方法
- サンプリングと正規化する方法
- P-089: 売上実績のある顧客に対し、予測モデル構築のため学習用データとテスト用データに分割したい。それぞれ8:2の割合でランダムにデータを分割せよ。
- P-090: レシート明細データフレーム(df_receipt)は2017年1月1日〜2019年10月31日までのデータを有している。売上金額(amount)を月次で集計し、学習用に12ヶ月、テスト用に6ヶ月のモデル構築用データを3セット作成せよ。
- P-091: 顧客データフレーム(df_customer)の各顧客に対し、売上実績のある顧客数と売上実績のない顧客数が1:1となるようにアンダーサンプリングで抽出せよ。
- P-092: 顧客データフレーム(df_customer)では、性別に関する情報が非正規化の状態で保持されている。これを第三正規化せよ。
サンプリングと正規化する方法
まずは、以下からダウンロードして下さい。
P-089: 売上実績のある顧客に対し、予測モデル構築のため学習用データとテスト用データに分割したい。それぞれ8:2の割合でランダムにデータを分割せよ。
import pandas as pd df_customer = pd.read_csv("customer.csv") df_receipt = pd.read_csv("receipt.csv") from sklearn.model_selection import train_test_split df_sales = df_receipt.groupby("customer_id").agg({"amount":"sum"}).reset_index() df_89 = pd.merge(df_customer,df_sales["customer_id"],how="inner",on="customer_id") df_train,df_test = train_test_split(df_89,test_size=0.2,random_state=1) print("学習データ割合 :",len(df_train)/len(df_89)) print("テストデータ割合:",len(df_test)/len(df_89))
出力:
上2行のコードは過去に解説した通りです。
1行目:顧客ID(customer_id)ごとの売り上げ(amount)の合計(sum)のデータを作成する。
2行目:作成したデータと顧客データ(df_customer)を顧客を一致させた状態で結合する
そして、結合させたデータを train_test_split で2分割します。train_test_split は機械学習では必ず使うものです。過去に機械学習の方法を解説したときに使用しました。訓練用のデータを train 、機械学習の精度を評価するためのデータを test として分割します。
割合の決定は、test_size=0.2 と指定しているため、訓練データが80%、テストデータが20%となるはずです。
print() で確認しています。
学習データ割合:0.799….
テストデータ割合:0.200….
出力結果からほぼ8:2になっていることが確認できます。
P-090: レシート明細データフレーム(df_receipt)は2017年1月1日〜2019年10月31日までのデータを有している。売上金額(amount)を月次で集計し、学習用に12ヶ月、テスト用に6ヶ月のモデル構築用データを3セット作成せよ。
df_90 = df_receipt[["sales_ymd","amount"]].copy() df_90["sales_ym"] = df_90["sales_ymd"].astype("str").str[0:6] df_90 = df_90.groupby("sales_ym").agg({"amount":"sum"}).reset_index() def split_data(df,train_size,test_size,slide_window,start_point): train_start = start_point * slide_window test_start = train_start + train_size return df[train_start : test_start],df[test_start : test_start + test_size] df_train_1, df_test_1 = split_data(df_90, train_size=12, test_size=6, slide_window=6, start_point=0) df_train_2, df_test_2 = split_data(df_90, train_size=12, test_size=6, slide_window=6, start_point=1) df_train_3, df_test_3 = split_data(df_90, train_size=12, test_size=6, slide_window=6, start_point=2)
出力結果を確認してみましょう。今回は、6つのデータを作成したのでそれぞれみてみましょう。
もう少し確認してみましょう。
df_train_1 は0〜11の12行、df_test_1 は12〜17の6行を抽出
df_train_2 は6〜17の12行、df_test_2 は18〜23の6行を抽出
df_train_3 は12〜23の12行、df_test_3 は24〜29の6行を抽出されています。
今回のコードのキーとなる関数である、split_data() の内容を見てみましょう。
データを6つずらしながらサンプリングしていることが分かります。
P-091: 顧客データフレーム(df_customer)の各顧客に対し、売上実績のある顧客数と売上実績のない顧客数が1:1となるようにアンダーサンプリングで抽出せよ。
import numpy as np from imblearn.under_sampling import RandomUnderSampler df_91 = df_receipt.groupby("customer_id").agg({"amount":"sum"}).reset_index() df_91 = pd.merge(df_customer, df_91, how="left", on="customer_id") df_91["buy_flg"] = df_91["amount"].apply(lambda x: 0 if np.isnan(x) else 1) print("0の件数",len(df_91.query("buy_flg == 0"))) print("1の件数",len(df_91.query("buy_flg == 1"))) positive_count = len(df_91.query("buy_flg == 1")) rs = RandomUnderSampler(sampling_strategy={0:positive_count, 1:positive_count}, random_state=1) df_sample, _ = rs.fit_sample(df_91,df_91.buy_flg) print("0の件数",len(df_sample.query("buy_flg == 0"))) print("1の件数",len(df_sample.query("buy_flg == 1")))
出力:
0の件数 13665
1の件数 8306
0の件数 8306
1の件数 8306
出力結果はこんな感じですが、コードが長いので、分割して解説していきます。
まずは前半のコードです。
売上実績のあるなしを “buy_flg” という変数を作成します。
売上(amount)が欠損であるということは、売上実績がないということなので0にし、それ以外は売上実績があるため1としています。
次にサンプリング方法です。今回は、データ数を1:1と割合を揃えるため、アンダーサンプリングをします。
サンプリングを指定し、それを実行しています。
一番上のコード(positive_count)は意味がないですね。できれば、サンプリングの詳細を指定したほうがいいですね(上図のコード)
P-092: 顧客データフレーム(df_customer)では、性別に関する情報が非正規化の状態で保持されている。これを第三正規化せよ。
第三正規化とは、同じデータが2つ以上あるため、1つにすることです。
今回の性別に関する情報は、”gender_cd” と “gender” の2つがあるため、1つにしなければなりません。
df_gender = df_customer[["gender_cd","gender"]].drop_duplicates() print(df_gender) df_customer_s = df_customer.drop(columns="gender") df_customer_s.head()
出力:
“gender_cd” のほうが数値データで扱いやすいため、”gender” を削除しています。
もとのデータと第三正規化したデータを確認しまみましょう。
性別に関する情報が、”gender” の1つになり、第三正規化できていることが確認できました。
データサイエンティスト協会の100本ノックを解説|ダウンロードから読み込みまで
データサイエンティスト協会の100本ノックを解説|データの抽出
データサイエンティスト協会の100本ノックを解説|変数の一部を使ってデータを抽出する
データサイエンティスト協会の100本ノックを解説|ソート(順序で整列)
データサイエンティスト協会の100本ノックを解説|グループ分け
データサイエンティスト協会の100本ノック|新たなデータフレームの作成
データサイエンティスト協会の100本ノック|特徴量エンジニアリング
データサイエンティスト協会の100本ノック|時系列データの処理
データサイエンティスト協会の100本ノック|住所データの処理
コメント