データサイエンス100本ノック 71~80#
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-071#
レシート明細データ(df_receipt)の売上日(sales_ymd)に対し、顧客データ(df_customer)の会員申込日(application_date)からの経過月数を計算し、顧客ID(customer_id)、売上日、会員申込日とともに10件表示せよ(sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。1ヶ月未満は切り捨てること。
(
df_receipt
.select('customer_id', 'sales_ymd')
.unique(keep='first')
.join(df_customer, on='customer_id')
.select(
pl.col.customer_id,
pl.col.sales_ymd.cast(str).str.strptime(pl.Date, '%Y%m%d'),
pl.col.application_date.cast(str).str.strptime(pl.Date, '%Y%m%d')
)
.with_columns(
elapsed_months=
(pl.col.sales_ymd.dt.year() - pl.col.application_date.dt.year()) * 12 +
(pl.col.sales_ymd.dt.month() - pl.col.application_date.dt.month())
)
.head()
)
| customer_id | sales_ymd | application_date | elapsed_months |
|---|---|---|---|
| str | date | date | i32 |
| "CS003215000091" | 2018-04-09 | 2016-02-23 | 26 |
| "CS007512000016" | 2018-09-21 | 2015-09-30 | 36 |
| "CS024515000234" | 2018-11-28 | 2015-06-10 | 41 |
| "CS038515000127" | 2019-02-07 | 2015-03-25 | 47 |
| "CS021515000153" | 2018-09-29 | 2015-03-01 | 42 |
P-072#
レシート明細データ(df_receipt)の売上日(df_customer)に対し、顧客データ(df_customer)の会員申込日(application_date)からの経過年数を計算し、顧客ID(customer_id)、売上日、会員申込日とともに10件表示せよ(sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。1年未満は切り捨てること。
(
df_receipt
.select('customer_id', 'sales_ymd')
.unique(keep='first')
.join(df_customer, on='customer_id')
.select(
pl.col.customer_id,
pl.col.sales_ymd.cast(str).str.strptime(pl.Date, '%Y%m%d'),
pl.col.application_date.cast(str).str.strptime(pl.Date, '%Y%m%d')
)
.with_columns(
elapsed_years=pl.col.sales_ymd.dt.year() - pl.col.application_date.dt.year()
)
.head()
)
| customer_id | sales_ymd | application_date | elapsed_years |
|---|---|---|---|
| str | date | date | i32 |
| "CS040605000014" | 2017-02-21 | 2015-08-20 | 2 |
| "CS034414000077" | 2019-09-29 | 2015-02-20 | 4 |
| "CS013514000050" | 2017-11-10 | 2015-03-14 | 2 |
| "CS024815000009" | 2018-09-23 | 2015-08-07 | 3 |
| "CS010414000031" | 2018-01-08 | 2015-03-09 | 3 |
P-073#
レシート明細データ(df_receipt)の売上日(sales_ymd)に対し、顧客データ(df_customer)の会員申込日(application_date)からのエポック秒による経過時間を計算し、顧客ID(customer_id)、売上日、会員申込日とともに10件表示せよ(なお、sales_ymdは数値、application_dateは文字列でデータを保持している点に注意)。なお、時間情報は保有していないため各日付は0時0分0秒を表すものとする。
(
df_receipt
.select('customer_id', 'sales_ymd')
.unique(keep='first')
.join(df_customer, on='customer_id')
.select(
pl.col.customer_id,
pl.col.sales_ymd.cast(str).str.strptime(pl.Date, '%Y%m%d'),
pl.col.application_date.cast(str).str.strptime(pl.Date, '%Y%m%d')
)
.with_columns(
elapsed_years=(pl.col.sales_ymd - pl.col.application_date).dt.total_seconds()
)
.head()
)
| customer_id | sales_ymd | application_date | elapsed_years |
|---|---|---|---|
| str | date | date | i64 |
| "CS030214000008" | 2017-01-17 | 2015-05-25 | 52099200 |
| "CS027515000056" | 2017-09-23 | 2015-02-08 | 82771200 |
| "CS010415000253" | 2019-05-20 | 2015-01-22 | 136425600 |
| "CS040615000016" | 2019-08-09 | 2015-08-26 | 124761600 |
| "CS014415000151" | 2018-06-17 | 2015-07-17 | 92102400 |
P-074#
レシート明細データ(df_receipt)の売上日(sales_ymd)に対し、当該週の月曜日からの経過日数を計算し、売上日、直前の月曜日付とともに10件表示せよ(sales_ymdは数値でデータを保持している点に注意)。
(
df_receipt
.select('customer_id', 'sales_ymd')
.join(df_customer, on='customer_id')
.select(
pl.col.sales_ymd.cast(str).str.strptime(pl.Date, '%Y%m%d'),
)
.with_columns(
pl.col.sales_ymd.dt.truncate('1w').alias('monday')
)
.with_columns(
(pl.col.sales_ymd - pl.col.monday).alias('elapsed_days').dt.total_days()
)
.head()
)
| sales_ymd | monday | elapsed_days |
|---|---|---|
| date | date | i64 |
| 2018-11-03 | 2018-10-29 | 5 |
| 2018-11-18 | 2018-11-12 | 6 |
| 2017-07-12 | 2017-07-10 | 2 |
| 2018-08-21 | 2018-08-20 | 1 |
| 2019-06-05 | 2019-06-03 | 2 |
P-075#
顧客データ(df_customer)からランダムに1%のデータを抽出し、先頭から10件表示せよ。
df_customer.sample(fraction=0.01).head(5)
| customer_id | customer_name | gender_cd | gender | birth_day | age | postal_cd | address | application_store_cd | application_date | status_cd |
|---|---|---|---|---|---|---|---|---|---|---|
| str | str | str | str | str | i64 | str | str | str | i64 | str |
| "CS010415000255" | "星 さやか" | "1" | "女性" | "1975-02-08" | 44 | "222-0011" | "神奈川県横浜市港北区菊名**********" | "S14010" | 20150408 | "D-20101026-D" |
| "CS031312000056" | "多岐川 未來" | "1" | "女性" | "1984-04-27" | 34 | "151-0063" | "東京都渋谷区富ヶ谷**********" | "S13031" | 20150410 | "0-00000000-0" |
| "CS023213000050" | "長野 倫子" | "1" | "女性" | "1995-12-01" | 23 | "212-0005" | "神奈川県川崎市幸区戸手**********" | "S14023" | 20150625 | "0-00000000-0" |
| "CS022313000123" | "中川 薫" | "1" | "女性" | "1984-02-20" | 35 | "249-0001" | "神奈川県逗子市久木**********" | "S14022" | 20160106 | "0-00000000-0" |
| "CS019714000037" | "浜口 季衣" | "1" | "女性" | "1944-06-04" | 74 | "173-0037" | "東京都板橋区小茂根**********" | "S13019" | 20180509 | "0-00000000-0" |
P-076#
顧客データ(df_customer)から性別コード(gender_cd)の割合に基づきランダムに10%のデータを層化抽出し、性別コードごとに件数を集計せよ。
(
df_customer
.filter(
(pl.int_range(pl.len()) < pl.len() * 0.1).shuffle().over('gender_cd') == 1
)
.group_by('gender_cd')
.agg(pl.len())
)
| gender_cd | len |
|---|---|
| str | u32 |
| "0" | 299 |
| "1" | 1792 |
| "9" | 108 |
P-077#
レシート明細データ(df_receipt)の売上金額を顧客単位に合計し、合計した売上金額の外れ値を抽出せよ。なお、外れ値は売上金額合計を対数化したうえで平均と標準偏差を計算し、その平均から3σを超えて離れたものとする(自然対数と常用対数のどちらでも可)。結果は10件表示せよ。
(
df_receipt
.group_by('customer_id')
.agg(
sum_amount=pl.col.amount.sum(),
log_sum_amount=pl.col.amount.sum().log(),
)
.filter(
(pl.col.log_sum_amount - pl.col.log_sum_amount.mean()) / pl.col.log_sum_amount.std() > 3
)
)
| customer_id | sum_amount | log_sum_amount |
|---|---|---|
| str | i64 | f64 |
| "ZZ000000000000" | 12395003 | 16.332804 |
P-078#
レシート明細データ(df_receipt)の売上金額(amount)を顧客単位に合計し、合計した売上金額の外れ値を抽出せよ。ただし、顧客IDが"Z"から始まるのものは非会員を表すため、除外して計算すること。なお、ここでは外れ値を第1四分位と第3四分位の差であるIQRを用いて、「第1四分位数-1.5×IQR」を下回るもの、または「第3四分位数+1.5×IQR」を超えるものとする。結果は10件表示せよ。
col = pl.col.sum_amount
q25 = col.quantile(0.25)
q75 = col.quantile(0.75)
iqr = q75 - q25
expr = (col > q75 + iqr * 1.5) | (col < q25 - iqr * 1.5)
(
df_receipt
.filter(
pl.col.customer_id.str.starts_with('Z').not_()
)
.group_by('customer_id')
.agg(sum_amount=pl.col.amount.sum())
.filter(expr)
.head()
)
| customer_id | sum_amount |
|---|---|
| str | i64 |
| "CS014415000172" | 11329 |
| "CS014415000077" | 14076 |
| "CS017415000187" | 9948 |
| "CS019415000015" | 13958 |
| "CS023414000088" | 8798 |
P-079#
商品データ(df_product)の各項目に対し、欠損数を確認せよ。
df_product.select(
pl.all().null_count()
)
| product_cd | category_major_cd | category_medium_cd | category_small_cd | unit_price | unit_cost |
|---|---|---|---|---|---|
| u32 | u32 | u32 | u32 | u32 | u32 |
| 0 | 0 | 0 | 0 | 7 | 7 |
P-080#
商品データ(df_product)のいずれかの項目に欠損が発生しているレコードを全て削除した新たな商品データを作成せよ。なお、削除前後の件数を表示させ、079で確認した件数だけ減少していることも確認すること。
len(df_product), len(df_product.drop_nulls())
(10030, 10023)