返回首页

Roadmap
更新于 2026年10月30日 全文 450 字未阅读

第 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 个步骤:

  1. 打印 dirty 每一列的缺失值数量;

  2. 打印整张表总共缺了多少个值;

  3. 把「金额」列缺失的值填 0,存到 t1;

  4. 把「客户评分」列缺失的值填该列的中位数,存到 t2;

  5. 用一个字典,让「金额」填 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 个步骤:

  1. 打印 dirty 的行数;

  2. 用 drop_duplicates() 删掉完全重复的行,打印新行数;

  3. 打印 dirty.duplicated(),看清哪些行被判成重复;

  4. 按「城市」+「商品」两列判断重复,删掉后打印行数;

  5. 同样按「城市」+「商品」,但用 keep="last",打印行数;再用 keep=False,打印行数。

思考题:** 第 4、5 题的行数一样吗?keep=False 为什么更少?

# 1. 原始行数
print(len(dirty))     # 9
阅读 --