复盘T^T
总体做的都不咋样时间不够用,先做的后面SQL最后才发现一空一分,而Excel+Python一空5分,时间安排不合理且做题过慢。
Python题又太难了T-T
体量大且难没有时间磨蹭犹豫了。
Python
1.
业务背景:山东康民医药连锁有限公司需要对 2024 年 1-6 月抽取的 386 名会员订单明细进行分析,以优化下半年资源配置。
数据处理口径(所有小题的绝对前提):
去重:删除完全重复的记录(订单平台重复推送)。
剔除异常金额:剔除"实付金额(元)"缺失(NaN)或 ≤ 0 的记录(缺失为支付失败,0为测试单,负数为退款单)。
剔除异常折扣:剔除"折扣率" > 0.6 的记录(超出 6 折权限的录入错误)。
提示要求:所有计算结果均保留小数点后两位,采取四舍五入。
思路分析与代码实现:
以下代码假设已经成功读取了 Excel 数据,并存储在 df 中。
🟢 单选题 1:清洗后的有效订单笔数与平均客单价
解题思路:
严格按照数据处理口径,依次执行去重、剔除异常金额、剔除异常折扣率。
计算清洗后 DataFrame 的总行数(有效订单笔数)。
计算"实付金额(元)"列的平均值(平均客单价),并按要求保留两位小数。
(1)
python
# 1. 读取数据 (请将文件路径替换为你本地实际的路径)
df = pd.read_excel('https://oss.xinchanjiao.com/upload/default/20261010-2b938c45-2e24-4779-9bbe-b74a63ae7992.xlsx')
df
# ① 删除完全重复的记录
df.drop_duplicates(inplace=True)
# ② 剔除"实付金额(元)"缺失或 <= 0 的记录
# 假设列名为 '实付金额(元)',如果包含空格需去除或使用真实列名
df = df[df['实付金额(元)'].notna()]
df = df[df['实付金额(元)'] > 0]
# ③ 剔除"折扣率" > 0.6 的记录 (注意:Excel里的6折通常为0.6)
df = df[df['折扣率'] <= 0.6]
# 计算最终结果
有效订单笔数 = len(df)
平均客单价 = df['实付金额(元)'].mean()
# 2. 打印结果,计算结果保留小数点后两位,采取四舍五入
print(f"清洗后的有效订单笔数:{有效订单笔数}")
print(f"平均客单价(元):{round(平均客单价, 2)}")
同时注意:客单价"的定义就是"平均每个订单的实付金额" ,而不是商品标签上的"单价"。
(2)
#按"城市"统计实付金额合计并降序排列,问:销售额最高的城市、其销售额及占全省销售额的比重分别是多少?
python
df1=df.groupby('城市').sum().sort_values('实付金额(元)')
df1['占比']=df1['实付金额(元)']/df1['实付金额(元)'].sum()
(3)
- 获取日期
pd.to_datetime() 是 Pandas 库的顶级函数,用于将各种格式的时间数据转换为 datetime 类型。
python
import pandas as pd
# 示例:将不同格式的日期字符串批量转换
dates = ['2023-01-01', '01/02/2023', '2023/03/15 14:30:00']
result = pd.to_datetime(dates, dayfirst=False, errors='coerce')
print(result)
DatetimeIndex('2023-01-01', '2023-02-01', '2023-03-15 14:30:00',
dtype='datetime64ns', freq=None)
dt.date()是Pandas中Series对象的一个属性方法,它用于将datetime64类型的Series中的每个元素转换为Python的datetime.date对象。datetime.date对象只包含日期部分(年、月、日),不包含时间部分(时、分、秒)。这在进行日期相关的统计汇总时非常有用,因为它可以避免时间部分的干扰。
Series类型的数据,经过 to_datetime 之后就可以用 pandas.Series.dt.days 和 pandas.Series.pd.month。
除了 days 和 month 外,还包括 date、dayofweek、dayofyear、days_in_month、freq、hour、microsecond、minute、month、quarter、second、time、tz、week、weekday、year等。这些是提取 Series 时间数据的常用方法。
python
import pandas as pd
a = pd.Series(['2017-1-2','2017-9-1'])
print(a)
0 2017-1-2
1 2017-9-1
dtype: object
python
a = pd.to_datetime(a)
print(a)
0 2017-01-02
1 2017-09-01
dtype: datetime64ns
python
b = pd.Series(['2019-8-19', '2019-6-29'])
b = pd.to_datetime(b)
print(b)
0 2019-08-19
1 2019-06-29
dtype: datetime64ns
python
c = (b-a).dt.days
print(c)
0 959
1 666
dtype: int64
python
df['月份'] = pd.to_datetime(df['订单日期']).dt.month# 新增一列月份
df['月份'].isin([5,6]) #判断每行信息里是否有要求中的月份

2.
题目背景与要求
题目描述:
公司希望利用 RFM 模型 对会员进行分层,以便将预算投向"贡献高且当前仍活跃"的会员。
基准日:2024-06-30
指标定义:
R (Recency):最近一次消费距基准日的天数(越小越活跃)。
F (Frequency):累计订单数。
M (Monetary):累计实付金额。
评分规则:统一按五分位数将 R、F、M 转换为 1-5 分。
R 越小得分越高(即天数少得高分)。
F、M 越大得分越高(即数值大得高分)。
目标客户:"重要价值客户"定义为 三项得分均 ≥ 4 分 。
任务:
补全代码中的空缺部分,用于计算该类会员人数及其消费金额占比。
解题思路与代码补全:
我们需要填补代码中的四个关键空缺,逻辑如下:
分组键 (groupby):RFM 模型是基于"用户"维度的分析,因此必须按 会员编号 进行分组。
F 指标聚合 (agg):F 代表频率(Frequency),即订单数量,因此需要对订单编号进行计数,使用 count。
VIP 筛选条件:题目要求"三项得分均 ≥ 4",代码中已经写了 R 和 F 的判断,缺失的是 M 的判断,即 rfm'M分'。
金额统计 (isin):最后一行计算 VIP 的总金额时,需要筛选出属于 VIP 列表的会员编号,使用 .index 获取 VIP 表的索引(即会员编号)。
python
import pandas as pd
# 假设 df 为读取后的 DataFrame
# df['订单日期'] = pd.to_datetime(df['订单日期'], format='%Y/%m/%d')
base = pd.Timestamp('2024-06-30')
# 1. 数据聚合
# 【填空1】:按会员编号分组
# 【填空2】:F指标统计订单数量,使用 count
rfm = df.groupby('会员编号').agg(
R=('订单日期', lambda x: (base - x.max()).days),
F=('订单编号', 'count'),
M=('实付金额(元)', 'sum')
)
# 2. 计算五分位阈值
q = (0.2, 0.4, 0.6, 0.8)
r_q = [rfm['R'].quantile(i) for i in q]
f_q = [rfm['F'].quantile(i) for i in q]
m_q = [rfm['M'].quantile(i) for i in q]
# 3. 打分逻辑
# R值越小越好:小于20%分位数给5分
rfm['R分'] = rfm['R'].apply(lambda v: 5 if v <= r_q[0] else 4 if v <= r_q[1]
else 3 if v <= r_q[2] else 2 if v <= r_q[3] else 1)
# F值越大越好:大于80%分位数给5分
rfm['F分'] = rfm['F'].apply(lambda v: 5 if v >= f_q[3] else 4 if v >= f_q[2]
else 3 if v >= f_q[1] else 2 if v >= f_q[0] else 1)
# M值越大越好:大于80%分位数给5分
rfm['M分'] = rfm['M'].apply(lambda v: 5 if v >= m_q[3] else 4 if v >= m_q[2]
else 3 if v >= m_q[1] else 2 if v >= m_q[0] else 1)
# 4. 筛选重要价值客户
# 【填空3】:筛选条件需包含 M分 >= 4
vip = rfm[(rfm['R分'] >= 4) & (rfm['F分'] >= 4) & (rfm['M分'] >= 4)]
# 5. 计算结果
# 【填空4】:获取 vip 的索引(会员编号)用于匹配原表
amt = df[df['会员编号'].isin(vip.index)]['实付金额(元)'].sum()
# 输出人数和金额占比
print(len(vip), round(amt / df['实付金额(元)'].sum() * 100, 2))
SQL
题1:

create tabel
foreign key (book_id) references BOOKS (book_id)
insert into reservation values(***)
为books表新增一列,类型为varchar(20),默认值为'A区'
ALTER TABLE books ADD location VARCHAR(20) DEFAULT'A区'
查询读者姓名(同一读者只出现一次),按读者姓名升序排列
SELECT DISTINCT rd.reader_name
按图书类别分组统计图书数量与平均价格(平均价格保留1为小数),显示类别,图书数量、平均价格,按图书数量降序排列。
sql
SELECT
category,
COUNT(book_id) AS book_count,
ROUND(AVG(price), 1) AS avg_price
FROM books
GROUP BY category
ORDER BY book_count DESC;
创建视图只显示读者编号、读者姓名、借阅次数,要求使用左连接保证从未借阅的读者也能参与统计,且只显示借阅次数>=1的读者
sql
CREATE VIEW v_active_reader AS
SELECT
rd.reader_id,
rd.reader_name,
COUNT(bo.borrow_id) AS borrow_count
FROM
readers rd
LEFT JOIN
borrow bo ON rd.reader_id = bo.reader_id
GROUP BY
rd.reader_id, rd.reader_name
HAVING
COUNT(bo.borrow_id) >= 1;
基于视图,查询借阅次数高与全体读者平均借阅次数的读者姓名与借阅次数。
sql
SELECT reader_name, borrow_count
FROM v_active_reader
WHERE borrow_count > (SELECT AVG(borrow_count) FROM v_active_reader);