データサイエンス100本ノック 41~50

データサイエンス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()
)
shape: (10, 5)
sales_ymdamountlag_sales_ymdlag_amountdiff_amount
i64i64i64i64i64
2017010133723nullnullnull
20170102241652017010133723-9558
201701032750320170102241653338
201701043616520170103275038662
201701053783020170104361651665
20170106323872017010537830-5443
20170107234152017010632387-8972
201701082473720170107234151322
201701092671820170108247371981
20170110201432017010926718-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)
)
shape: (10, 4)
sales_ymdamountsales_ymd_lagamount_lag
i64i64i64i64
2017010133723nullnull
20170102241652017010133723
20170103275032017010133723
20170103275032017010224165
20170104361652017010133723
20170104361652017010224165
20170104361652017010327503
20170105378302017010224165
20170105378302017010327503
20170105378302017010436165

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
shape: (9, 4)
agemalefemaleunknown
i64i64i64i64
1015911498364317
2072940136372444328
3017732269304750441
40193559320791483512
50543206685192342923
6027246998774171418
7013435297642427
80463602629235111
90null6260null

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()
)
shape: (5, 3)
agegender_cdamount
i64stri64
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()
)
shape: (5, 2)
customer_idbirth_day
strstr
"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()
)
shape: (5, 2)
customer_idapplication_date
strdate
"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()
)
shape: (5, 3)
receipt_noreceipt_sub_nosales_ymd
i64i64date
11212018-11-03
113222018-11-18
110212017-07-12
113212019-02-05
110222018-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()
)
shape: (5, 3)
receipt_noreceipt_sub_nosales_epoch
i64i64date
11212018-11-03
113222018-11-18
110212017-07-12
113212019-02-05
110222018-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()
)
shape: (5, 3)
receipt_noreceipt_sub_nosales_epoch
i64i64i32
11212018
113222018
110212017
113212019
110222018

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()
)
shape: (5, 3)
receipt_noreceipt_sub_nosales_epoch
i64i64str
1121"11"
11322"11"
11021"07"
11321"02"
11022"08"