データサイエンス100本ノック 41~50#
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-041#
レシート明細データ(df_receipt)の売上金額(amount)を日付(sales_ymd)ごとに集計し、前回売上があった日からの売上金額増減を計算せよ。そして結果を10件表示せよ。
(
df_receipt
.lazy()
.group_by('sales_ymd')
.agg(
pl.col.amount.sum()
)
.sort(
by='sales_ymd'
)
.with_columns(
pl.all().shift().name.prefix('lag_')
)
.with_columns(
diff_amount = pl.col.amount - pl.col.lag_amount
)
.head(10)
.collect()
)
sales_ymd | amount | lag_sales_ymd | lag_amount | diff_amount |
---|---|---|---|---|
i64 | i64 | i64 | i64 | i64 |
20170101 | 33723 | null | null | null |
20170102 | 24165 | 20170101 | 33723 | -9558 |
20170103 | 27503 | 20170102 | 24165 | 3338 |
20170104 | 36165 | 20170103 | 27503 | 8662 |
20170105 | 37830 | 20170104 | 36165 | 1665 |
20170106 | 32387 | 20170105 | 37830 | -5443 |
20170107 | 23415 | 20170106 | 32387 | -8972 |
20170108 | 24737 | 20170107 | 23415 | 1322 |
20170109 | 26718 | 20170108 | 24737 | 1981 |
20170110 | 20143 | 20170109 | 26718 | -6575 |
P-042#
レシート明細データ(df_receipt)の売上金額(amount)を日付(sales_ymd)ごとに集計し、各日付のデータに対し、前回、前々回、3回前に売上があった日のデータを結合せよ。そして結果を10件表示せよ。
df_tmp = (
df_receipt
.group_by('sales_ymd')
.agg(pl.col.amount.sum())
.sort(by='sales_ymd')
.with_columns(
index=pl.int_range(0, pl.len(), dtype=pl.Int32)
)
)
df_rolling = (
df_tmp
.rolling('index', period='3i', offset='-4i')
.agg(
pl.col.sales_ymd,
pl.col.amount
)
)
(
df_tmp
.join(
df_rolling, on='index', suffix='_lag'
)
.explode(pl.col('^*._lag$'))
.drop('index')
.head(10)
)
sales_ymd | amount | sales_ymd_lag | amount_lag |
---|---|---|---|
i64 | i64 | i64 | i64 |
20170101 | 33723 | null | null |
20170102 | 24165 | 20170101 | 33723 |
20170103 | 27503 | 20170101 | 33723 |
20170103 | 27503 | 20170102 | 24165 |
20170104 | 36165 | 20170101 | 33723 |
20170104 | 36165 | 20170102 | 24165 |
20170104 | 36165 | 20170103 | 27503 |
20170105 | 37830 | 20170102 | 24165 |
20170105 | 37830 | 20170103 | 27503 |
20170105 | 37830 | 20170104 | 36165 |
P-043#
レシート明細データ(df_receipt)と顧客データ(df_customer)を結合し、性別コード(gender_cd)と年代(ageから計算)ごとに売上金額(amount)を合計した売上サマリデータを作成せよ。性別コードは0が男性、1が女性、9が不明を表すものとする。
ただし、項目構成は年代、女性の売上金額、男性の売上金額、性別不明の売上金額の4項目とすること(縦に年代、横に性別のクロス集計)。また、年代は10歳ごとの階級とすること。
df_sales_summary = (
df_receipt
.join(
df_customer, on='customer_id', how='inner'
)
.group_by(
(pl.col.age // 10) * 10, 'gender_cd'
)
.agg(
pl.col.amount.sum()
)
.sort(
by=['age', 'gender_cd']
)
.with_columns(
pl.col.gender_cd.replace({'0':'male', '1':'female', '9':'unknown'})
)
.pivot(
index='age',
on='gender_cd',
values='amount'
)
)
df_sales_summary
age | male | female | unknown |
---|---|---|---|
i64 | i64 | i64 | i64 |
10 | 1591 | 149836 | 4317 |
20 | 72940 | 1363724 | 44328 |
30 | 177322 | 693047 | 50441 |
40 | 19355 | 9320791 | 483512 |
50 | 54320 | 6685192 | 342923 |
60 | 272469 | 987741 | 71418 |
70 | 13435 | 29764 | 2427 |
80 | 46360 | 262923 | 5111 |
90 | null | 6260 | null |
P-044#
043で作成した売上サマリデータ(df_sales_summary)は性別の売上を横持ちさせたものであった。このデータから性別を縦持ちさせ、年代、性別コード、売上金額の3項目に変換せよ。ただし、性別コードは男性を”00”、女性を”01”、不明を”99”とする。
(
df_sales_summary
.unpivot(
index='age', variable_name='gender_cd', value_name='amount'
)
.with_columns(
pl.col.gender_cd.replace({'male':'00', 'female':'01', 'unknown':'99'})
)
.head()
)
age | gender_cd | amount |
---|---|---|
i64 | str | i64 |
10 | "00" | 1591 |
20 | "00" | 72940 |
30 | "00" | 177322 |
40 | "00" | 19355 |
50 | "00" | 54320 |
P-045#
顧客データ(df_customer)の生年月日(birth_day)は日付型でデータを保有している。これをYYYYMMDD形式の文字列に変換し、顧客ID(customer_id)とともに10件表示せよ。
(
df_customer
.select(
pl.col.customer_id,
pl.col.birth_day.str.replace_all('-', '')
)
.head()
)
customer_id | birth_day |
---|---|
str | str |
"CS021313000114" | "19810429" |
"CS037613000071" | "19520401" |
"CS031415000172" | "19761004" |
"CS028811000001" | "19330327" |
"CS001215000145" | "19950329" |
P-046#
顧客データ(df_customer)の申し込み日(application_date)はYYYYMMDD形式の文字列型でデータを保有している。これを日付型に変換し、顧客ID(customer_id)とともに10件表示せよ。
(
df_customer
.select(
pl.col.customer_id,
pl.col.application_date.cast(str).str.strptime(pl.Date, '%Y%m%d')
)
.head()
)
customer_id | application_date |
---|---|
str | date |
"CS021313000114" | 2015-09-05 |
"CS037613000071" | 2015-04-14 |
"CS031415000172" | 2015-05-29 |
"CS028811000001" | 2016-01-15 |
"CS001215000145" | 2017-06-05 |
P-047#
レシート明細データ(df_receipt)の売上日(sales_ymd)はYYYYMMDD形式の数値型でデータを保有している。これを日付型に変換し、レシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに10件表示せよ。
# cast(str)以外の方法
(
df_receipt
.select(
pl.col('receipt_no', 'receipt_sub_no'),
pl.date(
pl.col.sales_ymd // 10000,
pl.col.sales_ymd % 10000 // 100,
pl.col.sales_ymd % 100
)
.alias('sales_ymd')
)
.head()
)
receipt_no | receipt_sub_no | sales_ymd |
---|---|---|
i64 | i64 | date |
112 | 1 | 2018-11-03 |
1132 | 2 | 2018-11-18 |
1102 | 1 | 2017-07-12 |
1132 | 1 | 2019-02-05 |
1102 | 2 | 2018-08-21 |
P-048#
レシート明細データ(df_receipt)の売上エポック秒(sales_epoch)は数値型のUNIX秒でデータを保有している。これを日付型に変換し、レシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに10件表示せよ。
(
df_receipt
.select(
pl.col('receipt_no', 'receipt_sub_no'),
pl.from_epoch(pl.col.sales_epoch).dt.date()
)
.head()
)
receipt_no | receipt_sub_no | sales_epoch |
---|---|---|
i64 | i64 | date |
112 | 1 | 2018-11-03 |
1132 | 2 | 2018-11-18 |
1102 | 1 | 2017-07-12 |
1132 | 1 | 2019-02-05 |
1102 | 2 | 2018-08-21 |
P-049#
レシート明細データ(df_receipt)の売上エポック秒(sales_epoch)を日付型に変換し、「年」だけ取り出してレシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに10件表示せよ。
(
df_receipt
.select(
pl.col('receipt_no', 'receipt_sub_no'),
pl.from_epoch(pl.col.sales_epoch).dt.year()
)
.head()
)
receipt_no | receipt_sub_no | sales_epoch |
---|---|---|
i64 | i64 | i32 |
112 | 1 | 2018 |
1132 | 2 | 2018 |
1102 | 1 | 2017 |
1132 | 1 | 2019 |
1102 | 2 | 2018 |
P-050#
レシート明細データ(df_receipt)の売上エポック秒(sales_epoch)を日付型に変換し、「月」だけ取り出してレシート番号(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.month().cast(str).str.pad_start(2, '0')
)
.head()
)
receipt_no | receipt_sub_no | sales_epoch |
---|---|---|
i64 | i64 | str |
112 | 1 | "11" |
1132 | 2 | "11" |
1102 | 1 | "07" |
1132 | 1 | "02" |
1102 | 2 | "08" |