第 3.2 节 编程练习#
预计学习时长: 45 分钟
练习方式: 新建一个 Jupyter Notebook,抄好准备代码,然后每题独立完成。这 5 题建议连着做,因为它们合起来就是一次完整的清洗流程。
本课程使用的 Pandas 版本是
'3.1.0'
先准备造一张脏表#
import pandas as pd
import numpy as np
data = {
"订单号": [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008],
"下单日期": ["2024-01-05", "2024-01-08", "2024-01-12", "2024-02-03",
"2024-02-15", "2024-03-02", "2024-03-20", "2024-04-08"],
"城市": ["北京", "上海", "北京", "广州", "上海", "北京", "深圳", "广州"],
"商品": ["手机", "电脑", "耳机", "手机", "键盘", "显示器", "耳机", "手机"],
"销量": [2, 1, 3, 2, 5, 1, 4, 2],
"单价": [3999.0, 7999.0, 599.0, 3999.0, 299.0, 1299.0, 599.0, 3999.0],
"金额": [7998.0, 7999.0, 1797.0, 7998.0, 1495.0, 1299.0, 2396.0, 7998.0],
"客户评分": [4.5, 4.0, 4.8, 3.9, 4.2, 4.6, 4.1, 4.9],
}
df = pd.DataFrame(data)
# 造一张有问题的表
dirty = df.copy()
dirty.loc[1, "金额"] = np.nan # 金额缺失
dirty.loc[5, "客户评分"] = np.nan # 评分缺失
dirty.loc[2, "商品"] = "未知" # 异常取值
dirty = pd.concat([dirty, dirty.iloc[[0]]], ignore_index=True) # 重复了一行练习 1:检测缺失值并使用指定值填充#
题目: 完成下面 5 个步骤:
打印
dirty每一列的缺失值数量;打印整张表总共缺了多少个值;
把「金额」列缺失的值填 0,存到
t1;把「客户评分」列缺失的值填该列的中位数,存到
t2;用一个字典,让「金额」填 0、「客户评分」填 5.0,一次性填完,存到
t3。
思考题: 第 4 题如果改用平均值,结果会一样吗?算一算哪个更合理。
# 1. 每列缺失数量
print(dirty.isna().sum())订单号 0
下单日期 0
城市 0
商品 0
销量 0
单价 0
金额 1
客户评分 1
dtype: int64# 2. 总共缺了几个
print(dirty.isna().sum().sum()) # 2# 3. 填固定值
t1 = dirty.copy()
t1["金额"] = t1["金额"].fillna(0)
print(t1["金额"].tolist())[7998.0, 0.0, 1797.0, 7998.0, 1495.0, 1299.0, 2396.0, 7998.0, 7998.0]# 4. 填中位数(先算出来,再填)
t2 = dirty.copy()
mid = t2["客户评分"].median()
print(mid) # 4.35
t2["客户评分"] = t2["客户评分"].fillna(mid)# 5. 用字典一次填多列
t3 = dirty.fillna({"金额": 0, "客户评分": 5.0})
print(t3[["金额", "客户评分"]].isna().sum().sum()) # 0要点: 第 4 题里,均值是 4.35,中位数也是 4.35——因为 8 个评分里只有 1 个缺失,剩下的 7 个是 4.5, 4.0, 4.8, 3.9, 4.2, 4.6, 4.1,排序后中间那个正好是 4.35。
真实数据里两者通常不一样:如果评分里混着一个 1.0 的差评,均值会被拉低,中位数不会。
练习 2:删除重复行并保留首次出现的记录#
题目: 完成下面 5 个步骤:
打印
dirty的行数;用
drop_duplicates()删掉完全重复的行,打印新行数;打印
dirty.duplicated(),看清哪些行被判成重复;按「城市」+「商品」两列判断重复,删掉后打印行数;
同样按「城市」+「商品」,但用
keep="last",打印行数;再用keep=False,打印行数。
思考题:** 第 4、5 题的行数一样吗?keep=False 为什么更少?
# 1. 原始行数
print(len(dirty)) # 9