【解説】データサイエンス100本ノック【問89〜90回答】

【解説】データサイエンス100本ノック【問89〜90回答】

当ページのリンクには広告が含まれています。


目次


データサイエンス100本ノックの始め方は、以下の記事を参考にしていただければと思います。


>>データサイエンス100本ノックの始め方を確認する


第89問目:データ分割(レコードデータの分割)

P-089: 売上実績のある顧客に対し、予測モデル構築のため学習用データとテスト用データに分割したい。それぞれ8:2の割合でランダムにデータを分割せよ。

データを分割するには、sklearn.model_selection.train_test_split関数を使用します。

train_test_split関数は、pandas.Dataframeやnumpy.ndarrayなどに対してデータをランダムに分割することができます。
また、データを分析する際には、再現性を担保するためにrandom_stateを使用します。
このrandom_stateを指定することで、生成される乱数が同じになります。

train_test_split関数とrandom_stateについてはデータサイエンス100本ノックの第75問目でも扱っていますので、そちらも参照ください。

【解説】データサイエンス100本ノック【問75〜76 回答】 - omathin blog

それでは早速学習用データとテスト用データに分割してみましょう。

まずは顧客ごとの売上金額合計を算出します。

1
2
df_sales = df_receipt.groupby('customer_id').agg({'amount':'sum'}).reset_index()
df_sales.head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	customer_id	amount
0 CS001113000004 1298
1 CS001114000005 626
2 CS001115000010 3044
3 CS001205000004 1988
4 CS001205000006 3337
5 CS001211000025 456
6 CS001212000027 448
7 CS001212000031 296
8 CS001212000046 228
9 CS001212000070 456

df_salesにある顧客のみをdf_customerから抽出することで、売上実績のある顧客を取り出します。

取り出し方は、内部結合を行えばOKです。

1
2
df_tmp = pd.merge(df_customer, df_sales['customer_id'], how='inner', on='customer_id')
df_tmp.head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	customer_id	customer_name	gender_cd	gender	birth_day	age	postal_cd	address	application_store_cd	application_date	status_cd
0 CS031415000172 宇多田 貴美子 1 女性 1976-10-04 42 151-0053 東京都渋谷区代々木********** S13031 20150529 D-20100325-C
1 CS001215000145 田崎 美紀 1 女性 1995-03-29 24 144-0055 東京都大田区仲六郷********** S13001 20170605 6-20090929-2
2 CS015414000103 奥野 陽子 1 女性 1977-08-09 41 136-0073 東京都江東区北砂********** S13015 20150722 B-20100609-B
3 CS033513000180 安斎 遥 1 女性 1962-07-11 56 241-0823 神奈川県横浜市旭区善部町********** S14033 20150728 6-20080506-5
4 CS011215000048 芦田 沙耶 1 女性 1992-02-01 27 223-0062 神奈川県横浜市港北区日吉本町********** S14011 20150228 C-20100421-9
5 CS040412000191 川井 郁恵 1 女性 1977-01-05 42 226-0021 神奈川県横浜市緑区北八朔町********** S14040 20151101 1-20091025-4
6 CS029415000023 梅田 里穂 1 女性 1976-01-17 43 279-0043 千葉県浦安市富士見********** S12029 20150610 D-20100918-E
7 CS009315000023 皆川 文世 1 女性 1980-04-15 38 154-0012 東京都世田谷区駒沢********** S13009 20150319 5-20080322-1
8 CS035415000029 寺沢 真希 9 不明 1977-09-27 41 158-0096 東京都世田谷区玉川台********** S13035 20141220 F-20101029-F
9 CS015315000033 福士 璃奈子 1 女性 1983-03-17 36 135-0043 東京都江東区塩浜********** S13015 20141024 4-20080219-3

問題の指定通り8:2の割合でランダムにデータを分割します。

1
2
3
df_train, df_test = train_test_split(df_tmp, test_size=0.2, random_state=1)
print('学習データ割合:', len(df_train) / len(df_tmp))
print('テストデータ割合:', len(df_test) / len(df_tmp))
出力
1
2
学習データ割合: 0.7999036840837949
テストデータ割合: 0.20009631591620516

第90問目:データ分割(時系列データの分割)

P-090: レシート明細データフレーム(df_receipt)は2017年1月1日〜2019年10月31日までのデータを有している。売上金額(amount)を月次で集計し、学習用に12ヶ月、テスト用に6ヶ月のモデル構築用データを3セット作成せよ。

まずはdf_receiptの構造を確認します。

1
df_receipt.head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	sales_ymd	sales_epoch	store_cd	receipt_no	receipt_sub_no	customer_id	product_cd	quantity	amount
0 20181103 1541203200 S14006 112 1 CS006214000001 P070305012 1 158
1 20181118 1542499200 S13008 1132 2 CS008415000097 P070701017 1 81
2 20170712 1499817600 S14028 1102 1 CS028414000014 P060101005 1 170
3 20190205 1549324800 S14042 1132 1 ZZ000000000000 P050301001 1 25
4 20180821 1534809600 S14025 1102 2 CS025415000050 P060102007 1 90
5 20190605 1559692800 S13003 1112 1 CS003515000195 P050102002 1 138
6 20181205 1543968000 S14024 1102 2 CS024514000042 P080101005 1 30
7 20190922 1569110400 S14040 1102 1 CS040415000178 P070501004 1 128
8 20170504 1493856000 S13020 1112 2 ZZ000000000000 P071302010 1 770
9 20191010 1570665600 S14027 1102 1 CS027514000015 P071101003 1 680

まずは、日付データであるsales_ymdと売上金額のamountを抽出します。

1
df_tmp = df_receipt[['sales_ymd', 'amount']].copy()

月次で集計する必要があるので、西暦と月のみにし、sales_ymに代入します。

1
2
df_tmp['sales_ym'] = df_tmp['sales_ymd'].astype('str').str[0:6]
df_tmp.head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
12

sales_ymd amount sales_ym
0 20181103 158 201811
1 20181118 81 201811
2 20170712 170 201707
3 20190205 25 201902
4 20180821 90 201808
5 20190605 138 201906
6 20181205 30 201812
7 20190922 128 201909
8 20170504 770 201705
9 20191010 680 201910

月ごとのamountを算出します。

1
2
df_tmp = df_tmp.groupby('sales_ym').agg({'amount':'sum'}).reset_index()
df_tmp.head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	sales_ym	amount
0 201701 902056
1 201702 764413
2 201703 962945
3 201704 847566
4 201705 884010
5 201706 894242
6 201707 959205
7 201708 954836
8 201709 902037
9 201710 905739

ここからデータを分割していきます。
学習用に12ヶ月分、テスト用に6ヶ月のデータを3セット用意します。
3セット分なので、スライスで3つ分数値を直接書き込んで3セット用意しても良いですが、ここではデータを分割する関数を定義して処理していきます。

1
2
3
4
5
6
7
8
9
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_tmp, train_size=12, test_size=6, slide_window=6, start_point=0)
df_train_2, df_test_2 = split_data(df_tmp, train_size=12, test_size=6, slide_window=6, start_point=1)
df_train_3, df_test_3 = split_data(df_tmp, train_size=12, test_size=6, slide_window=6, start_point=2)
print(df_train_3)
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
   sales_ym   amount
12 201801 944509
13 201802 864128
14 201803 946588
15 201804 937099
16 201805 1004438
17 201806 1012329
18 201807 1058472
19 201808 1045793
20 201809 977114
21 201810 1069939
22 201811 967479
23 201812 1016425

まとめ:データの分割を学びました。

本記事で紹介した方法を元にデータサイエンティストとしての知見を深めていただければと思います。

データサイエンティストに必要な知識は、TechAcademyのデータサイエンスコースでの学習がおすすめです。

無料体験可能なのでご確認ください。

コメント