数据科学 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 条。日以补零的 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 中用 bin_quantiles 代替 qcut(默认为左闭区间)
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 |
| "CS017412000064" | 4755 | 0.811291 |
| "CS031512000114" | 202 | -0.862192 |
| "CS003414000181" | 4626 | 0.763876 |
| "CS001415000480" | 6635 | 1.502296 |
| "CS013513000128" | 216 | -0.857046 |
| "CS009514000024" | 1446 | -0.404952 |
| "CS003415000452" | 4237 | 0.620897 |
| "CS040613000056" | 2764 | 0.079487 |
| "CS008615000064" | 346 | -0.809264 |
| "CS027612000052" | 280 | -0.833522 |
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 |
| "CS035513000171" | 2251 | 0.09476 |
| "CS028512000131" | 562 | 0.021376 |
| "CS029515000204" | 1141 | 0.046533 |
| "CS040212000007" | 486 | 0.018074 |
| "CS002415000576" | 2786 | 0.118005 |
| "CS001114000005" | 626 | 0.024157 |
| "CS016415000253" | 1978 | 0.082899 |
| "CS015415000069" | 9852 | 0.425009 |
| "CS023414000072" | 6898 | 0.296663 |
| "CS034515000164" | 4136 | 0.17666 |