6 minutes
データサイエンス100本ノックをPythonでやってみた [51-60]
データサイエンス 100 本ノックとは
The-Japan-DataScientist-Society/100knocks-preprocess: データサイエンス 100 本ノック(構造化データ加工編)
Google Colab で データサイエンス 100 本ノックをするにあたって
以下の ipynb ファイルを使用させていただきました。
実行ファイル
データサイエンス 100 本ノック by tomowarkar
051
P-051: レシート明細データフレーム(df_receipt)の売上エポック秒(sales_epoch)を日付型(timestamp 型)に変換し、“日"だけ取り出してレシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに抽出せよ。なお、“日"は 0 埋め 2 桁で取り出すこと。データは 10 件を抽出すれば良い。
50 と同じようにしてもできるが、違う方法で解く
pd.concat(
[pd.to_datetime(df_receipt.sales_epoch, unit='s').map(lambda x: "{:02d}".format(x.day)),
df_receipt[["receipt_no", "receipt_sub_no"]]],
axis=1
).head(10)
sales_epoch receipt_no receipt_sub_no
0 03 112 1
1 18 1132 2
2 12 1102 1
3 05 1132 1
4 21 1102 2
5 05 1112 1
6 05 1102 2
7 22 1102 1
8 04 1112 2
9 10 1102 1
052
P-052: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計の上、売上金額合計に対して 2000 円以下を 0、2000 円超を 1 に 2 値化し、顧客 ID、売上金額合計とともに 10 件表示せよ。ただし、顧客 ID が"Z"から始まるのものは非会員を表すため、除外して計算すること。
tmp = df_receipt[~df_receipt.customer_id.str.startswith("Z")]\
.groupby("customer_id").amount.sum()
pd.DataFrame(
[tmp, tmp.map(lambda x: 0 if x <= 2000 else 1)],
index=["amount", "flag"]
).T.head(10)
amount flag
customer_id
CS001113000004 1298 0
CS001114000005 626 0
CS001115000010 3044 1
CS001205000004 1988 0
CS001205000006 3337 1
CS001211000025 456 0
CS001212000027 448 0
CS001212000031 296 0
CS001212000046 228 0
CS001212000070 456 0
053
P-053: 顧客データフレーム(df_customer)の郵便番号(postal_cd)に対し、東京(先頭 3 桁が 100〜209 のもの)を 1、それ以外のものを 0 に2値化せよ。さらにレシート明細データフレーム(df_receipt)と結合し、全期間において買い物実績のある顧客数を、作成した 2 値ごとにカウントせよ。
pd.merge(
pd.concat(
[df_customer.customer_id, df_customer.postal_cd.str.match("1\d\d|20\d").map(lambda x: 1 if x else 0)],
axis=1
),
df_receipt.customer_id, how="inner", on="customer_id"
).groupby("postal_cd").agg({"customer_id":"nunique"})
customer_id
postal_cd
0 3906
1 4400
別解
tmp = df_customer[["customer_id", "postal_cd"]].copy()
tmp["flag"] = tmp.postal_cd.str.match("1\d\d|20\d").map(lambda x: 1 if x else 0)
# tmp["flag"] = tmp.postal_cd.map(lambda x: 1 if 100<=int(x[:3])<=209 else 0)
pd.merge(
tmp,
pd.Series(df_receipt.customer_id.unique(), name="customer_id"),
how="inner",
on="customer_id"
).groupby("flag").customer_id.count()
054
P-054: 顧客データデータフレーム(df_customer)の住所(address)は、埼玉県、千葉県、東京都、神奈川県のいずれかとなっている。都道府県毎にコード値を作成し、顧客 ID、住所とともに抽出せよ。値は埼玉県を 11、千葉県を 12、東京都を 13、神奈川県を 14 とすること。結果は 10 件表示させれば良い。
pd.concat([df_customer[["customer_id", "address"]],
pd.Series(
df_customer.address.str[:3].map({"埼玉県":11, "千葉県":12, "東京都":13, "神奈川":14}),
name="address_cd")],
axis=1
).head(10)
customer_id address address_cd
0 CS021313000114 神奈川県伊勢原市粟窪********** 14
1 CS037613000071 東京都江東区南砂********** 13
2 CS031415000172 東京都渋谷区代々木********** 13
3 CS028811000001 神奈川県横浜市泉区和泉町********** 14
4 CS001215000145 東京都大田区仲六郷********** 13
5 CS020401000016 東京都板橋区若木********** 13
6 CS015414000103 東京都江東区北砂********** 13
7 CS029403000008 千葉県浦安市海楽********** 12
8 CS015804000004 東京都江東区北砂********** 13
9 CS033513000180 神奈川県横浜市旭区善部町********** 14
055
P-055: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計し、その合計金額の四分位点を求めよ。その上で、顧客ごとの売上金額合計に対して以下の基準でカテゴリ値を作成し、顧客 ID、売上金額と合計ともに表示せよ。カテゴリ値は上から順に 1〜4 とする。結果は 10 件表示させれば良い。
- 最小値以上第一四分位未満
- 第一四分位以上第二四分位未満
- 第二四分位以上第三四分位未満
- 第三四分位以上
32 でも使ったpandas.Series.quantile
を使う
tmp = df_receipt.groupby("customer_id").agg({"amount":"sum"})
quarter = tmp.amount.quantile([i/100 for i in range(25, 76, 25)]).values
def f(x):
if x < quarter[0]: return 1
if quarter[0] <= x < quarter[1]: return 2
if quarter[1] <= x < quarter[2]: return 3
return 4
tmp["cat_cd"] = tmp.amount.map(f)
tmp.head(10)
amount cat_cd
customer_id
CS001113000004 1298 2
CS001114000005 626 2
CS001115000010 3044 3
CS001205000004 1988 3
CS001205000006 3337 3
CS001211000025 456 1
CS001212000027 448 1
CS001212000031 296 1
CS001212000046 228 1
CS001212000070 456 1
056
P-056: 顧客データフレーム(df_customer)の年齢(age)をもとに 10 歳刻みで年代を算出し、顧客 ID(customer_id)、生年月日(birth_day)とともに抽出せよ。ただし、60 歳以上は全て 60 歳代とすること。年代を表すカテゴリ名は任意とする。先頭 10 件を表示させればよい。
pd.concat(
[df_customer[["customer_id", "birth_day"]],
pd.Series(df_customer.age.map(lambda x: x//10*10 if x < 60 else 60), name="age_cd")],
axis=1
).head(10)
customer_id birth_day age_cd
0 CS021313000114 1981-04-29 30
1 CS037613000071 1952-04-01 60
2 CS031415000172 1976-10-04 40
3 CS028811000001 1933-03-27 60
4 CS001215000145 1995-03-29 20
5 CS020401000016 1974-09-15 40
6 CS015414000103 1977-08-09 40
7 CS029403000008 1973-08-17 40
8 CS015804000004 1931-05-02 60
9 CS033513000180 1962-07-11 50
057
P-057: 前問題の抽出結果と性別(gender)を組み合わせ、新たに性別 × 年代の組み合わせを表すカテゴリデータを作成せよ。組み合わせを表すカテゴリの値は任意とする。先頭 10 件を表示させればよい
pd.concat(
[df_customer[["customer_id", "birth_day", "gender"]],
pd.Series(
["{:02d}{:02d}".format(g, a) for g, a in zip(df_customer.gender_cd, df_customer.age.map(lambda x: x//10*10 if x < 60 else 60))], name="gen_age")],
axis=1
).head(10)
customer_id birth_day gender gen_age
0 CS021313000114 1981-04-29 女性 0130
1 CS037613000071 1952-04-01 不明 0960
2 CS031415000172 1976-10-04 女性 0140
3 CS028811000001 1933-03-27 女性 0160
4 CS001215000145 1995-03-29 女性 0120
5 CS020401000016 1974-09-15 男性 0040
6 CS015414000103 1977-08-09 女性 0140
7 CS029403000008 1973-08-17 男性 0040
8 CS015804000004 1931-05-02 男性 0060
9 CS033513000180 1962-07-11 女性 0150
058
P-058: 顧客データフレーム(df_customer)の性別コード(gender_cd)をダミー変数化し、顧客 ID(customer_id)とともに抽出せよ。結果は 10 件表示させれば良い。
pandas.get_dummies
を使う
pd.get_dummies(
df_customer[["customer_id", "gender_cd"]],
columns=["gender_cd"],
prefix_sep='_'
).head(10)
customer_id gender_cd_0 gender_cd_1 gender_cd_9
0 CS021313000114 0 1 0
1 CS037613000071 0 0 1
2 CS031415000172 0 1 0
3 CS028811000001 0 1 0
4 CS001215000145 0 1 0
5 CS020401000016 1 0 0
6 CS015414000103 0 1 0
7 CS029403000008 1 0 0
8 CS015804000004 1 0 0
9 CS033513000180 0 1 0
059
P-059: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計し、合計した売上金額を平均 0、標準偏差 1 に標準化して顧客 ID、売上金額合計とともに表示せよ。標準化に使用する標準偏差は、不偏標準偏差と標本標準偏差のどちらでも良いものとする。ただし、顧客 ID が"Z"から始まるのものは非会員を表すため、除外して計算すること。結果は 10 件表示させれば良い。
tmp = df_receipt[~df_receipt.customer_id.str.startswith("Z")].groupby("customer_id").amount.sum()
pd.concat(
[tmp,
pd.Series((tmp - tmp.mean()) / tmp.std(), name="standardization")],
axis=1
).head(10)
amount standardization
customer_id
CS001113000004 1298 -0.459350
CS001114000005 626 -0.706348
CS001115000010 3044 0.182403
CS001205000004 1988 -0.205737
CS001205000006 3337 0.290096
CS001211000025 456 -0.768832
CS001212000027 448 -0.771773
CS001212000031 296 -0.827641
CS001212000046 228 -0.852635
CS001212000070 456 -0.768832
060
P-060: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計し、合計した売上金額を最小値 0、最大値 1 に正規化して顧客 ID、売上金額合計とともに表示せよ。ただし、顧客 ID が"Z"から始まるのものは非会員を表すため、除外して計算すること。結果は 10 件表示させれば良い。
tmp = df_receipt[~df_receipt.customer_id.str.startswith("Z")].groupby("customer_id").amount.sum()
pd.concat(
[tmp,
pd.Series((tmp - tmp.min()) / (tmp.max() - tmp.min()), name="normalization")],
axis=1
).head(10)
amount normalization
customer_id
CS001113000004 1298 0.053354
CS001114000005 626 0.024157
CS001115000010 3044 0.129214
CS001205000004 1988 0.083333
CS001205000006 3337 0.141945
CS001211000025 456 0.016771
CS001212000027 448 0.016423
CS001212000031 296 0.009819
CS001212000046 228 0.006865
CS001212000070 456 0.016771