データサイエンス100本ノック 51~60#
import polars as pl
from helper.polars import load_100knocks_data
pl.Config.set_fmt_str_lengths(100)
df_customer, df_category, df_product, df_receipt, df_store, df_geocode = load_100knocks_data()
P-051#
レシート明細データ(df_receipt)の売上エポック秒を日付型に変換し、「日」だけ取り出してレシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに10件表示せよ。なお、「日」は0埋め2桁で取り出すこと。
(
df_receipt
.select(
pl.col('receipt_no', 'receipt_sub_no'),
pl.from_epoch(pl.col.sales_epoch).dt.day().cast(str).str.pad_start(2, '0')
)
.head()
)
| receipt_no | receipt_sub_no | sales_epoch |
|---|---|---|
| i64 | i64 | str |
| 112 | 1 | "03" |
| 1132 | 2 | "18" |
| 1102 | 1 | "12" |
| 1132 | 1 | "05" |
| 1102 | 2 | "21" |
P-052#
レシート明細データ(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計の上、売上金額合計に対して2,000円以下を0、2,000円より大きい金額を1に二値化し、顧客ID、売上金額合計とともに10件表示せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。
(
df_receipt
.filter(
pl.col.customer_id.str.starts_with('Z').not_()
)
.group_by(
'customer_id', maintain_order=True
)
.agg(
sum_amount=pl.col.amount.sum()
)
.with_columns(
sales_flg=pl.when(pl.col.sum_amount >= 2000).then(1).otherwise(0)
)
.head()
)
| customer_id | sum_amount | sales_flg |
|---|---|---|
| str | i64 | i32 |
| "CS006214000001" | 7364 | 1 |
| "CS008415000097" | 1895 | 0 |
| "CS028414000014" | 6222 | 1 |
| "CS025415000050" | 5736 | 1 |
| "CS003515000195" | 5412 | 1 |
P-053#
顧客データ(df_customer)の郵便番号(postal_cd)に対し、東京(先頭3桁が100〜209のもの)を1、それ以外のものを0に二値化せよ。さらにレシート明細データ(df_receipt)と結合し、全期間において売上実績のある顧客数を、作成した二値ごとにカウントせよ。
(
df_receipt
.join(
df_customer
.select(
'customer_id',
postal_flg=pl.col.postal_cd
.str.slice(0, 3)
.cast(pl.UInt16)
.is_between(100, 209)
.cast(pl.UInt8)
),
on='customer_id',
how='inner'
)
.group_by(
'postal_flg'
)
.agg(customer_cnt=pl.col.customer_id.n_unique())
)
| postal_flg | customer_cnt |
|---|---|
| u8 | u32 |
| 0 | 3906 |
| 1 | 4400 |
P-054#
顧客データ(df_customer)の住所(address)は、埼玉県、千葉県、東京都、神奈川県のいずれかとなっている。都道府県毎にコード値を作成し、顧客ID、住所とともに10件表示せよ。値は埼玉県を11、千葉県を12、東京都を13、神奈川県を14とすること。
names = ['埼玉県', '千葉県', '東京都', '神奈川県']
codes = [11, 12, 13, 14]
(
df_customer
.select(
'customer_id', 'address',
prefecture_cd=pl.col.address
.str.extract('^(.*?[都道府県])')
.replace(names, codes)
)
.head()
)
| customer_id | address | prefecture_cd |
|---|---|---|
| str | str | str |
| "CS021313000114" | "神奈川県伊勢原市粟窪**********" | "14" |
| "CS037613000071" | "東京都江東区南砂**********" | "13" |
| "CS031415000172" | "東京都渋谷区代々木**********" | "13" |
| "CS028811000001" | "神奈川県横浜市泉区和泉町**********" | "14" |
| "CS001215000145" | "東京都大田区仲六郷**********" | "13" |
P-055#
レシート明細(df_receipt)データの売上金額(amount)を顧客ID(customer_id)ごとに合計し、その合計金額の四分位点を求めよ。その上で、顧客ごとの売上金額合計に対して次の基準でカテゴリ値を作成し、顧客ID、売上金額合計とともに10件表示せよ。カテゴリ値は順に1〜4とする。
最小値以上第1四分位未満 ・・・ 1を付与
第1四分位以上第2四分位未満 ・・・ 2を付与
第2四分位以上第3四分位未満 ・・・ 3を付与
第3四分位以上 ・・・ 4を付与
(
df_receipt
.group_by("customer_id", maintain_order=True)
.agg(sum_amount=pl.col.amount.sum())
.with_columns(
# 2.0 では qcut の代わりに bin_quantiles を使う(既定は左閉区間)
pct_group=pl.col.sum_amount.bin_quantiles(
[0.25, 0.5, 0.75], labels=["1", "2", "3", "4"]
)
)
.head(10)
)
| customer_id | sum_amount | pct_group |
|---|---|---|
| str | i64 | enum |
| "CS006214000001" | 7364 | "4" |
| "CS008415000097" | 1895 | "3" |
| "CS028414000014" | 6222 | "4" |
| "ZZ000000000000" | 12395003 | "4" |
| "CS025415000050" | 5736 | "4" |
| "CS003515000195" | 5412 | "4" |
| "CS024514000042" | 533 | "1" |
| "CS040415000178" | 6149 | "4" |
| "CS027514000015" | 2788 | "3" |
| "CS025415000134" | 4902 | "4" |
P-056#
顧客データ(df_customer)の年齢(age)をもとに10歳刻みで年代を算出し、顧客ID(customer_id)、生年月日(birth_day)とともに10件表示せよ。ただし、60歳以上は全て60歳代とすること。年代を表すカテゴリ名は任意とする。
(
df_customer
.select(
'customer_id', 'birth_day',
(pl.col.age // 10 * 10).clip(upper_bound=60)
)
.head(10)
)
| customer_id | birth_day | age |
|---|---|---|
| str | str | i64 |
| "CS021313000114" | "1981-04-29" | 30 |
| "CS037613000071" | "1952-04-01" | 60 |
| "CS031415000172" | "1976-10-04" | 40 |
| "CS028811000001" | "1933-03-27" | 60 |
| "CS001215000145" | "1995-03-29" | 20 |
| "CS020401000016" | "1974-09-15" | 40 |
| "CS015414000103" | "1977-08-09" | 40 |
| "CS029403000008" | "1973-08-17" | 40 |
| "CS015804000004" | "1931-05-02" | 60 |
| "CS033513000180" | "1962-07-11" | 50 |
P-057#
056の抽出結果と性別コード(gender_cd)により、新たに性別×年代の組み合わせを表すカテゴリデータを作成し、10件表示せよ。組み合わせを表すカテゴリの値は任意とする。
(
df_customer
.select(
'customer_id', 'birth_day',
gender_era=
pl.col.gender_cd +
((pl.col.age // 10 * 10).clip(upper_bound=60) + 100)
.cast(str)
.str.slice(1, 2)
)
.head(10)
)
| customer_id | birth_day | gender_era |
|---|---|---|
| str | str | str |
| "CS021313000114" | "1981-04-29" | "130" |
| "CS037613000071" | "1952-04-01" | "960" |
| "CS031415000172" | "1976-10-04" | "140" |
| "CS028811000001" | "1933-03-27" | "160" |
| "CS001215000145" | "1995-03-29" | "120" |
| "CS020401000016" | "1974-09-15" | "040" |
| "CS015414000103" | "1977-08-09" | "140" |
| "CS029403000008" | "1973-08-17" | "040" |
| "CS015804000004" | "1931-05-02" | "060" |
| "CS033513000180" | "1962-07-11" | "150" |
P-058#
顧客データ(df_customer)の性別コード(gender_cd)をダミー変数化し、顧客ID(customer_id)とともに10件表示せよ。
(
pl.concat([
df_customer.select('customer_id'),
df_customer.get_column('gender_cd').to_dummies()
], how='horizontal')
.head()
)
| customer_id | gender_cd_0 | gender_cd_1 | gender_cd_9 |
|---|---|---|---|
| str | u8 | u8 | u8 |
| "CS021313000114" | 0 | 1 | 0 |
| "CS037613000071" | 0 | 0 | 1 |
| "CS031415000172" | 0 | 1 | 0 |
| "CS028811000001" | 0 | 1 | 0 |
| "CS001215000145" | 0 | 1 | 0 |
P-059#
レシート明細データ(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計し、売上金額合計を平均0、標準偏差1に標準化して顧客ID、売上金額合計とともに10件表示せよ。標準化に使用する標準偏差は、分散の平方根、もしくは不偏分散の平方根のどちらでも良いものとする。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。
TIPS:
query()の引数engineで'python'か'numexpr'かを選択でき、デフォルトはインストールされていればnumexprが、無ければpythonが使われます。さらに、文字列メソッドはengine='python'でないとquery()内で使えません。
(
df_receipt
.filter(
pl.col.customer_id.str.starts_with('Z').not_()
)
.group_by('customer_id')
.agg(
sum_amount=pl.col.amount.sum()
)
.with_columns(
std_amount=(pl.col.sum_amount - pl.col.sum_amount.mean()) / pl.col.sum_amount.std()
)
.head(10)
)
| customer_id | sum_amount | std_amount |
|---|---|---|
| str | i64 | f64 |
| "CS016515000226" | 6488 | 1.448265 |
| "CS010803000005" | 93 | -0.902255 |
| "CS008414000057" | 9675 | 2.619666 |
| "CS011415000276" | 1688 | -0.316003 |
| "CS016413000152" | 576 | -0.724726 |
| "CS023512000159" | 1208 | -0.49243 |
| "CS037415000100" | 12147 | 3.528265 |
| "CS027212000007" | 801 | -0.642026 |
| "CS004215000009" | 1450 | -0.403482 |
| "CS030412000203" | 276 | -0.834992 |
P-060#
レシート明細データ(df_receipt)の売上金額(amount)を顧客ID(customer_id)ごとに合計し、売上金額合計を最小値0、最大値1に正規化して顧客ID、売上金額合計とともに10件表示せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。
(
df_receipt
.filter(
pl.col.customer_id.str.starts_with('Z').not_()
)
.group_by('customer_id')
.agg(
sum_amount=pl.col.amount.sum()
)
.with_columns(
std_amount=(pl.col.sum_amount - pl.col.sum_amount.min()) / (pl.col.sum_amount.max() - pl.col.sum_amount.min())
)
.head(10)
)
| customer_id | sum_amount | std_amount |
|---|---|---|
| str | i64 | f64 |
| "CS038413000133" | 546 | 0.020681 |
| "CS032411000023" | 1308 | 0.053789 |
| "CS004415000607" | 200 | 0.005648 |
| "CS004415000399" | 4438 | 0.189781 |
| "CS001413000427" | 633 | 0.024461 |
| "CS013412000093" | 1280 | 0.052572 |
| "CS019514000043" | 1252 | 0.051356 |
| "CS018513000109" | 1520 | 0.063 |
| "CS005512000033" | 430 | 0.015641 |
| "CS019412000140" | 753 | 0.029675 |