4-2 DataFrame基本与数据清洗

🎯 教学目标与重难点…

【三维目标】

  • 📚 知识目标

  • 掌握 DataFrame 的精准索引定位(loc 显式标签索引 vs iloc 隐式位置索引);

  • 掌握条件过滤(布尔索引)、数据排序(sort_values)与表合并(concat/merge);

  • 掌握缺失值诊断与处理(isna()fillna()dropna())及重复数据剔除(drop_duplicates());

  • 理解连续特征离散化(pd.cut())与哑变量转换(pd.get_dummies())在机器学习中的作用。

  • ⚙️ 能力目标

  • 能够熟练使用 loc/iloc 进行复杂条件的表格数据筛选与切片;

  • 能够独立对脏数据集完成“去重 ➔ 补缺 ➔ 特征离散化/哑变量处理”的预处理全流程。

  • 💡 素养目标

  • 建立“脏数据不能直接入模型”的数据质量与规范清洗意识;

  • 体会逻辑条件筛选与特征工程的巧妙联动,提升工程解决问题的综合素养。

【重点与难点】

  • 🟢 教学重点lociloc 的区别;布尔条件筛选(如 df[df['售价'] > 300]);缺失值填补 fillna();哑变量 pd.get_dummies()
  • 🟡 教学难点:多条件的布尔索引逻辑组合(使用 &| 并加括号);merge 连接方式(inner/outer/left)的物理意义;哑变量转换后的特征维度变化。

📌 一、 课程导入(10 分钟)

  1. 真实场景痛点:拿到的数据能直接喂给机器学习模型吗?
  • 上节课我们学会了把 CSV 读进 DataFrame,但现实中的原始数据充满了“垃圾”:有缺失的空项、重复录入的行、杂乱的文本分类(如“男/女”、“北京/上海”)。
  • 计算机模型只认识数字,且极度害怕 NaN(空值)。
  1. 数据预处理的两大核心任务
  • 任务一:数据切片与组装(怎么把想要的数据筛选出来?怎么把多张表拼在一起?)
  • 任务二:数据清洗与特征打磨(去重、补缺、数值化,打造适合模型的干净矩阵)。
  • 👨‍🏫 教师活动:展示一张带有 NaN 和文本分类的真实二手房数据集,提出问题:“如果不处理直接让模型计算房价,会发生什么?”
  • 🧑‍🎓 学生活动:思考并回答问题,意识到必须先对数据进行清洗和转换,才能进行后续的数学建模。

从真实数据集的“脏乱差”痛点切入,明确本节课的核心任务,帮助学生建立从“表格操作”到“模型输入预处理”的工程桥梁。


📖 二、 解决问题过程(一):DataFrame 基本操作——检索、排序与合并(30 分钟)

1. 精准定位:loc(看名字)vs iloc(看数字)

  • loc[行标签, 列标签]:基于显式名称定位。
  • iloc[行位置, 列位置]:基于隐式数字序号定位(左闭右开,与 NumPy 一致)。

2. 布尔筛选(条件过滤)与排序

  • 筛选语法:df[条件表达]

  • 单条件:df[df['售价'] > 300]

  • 多条件(必须用 &|,且每个条件必须加小括号):df[(df['售价'] > 300) & (df['面积'] > 100)]

  • 排序:df.sort_values(by='列名', ascending=False)ascending=False 表示降序)。

3. 表合并:concatmerge

  • pd.concat([df1, df2], axis=0):简单拼接(axis=0 纵向按行堆叠,axis=1 横向按列拼接)。
  • pd.merge(df1, df2, on='主键', how='inner'):按共同字段精准关联(类似 SQL Join)。
 1import pandas as pd
 2
 3# 模拟二手房数据
 4df = pd.DataFrame({
 5    '小区': ['A区', 'B区', 'C区', 'D区'],
 6    '面积': [85, 120, 60, 150],
 7    '售价': [220, 350, 150, 500]
 8})
 9
10# 1. loc 与 iloc 区分
11print("loc 提取 A区 的售价:", df.loc[0, '售价'])
12print("iloc 提取第 0 行第 2 列:", df.iloc[0, 2])
13
14# 2. 条件筛选:面积 > 80 且 售价 < 400
15sub_df = df[(df['面积'] > 80) & (df['售价'] < 400)]
16print("\n筛选后的数据:\n", sub_df)
17
18# 3. 按售价降序排序
19sorted_df = df.sort_values(by='售价', ascending=False)
20print("\n按售价降序:\n", sorted_df.head(2))
  • 👨‍🏫 教师活动:重点演示布尔筛选时“漏写括号”引发的经典语法错误,帮助学生规避;用图解演示 mergeinnerleft 关联机制。
  • 🧑‍🎓 学生活动:在 Jupyter Notebook 中跟练代码,尝试编写多条件筛选语句,提取符合特定条件的行。

掌握数据检索与合并是数据预处理的基本功,通过对比 loc/iloc 以及强调布尔括号规则,提升学生的代码准确度。


💻 三、 解决问题过程(二):数据清洗“四大件”与特征转换(30 分钟)

1. 缺失值处理(NaN 清洗)

  • 检查缺失值:df.isna().sum()(统计每列空值数量)。
  • 删除空值行:df.dropna(axis=0)
  • 填补空值(更常用):df['列名'].fillna(值, inplace=True)(如用均值/中位数填补)。

2. 重复数据处理

  • 检查重复行:df.duplicated()
  • 删除重复行:df.drop_duplicates(inplace=True)

3. 连续特征离散化(分箱 pd.cut

将连续数字(如年龄、房价)切分成区间段(如:青年/中年/老年)。

  • 语法:pd.cut(df['面积'], bins=[0, 70, 110, 200], labels=['小户型', '中户型', '大户型'])

4. 哑变量处理(One-Hot 独热编码 pd.get_dummies

机器学习核心预处理:将文本分类变量(如“朝向: 东/南/西”)转换为计算机可识别的 0/1 矩阵。

 1import pandas as pd
 2import numpy as np
 3
 4# 模拟带脏数据的原始表格
 5data = pd.DataFrame({
 6    '面积': [85, 120, np.nan, 120, 60],
 7    '朝向': ['东', '南', '西', '南', '东'],
 8    '售价': [220, 350, 180, 350, 150]
 9})
10
11# 1. 剔除重复行
12data.drop_duplicates(inplace=True)
13
14# 2. 填补缺失值 (用均值填补面积)
15mean_area = data['面积'].mean()
16data['面积'].fillna(mean_area, inplace=True)
17
18# 3. 离散化:新增户型分类
19data['户型类别'] = pd.cut(data['面积'], bins=[0, 70, 100, 200], labels=['小户型', '中户型', '大户型'])
20
21# 4. 哑变量处理 (对“朝向”转换为 0/1 矩阵)
22dummies = pd.get_dummies(data['朝向'], prefix='朝向', dtype=int)
23clean_df = pd.concat([data, dummies], axis=1)
24
25print("--- 完全清洗与特征工程后的最终 DataFrame ---")
26print(clean_df)
  • 👨‍🏫 教师活动:画图演示 One-Hot 独热编码是如何把一列文本转换为多列 0/1 矩阵的;带领学生一步步完成“去重 ➔ 补缺 ➔ 分箱 ➔ 哑变量”组合拳。
  • 🧑‍🎓 学生活动:观察转换后 clean_df 的列数变化,理解为什么哑变量处理会导致特征列数增多,并在 Jupyter 中跟练。

打通从“脏表格”到“机器学习可用数值矩阵”的最后一步;将离散化与哑变量这两个看似抽象的概念,用极简的代码和真实表格演示呈现。


✍️ 四、 解决问题过程(三):充分课堂练习与巩固(20 分钟)

📝 任务一:复杂条件筛选与数据排序…

背景与题目: 教师发放了一个学生成绩表格 student_records.csv。请编写代码完成以下筛选与排序操作:

  • 使用 loc 或布尔筛选,找出数学成绩 > 80 且 语文成绩 >= 85 的所有学生。
  • 将筛选出来的学生数据,按照总分从高到低(降序)进行排序。
  • 使用 iloc 提取排序后前 3 名学生的姓名与总分(前 2 列)。
🔍 查看参考代码与解析…
 1import pandas as pd
 2
 3df = pd.read_csv('student_records.csv', encoding='gbk')
 4
 5# 1. 条件筛选 (注意小括号和 &)
 6sub_df = df[(df['数学'] > 80) & (df['语文'] >= 85)]
 7
 8# 2. 排序
 9sorted_df = sub_df.sort_values(by='总分', ascending=False)
10
11# 3. iloc 提取前 3 行的前 2 列
12top3_result = sorted_df.iloc[:3, :2]
13print("前 3 名优秀学生:\n", top3_result)

📝 任务二:二手房脏数据集预处理全流程实操…

背景与题目: 拿到的二手房原始数据集 raw_houses.csv 包含以下列:['房源ID', '城市', '面积', '售价']。请编写代码完成全套清洗流程:

  • 检查并删除重复的房源记录。
  • 检查 售价 列是否存在缺失值,若存在,用该列的中位数(.median())进行填补。
  • 城市 列(包含“北京”、“上海”)进行哑变量(One-Hot)转换,生成 0/1 特征列。
  • 使用 pd.concat 将哑变量特征拼接回原 DataFrame,并删除原始文本列 城市
🔍 查看参考代码与解析…
 1import pandas as pd
 2
 3df_raw = pd.read_csv('raw_houses.csv', encoding='gbk')
 4
 5# 1. 去重
 6df_raw.drop_duplicates(inplace=True)
 7
 8# 2. 填补售价缺失值
 9median_price = df_raw['售价'].median()
10df_raw['售价'].fillna(median_price, inplace=True)
11
12# 3. 哑变量处理
13city_dummies = pd.get_dummies(df_raw['城市'], prefix='城市', dtype=int)
14
15# 4. 拼接并删除原始文本列
16df_clean = pd.concat([df_raw, city_dummies], axis=1)
17df_clean.drop(columns=['城市'], inplace=True)
18
19print("预处理完毕的数据集前 5 行:\n", df_clean.head())

📝 五、 课堂小结(5 分钟)

flowchart LR
    root["📊 4-2 DataFrame 操作与清洗预处理"]

    subgraph C1["🔍 1. 检索与拼接"]
        direction TB
        A1["loc (看名字) / iloc (看数字)"]
        A2["布尔筛选: df[(条件1) & (条件2)]"]
        A3["合并: concat / merge"]
    end

    subgraph C2["🧹 2. 数据清洗"]
        direction TB
        B1["去重: drop_duplicates()"]
        B2["补缺: dropna() / fillna()"]
        B3["诊断: isna().sum()"]
    end

    subgraph C3["⚙️ 3. 特征转换"]
        direction TB
        C1_node["分箱离散化: pd.cut()"]
        C2_node["独热编码: pd.get_dummies()"]
        C3_node["成果: 转化纯数值矩阵"]
    end

    root --> C1
    root --> C2
    root --> C3

    %% 自定义主题色彩美化
    style root fill:#4b6cb7,stroke:#253b6e,color:#fff,stroke-width:2px,rx:8px,ry:8px
    style C1 fill:#e3f2fd,stroke:#2196f3,stroke-width:1px
    style C2 fill:#fff3e0,stroke:#ff9800,stroke-width:1px
    style C3 fill:#e8f5e9,stroke:#4caf50,stroke-width:1px

✏️ 随堂检测与互动练习

点击展开:随堂测试题(带解析)

一、 单选题

  1. 关于 lociloc 的区别,下列说法正确的是?
  • A. loc 使用数字索引,iloc 使用标签名称
  • B. lociloc 没有任何区别
  • C. loc 基于标签名称定位,iloc 基于整数位置序号定位
  • D. iloc 切片时包含右边界
【答案】

【解析】Cloc 是标签索引(Label-based),iloc 是位置序号索引(Integer-based)。

  1. 在对 DataFrame 进行多条件布尔筛选时(如条件 A 和条件 B 同时满足),逻辑运算符和条件表达格式正确的是?
  • A. df[条件A and 条件B]
  • B. df[(条件A) & (条件B)]
  • C. df[条件A && 条件B]
  • D. df[(条件A) or (条件B)]
【答案】

【解析】B。Pandas 中多条件筛选必须使用 bitwise 运算符 &(与)、|(或),且每个独立条件必须用小括号括起来。

  1. 为什么在将数据集送入机器学习模型之前,通常要对文本分类特征(如“红/绿/蓝”)执行 pd.get_dummies()
  • A. 为了减少数据的行数
  • B. 为了将文本分类转换为模型可以进行数学计算的 0/1 独热数值矩阵
  • C. 为了自动填补缺失值
  • D. 为了删除重复数据
【答案】

【解析】B。绝大多数机器学习算法底层是线性代数矩阵运算,无法直接处理字符串文本,哑变量转换能将其标准化为 0/1 独热向量。

二、 简答与思考题

题目:请简述在填补缺失值(fillna)时,直接用固定的数值填补与用该列的 mean()median() 填补各有何优缺点?

【答案】
  1. 用固定值(如 0):简单粗暴,但可能会强行改变原始数据的整体分布与统计特性(如拉低平均值)。
  2. 用均值/中位数(mean/median:最大程度保留了原数据的集中趋势与统计分布,是连续型数值列填补的常用工程手段(若存在极端异常值,用中位数比均值更稳健)。

📮 六、 课后作业与拓展

📮 课后作业…
  1. 基础巩固(检索与排序)
  • 读取上节课导出的 exported_data.csv
  • 使用 loc 筛选出某个数值列大于中位数的行。
  • 对筛选出的结果按照该数值列进行降序排序,并导出前 10 行。
  1. 完整预处理链条实操
  • 找一个包含文本列(如“性别”、“城市”)和缺失值的 CSV 数据集。
  • 编写一段完整的清洗代码:
  • ① 打印缺失值分布;
  • ② 用均值填补数值列的缺失值;
  • ③ 使用 pd.get_dummies 对文本列进行哑变量转换;
  • ④ 使用 NumPy 切片或 Pandas 选择,分离出特征矩阵 X 与目标列 y
  1. 预习任务
  • 预习下一个章节(4.5 DataFrame 进阶),思考:如果在数据清洗完毕后,我想统计“每个城市的平均房价”或者“不同性别的平均成绩”,应该使用什么函数?groupby 是如何工作的?

📋 七、 板书设计

🛠️ 板书设计…
 14-2 DataFrame 基本操作与数据清洗预处理
 2
 3一、 精准定位与检索
 4  - loc[行名称, 列名称]  : 基于标签名称
 5  - iloc[行序号, 列序号] : 基于数字序号 (左闭右开)
 6  - 布尔筛选: df[(条件1) & (条件2)]   (注: 必须加小括号!)
 7  - 排序    : df.sort_values(by='列名', ascending=False)
 8
 9二、 数据清洗“四大件”
10  1. 缺失值 (NaN) -> df.isna().sum() / df.fillna(df['列'].mean())
11  2. 重复值       -> df.drop_duplicates()
12  3. 离散化 (分箱)-> pd.cut(df['列'], bins=[...], labels=[...])
13  4. 哑变量 (独热)-> pd.get_dummies(df['文本列']) (转换 0/1 矩阵)
14
15三、 预处理工程标准流程
16  原始 CSV ➔ 读取体检 ➔ 去重/补缺 ➔ 哑变量转换 ➔ 分离 X 与 y