【Python初心者でも分かる】データサイエンティスト協会の100本ノック|サンプリングと正規化

スポンサーリンク
Python
ゼロ知識の初心者がデータサイエンスを完全無料で学習する方法5選
データサイエンスの知識や技術、またはPythonについて学びたい。でも「大学に行くほど本気度がない」、「スクールに行くほどお金がない」、なんせ「時間がない」という方も多いはずです。というよりほとんどの方がそうだと思います(当然わたし...
ウソ情報にだまされない、研究と因果関係から読み解く情報の取捨選択
ビジネス書やビジネスYouTuberなどは、ビジネスに役立つ情報を発信しています。これらは、ビジネスパーソンにとって、自分を成長させるための有用なツールになっている。 たとえば、優秀な社員が行っている行動や考え方、ダメな社員が行ってい...

データサイエンティスト協会の100本ノックがGitHubに公開しているデータとPythonコードを初心者にでも分かるように解説していきます。

今回は89~92本です。内容は主に、データから新たなデータを作成する「データのサンプリングと正規化の方法」について解説していきます。

Pythonの環境設定は以下の記事を参考にして下さい。

【2021年最新】M1 mac でanacondaをインストールする方法

【2021年最新】WindowsでAnacondaをインストールする方法

サンプリングと正規化する方法

まずは、以下からダウンロードして下さい。

GitHubからデータをダウンロードする方法

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本ノック|変数を整える

データサイエンティスト協会の100本ノック|小数点の処理

データサイエンティスト協会の100本ノック|時系列データの処理

データサイエンティスト協会の100本ノック|欠損値の処理

データサイエンティスト協会の100本ノック|住所データの処理




コメント

タイトルとURLをコピーしました