データサイエンス100本ノック 51~60

データサイエンス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()
)
shape: (5, 3)
receipt_noreceipt_sub_nosales_epoch
i64i64str
1121"03"
11322"18"
11021"12"
11321"05"
11022"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()
)
shape: (5, 3)
customer_idsum_amountsales_flg
stri64i32
"CS006214000001"73641
"CS008415000097"18950
"CS028414000014"62221
"CS025415000050"57361
"CS003515000195"54121

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())
)
shape: (2, 2)
postal_flgcustomer_cnt
u8u32
03906
14400

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()
)
shape: (5, 3)
customer_idaddressprefecture_cd
strstrstr
"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(
    pct_group=pl.col.sum_amount
        .qcut([0.25, 0.5, 0.75], labels=['1', '2', '3', '4'])
)
.head(10)
)
shape: (10, 3)
customer_idsum_amountpct_group
stri64cat
"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)
)
shape: (10, 3)
customer_idbirth_dayage
strstri64
"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)
)
shape: (10, 3)
customer_idbirth_daygender_era
strstrstr
"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()
)
shape: (5, 4)
customer_idgender_cd_0gender_cd_1gender_cd_9
stru8u8u8
"CS021313000114"010
"CS037613000071"001
"CS031415000172"010
"CS028811000001"010
"CS001215000145"010

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)
)
shape: (10, 3)
customer_idsum_amountstd_amount
stri64f64
"CS037411000055"226-0.85337
"CS005415000376"229-0.852268
"CS022613000082"1576-0.35717
"CS041411000001"96942.62665
"CS021515000208"90762.3995
"CS040311000030"323-0.817717
"CS018512000134"1053-0.549401
"CS010513000101"523-0.744206
"CS023514000110"60571.289849
"CS026513000002"692-0.682089

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)
)
shape: (10, 3)
customer_idsum_amountstd_amount
stri64f64
"CS024515000230"30410.129084
"CS034414000039"122700.530066
"CS026512000011"4460.016336
"CS019415000280"61090.262383
"CS026412000156"12900.053007
"CS025513000185"12380.050747
"CS010115000005"36560.155805
"CS005515000343"12480.051182
"CS021613000009"11640.047532
"CS006314000011"12080.049444