4-3 DataFrame高级分析与特征提取

🎯 教学目标与重难点…

【三维目标】

  • 📚 知识目标

  • 掌握数据描述性统计分析函数(describe()mean()value_counts());

  • 深度理解并掌握“ split-apply-combine(拆分-应用-合并)”的 groupby() 分组运算及数据透视表(pivot_table());

  • 掌握时间序列转换与提取(pd.to_datetime().dt.year/.dt.month/.dt.dayofweek);

  • 掌握文本向量化字符串操作(.str.contains().str.split())与 category 分类类型的优化应用。

  • ⚙️ 能力目标

  • 能够熟练运用 groupbypivot_table 完成多维度的业务数据汇总与交叉分析;

  • 能够从原始“交易时间”或“文本描述”列中提取出可用于机器学习建模的衍生特征(如“是否周末”、“文本关键词包含”)。

  • 💡 素养目标

  • 建立从简单表格呈现提升到多维业务数据挖掘的宏观分析思维;

  • 体会高效数据类型(category)对系统内存优化的重要性,培养严谨的算力优化意识。

【重点与难点】

  • 🟢 教学重点groupby() 分组聚合机制;pivot_table() 交叉分析;时间序列 .dt 提取;字符串 .str 向量化操作。
  • 🟡 教学难点groupby 聚合后多重索引(MultiIndex)的平铺重置(reset_index());利用时间与文本提取机器学习衍生特征逻辑。

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

  1. 真实业务需求:除了清洗数据,我们如何从表格中挖掘规律?
  • 经过前面几节课的学习,我们已经能把表格洗得很干净。但老板或业务部门经常问:
  • “不同城市的平均房价和最高房价是多少?”
  • “不同性别的学生在各科目的成绩表现有什么差异?”
  • “用户更喜欢在周末下单还是工作下单?交易时间里蕴含着什么特征?”
  1. 从“表格管理”升维到“数据挖掘与高级特征提取”
  • 本节课将掌握 Pandas 的两大终极杀招:分组透视(分组统计)特殊数据类型(时间/文本)的衍生特征提取
  • 👨‍🏫 教师活动:展示一张包含“成交时间(如 2026-06-18 14:30:00)”和“用户地址”的电商订单表,引导学生思考如何把一串时间字符串变成机器学习能看懂的“季度”、“月份”或“是否周末”。
  • 🧑‍🎓 学生活动:积极思考并回答,体会到直接拿原始时间字符串无法计算,必须进行高阶类型转换与特征提取。

从业务统计与特征工程的实际需求出发,引入分组聚合与特殊类型处理,帮助学生完成从“数据操作者”到“数据挖掘者”的思维转变。


📖 二、 解决问题过程(一):数据统计分析与分组聚合(30 分钟)

1. 基础描述性统计

  • df.describe():一键输出数值列的计数、均值、标准差、极值与四分位数。
  • df['列名'].value_counts():快速统计离散分类变量的频数(如各城市房源数量)。

2. 核心机制:groupby() 分组运算

遵循 Split-Apply-Combine(拆分-应用-合并) 三步曲:

  • 拆分:按指定列(如“城市”)将数据拆分为多个子组;
  • 应用:对每个子组独立应用聚合函数(如 mean()sum()count());
  • 合并:将结果重新组合成一个全新的 DataFrame。

踩坑提醒groupby 聚合后,分组列会默认变成“行索引”。一定要加上 .reset_index() 将其重新还原为标准列,方便后续切片或喂给模型!

3. 数据透视表:pivot_table()

比 Excel 透视表更强大,适合多维交叉汇总:

  • 语法:pd.pivot_table(df, values='统计指标列', index='行分组列', columns='列分组列', aggfunc='mean')
 1import pandas as pd
 2
 3# 模拟二手房交易数据
 4df = pd.DataFrame({
 5    '城市': ['北京', '北京', '上海', '上海', '北京'],
 6    '户型': ['大户型', '小户型', '大户型', '小户型', '小户型'],
 7    '售价': [500, 220, 450, 180, 250],
 8    '面积': [120, 60, 110, 50, 65]
 9})
10
11# 1. 单列分组统计:计算各城市的平均售价与平均面积
12city_summary = df.groupby('城市')[['售价', '面积']].mean().reset_index()
13print("--- 各城市平均指标 (reset_index 后) ---")
14print(city_summary)
15
16# 2. 数据透视表:展示不同城市在不同户型下的平均售价
17pivot_res = pd.pivot_table(df, values='售价', index='城市', columns='户型', aggfunc='mean', fill_value=0)
18print("\n--- 城市 x 户型 交叉透视表 ---")
19print(pivot_res)
  • 👨‍🏫 教师活动:板书画出 groupby 的 Split-Apply-Combine 拆分合并流程图,重点强调 .reset_index() 的重要性;对比 groupbypivot_table 的适用场景。
  • 🧑‍🎓 学生活动:跟练代码,尝试更改聚合函数为 maxsum,观察分组汇总结果的变化。

分组与透视是 Pandas 分析的核心,通过图解拆分合并过程,帮助学生建立明确的维度聚合概念,避免因索引嵌套导致后续代码卡壳。


💻 三、 解决问题过程(二):特殊数据类型提取(时间序列、文本与 Category)(30 分钟)

在真实数据集中,日期时间和文本是提取强特征的“矿山”。

1. 时间序列处理(datetime

原始日期通常是字符串(如 '2026-06-18'),必须转换为 datetime64 类型,才能使用 .dt 访问器提取特征:

  • 转换:df['时间列'] = pd.to_datetime(df['时间列'])
  • 特征提取:
  • 年/月/日:.dt.year / .dt.month / .dt.day
  • 星期几:.dt.dayofweek(0 代表周一,6 代表周日)
  • 生成衍生特征:df['是否周末'] = (df['时间列'].dt.dayofweek >= 5).astype(int)

2. 文本字符串向量化操作(.str

针对字符串列,使用 .str 访问器 进行批量处理:

  • 包含判断(用于衍生特征):df['描述'].str.contains('精装修')(返回 True/False)
  • 字符串切分:df['地址'].str.split('-', expand=True)(将地址切分为多列)

3. 分类数据类型(category

将高重复性的字符串列(如“性别”、“省份”)转换为 category 类型:

  • 优势:大幅降低内存占用,加快 groupby 运算速度;
  • 转换:df['城市'] = df['城市'].astype('category')
 1import pandas as pd
 2
 3# 模拟带时间与文本的真实业务表
 4orders = pd.DataFrame({
 5    '订单ID': [101, 102, 103, 104],
 6    '下单时间': ['2026-06-15 10:00:00', '2026-06-20 14:30:00', '2026-06-21 09:15:00', '2026-06-22 20:00:00'],
 7    '备注描述': ['大户型 精装修', '小户型 毛坯房', '中户型 精装修', '小户型 简装'],
 8    '区域': ['海淀区', '朝阳区', '海淀区', '朝阳区']
 9})
10
11# 1. 时间序列转换与衍生特征提取
12orders['下单时间'] = pd.to_datetime(orders['下单时间'])
13orders['月份'] = orders['下单时间'].dt.month
14orders['星期几'] = orders['下单时间'].dt.dayofweek
15orders['是否周末'] = (orders['下单时间'].dt.dayofweek >= 5).astype(int)
16
17# 2. 文本特征提取:是否存在“精装修”关键字
18orders['是否精装'] = orders['备注描述'].str.contains('精装修').astype(int)
19
20# 3. 内存优化:转为 category
21orders['区域'] = orders['区域'].astype('category')
22
23print("--- 高级特征提取后的 DataFrame ---")
24print(orders[['订单ID', '月份', '星期几', '是否周末', '是否精装', '区域']])
25print("\n'区域'列的数据类型:", orders['区域'].dtype)
  • 👨‍🏫 教师活动:演示将字符串转为 datetime 后,如何用一行代码 .dt.dayofweek >= 5 衍生出“是否周末”的 0/1 特征;展示 .info() 中内存消耗变化,证明 category 的优化威力。
  • 🧑‍🎓 学生活动:在 Jupyter 中运行代码,尝试用 .str.contains() 提取其他文本关键词,并打印提取出的特征矩阵。

直接对标机器学习特征工程要求,把看似枯燥的“类型转换”转化为“如何从时间与文本中挖掘模型特征”,极大提升学生的实战兴趣。


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

📝 任务一:groupby 汇总与数据透视表实操…

背景与题目: 教师发放了一个员工销售业绩表 sales_data.csv,包含列:['部门', '职位', '销售额']。请编写代码完成以下分析:

  • 使用 groupby() 统计各部门的总销售额平均销售额,并使用 reset_index() 平铺索引。
  • 使用 pivot_table() 创建数据透视表,展示不同“部门”在不同“职位”下的平均销售额(缺失值填补为 0)。
🔍 查看参考代码与解析…
 1import pandas as pd
 2
 3df_sales = pd.read_csv('sales_data.csv', encoding='gbk')
 4
 5# 1. groupby 汇总 (使用 agg 应用多个聚合函数)
 6dept_summary = df_sales.groupby('部门')['销售额'].agg(['sum', 'mean']).reset_index()
 7dept_summary.rename(columns={'sum': '总销售额', 'mean': '平均销售额'}, inplace=True)
 8print("--- 部门销售额统计 ---")
 9print(dept_summary)
10
11# 2. pivot_table 透视表
12pivot_res = pd.pivot_table(
13    df_sales, 
14    values='销售额', 
15    index='部门', 
16    columns='职位', 
17    aggfunc='mean', 
18    fill_value=0
19)
20print("\n--- 部门 x 职位 平均销售额透视表 ---")
21print(pivot_res)

📝 任务二:时间与文本衍生特征提取综合实操…

背景与题目: 拿到的用户行为日志数据 user_logs.csv 包含以下列:['用户ID', '访问时间', '搜索关键词']。请编写代码提取出以下可喂给机器学习模型的特征:

  • 访问时间 列转换为 datetime 类型。
  • 提取出访问时间对应的 小时(hour,并生成一个新的二进制特征列 是否夜间(定义 22 点至次日 6 点为夜间,即 hour >= 22hour < 6)。
  • 搜索关键词 列进行判断,若包含关键字 “Python” 或 “数据分析”,则衍生特征列 是否高意向 标记为 1,否则标记为 0。
🔍 查看参考代码与解析…
 1import pandas as pd
 2
 3df_log = pd.read_csv('user_logs.csv', encoding='gbk')
 4
 5# 1. 时间类型转换
 6df_log['访问时间'] = pd.to_datetime(df_log['访问时间'])
 7
 8# 2. 提取小时并生成“是否夜间”特征
 9hours = df_log['访问时间'].dt.hour
10df_log['是否夜间'] = ((hours >= 22) | (hours < 6)).astype(int)
11
12# 3. 文本提取“是否高意向”特征
13pattern = 'Python|数据分析'
14df_log['是否高意向'] = df_log['搜索关键词'].str.contains(pattern, na=False).astype(int)
15
16print("--- 特征工程提取后的数据集前 5 行 ---")
17print(df_log[['用户ID', '访问时间', '是否夜间', '是否高意向']].head())

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

flowchart LR
    root["📊 4-3 高级分析与特征提取"]

    subgraph C1["📈 1. 分组与透视"]
        direction TB
        A1["groupby(): 拆分-应用-合并"]
        A2["关键操作: .reset_index() 平铺"]
        A3["pivot_table(): 交叉汇总透视表"]
    end

    subgraph C2["⏰ 2. 时间特征提取"]
        direction TB
        B1["pd.to_datetime(): 类型转换"]
        B2[".dt 访问器: year/month/day"]
        B3["衍生特征: .dt.dayofweek (是否周末)"]
    end

    subgraph C3["🔤 3. 文本与内存优化"]
        direction TB
        C1_node[".str 访问器: .str.contains()"]
        C2_node[".str.split(): 字符串切分"]
        C3_node["astype('category'): 内存优化"]
    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. 在执行 df.groupby('城市')['售价'].mean() 之后,结果的索引(Index)通常是?
  • A. 默认的数字自增序号(0, 1, 2…)
  • B. ‘售价’ 列的值
  • C. ‘城市’ 列的唯一值
  • D. 空索引
【答案】

【解析】C。Pandas 的 groupby 默认会把分组依据列(‘城市’)提升为返回结果的行索引(Index),需要调用 .reset_index() 才能恢复为普通列。

  1. 如果要将字符串格式的日期列 df['date'] 转换为 Pandas 可以提取年月日的日期时间类型,应该使用哪个函数?
  • A. df['date'].astype(int)
  • B. pd.to_datetime(df['date'])
  • C. df['date'].str.to_date()
  • D. pd.parse_time(df['date'])
【答案】

【解析】Bpd.to_datetime() 是 Pandas 中用于将标准字符串或标准序列转换为 datetime64 类型的通用标准函数。

  1. 使用 .dt.dayofweek 提取时间列的星期属性时,返回值为 5 代表星期几?
  • A. 星期五
  • B. 星期六
  • C. 星期日
  • D. 星期五或星期六
【答案】

【解析】B.dt.dayofweek 按照 Python 惯例,范围为 0 ~ 6,其中 0 代表星期一,5 代表星期六,6 代表星期日。

二、 简答与思考题

题目:请简述为什么在机器学习建模前,我们不能直接把原始的日期字符串(如 '2026-06-18 14:30:00')输入给模型?我们需要对它进行怎样的特征提取?

【答案】
  1. 原因:日期字符串是无序且非数值的文本,机器学习模型(如线性回归、逻辑回归、SVM)无法直接计算文本的离散数学含义。
  2. 特征提取方法
  • 使用 pd.to_datetime() 转为时间对象;
  • 利用 .dt 拆分提取周期性离散特征(如年份、月份、季度、小时);
  • 衍生逻辑特征(如 是否周末是否节假日是否工作高峰时段),将其转化为数值型二进制(0/1)变量输入给模型。

📮 六、 课后作业与拓展

📮 课后作业…
  1. 分组与透视巩固
  • 提取上节课清洗好的二手房数据集 clean_houses.csv
  • 按“城市”和“户型类别”进行双重分组,计算平均售价与最高售价。
  • 使用 pivot_table 将上述结果重构为以“城市”为行、“户型类别”为列的透视表。
  1. 时间与文本高级特征工程
  • 创建一个包含 10 条日志的 DataFrame,包含 ['用户ID', '注册时间', '个人简介']
  • 注册时间 转为时间类型,并新增一列 注册年份
  • 检查 个人简介 列,使用 .str.contains() 提取是否包含某些职业关键词(如“学生”、“程序员”),生成相应的 0/1 标志特征。
  1. 预习任务
  • 预习第 5 章(机器学习算法实战:如 KNN / 逻辑回归),思考:我们这几节课从 NumPy 切片到 Pandas 数据清洗、独热编码、时间特征提取所做的所有准备,是如何一步步拼凑出算法需要的 X_trainy_train 的?

📋 七、 板书设计

🛠️ 板书设计…
 14-3 DataFrame 高级分析与特殊类型特征提取
 2
 3一、 分组与透视 (数据的聚合与维度分析)
 4  1. groupby(分组列)[目标列].聚合函数()
 5     - 核心三步: Split (拆分) ➔ Apply (应用) ➔ Combine (合并)
 6     - 关键点  : 记得加 .reset_index() 把索引平铺还原为普通列!
 7  2. pivot_table(df, values=..., index=..., columns=..., aggfunc='mean')
 8
 9二、 特殊数据类型特征提取 (机器学习特征工程)
10  1. 时间序列 (datetime64)
11     - 转换: df['时间'] = pd.to_datetime(df['时间'])
12     - 提取: .dt.year / .dt.month / .dt.hour / .dt.dayofweek
13     - 衍生: df['是否周末'] = (df['时间'].dt.dayofweek >= 5).astype(int)
14  2. 文本字符串 (.str)
15     - 提取包含: df['列'].str.contains('关键词').astype(int)
16     - 拆分列  : df['列'].str.split('-', expand=True)
17  3. 内存优化 (category)
18     - 转换: df['列'] = df['列'].astype('category')  (降低内存、加快分组)
19
20三、 模块终极链路闭环
21  原始表格 ➔ pd.read_csv ➔ 清洗/去重/补缺 ➔ 特征提取 (.dt/.str/get_dummies) ➔ 导出干净 X 与 y