第2讲 · EECS 189:数据工具(Data Tools)
UC Berkeley EECS 189/289A《机器学习导论》2026 春季 · 课堂实录重构
| 主讲 | Jennifer Listgarten、Alex Dimakis |
| 视频 | https://www.youtube.com/watch?v=IzfaWKuxThw |
| 课程主页 | https://eecs189.org/sp26/ |
| 官方讲义/笔记(Lecture 2) | Google Drive PDF |
| 教材 | Machine Learning: A First Course for Engineers and Scientists(Lindholm 等) |
| 幻灯片致谢 | Lecture 2 幻灯片由 Joseph E. Gonzalez、Narges Norouzi 制作 |
| 图片来源 | 书中幻灯片插图为官方 PDF 高清渲染图;少量截图为视频画面 |
对应讲次:第2讲(UC Berkeley EECS 189 机器学习导论)
制作模型:deepseek-flash(coding-agent / pi;据 ~/.pi/agent/settings.json)
说明:本讲对应的 pandas 主题不在教材中;课程材料版权归 UC Berkeley 及授课教师所有,本书仅供学习
编者说明:本讲分两部分。前半段(约 00:03–00:31)回顾第一讲的机器学习范式与问题类型;后半段(约 00:31 起)进入本讲主题 pandas 与数据可视化。转录自英文自动字幕(滚动字幕),已去重整理并按官方幻灯片校准术语。
第一部分:回顾——机器学习的范式与问题类型
(参考时间: 00:03)
1. 从一个模型范式说起
上一讲我们学习了模型的通用范式:在一张表里,某一列是我们要预测的(特殊)列,这类问题称为监督学习(supervised learning)。
随后我们强调了一个机器学习中至关重要的观念:重要的不是训练集上的准确率,而是模型在新数据上的准确率。这就是贯穿整门课的核心矛盾——泛化(generalization)与过拟合(overfitting)。
2. 泛化、记忆与「奥卡姆剃刀」
总存在一些模型能在训练集上表现完美却「愚蠢至极」——这就是记忆模型(memorization model),而且它有很多变体。我们的一半工作,就是要确保模型不是在死记硬背,而是真正能预测新数据。
于是有了一个哲学式的判断:训练集上表现相同的许多模型里,越简单的模型越可能在明天的新数据上表现良好——这正是奥卡姆剃刀(Occam's razor):「能解释数据的最简单解释,往往最接近真相」。
当我们用这个观念去看不同模型族时:
- 对决策树,用深度或分裂次数衡量复杂度;
- 对回归,用系数的大小或非零系数的个数衡量复杂度。
一旦选定了复杂度的度量,就得到一整套降低该族复杂度的技术,统称为正则化(regularization)——即「强迫模型变简单」。这门课会大量使用它。
3. 什么样的任务适合机器学习?
机器学习要解决的问题,是那些容易演示 / 评估,却难以用规则硬编码(hard-code)的问题——也就是「用例子编程」。当人类无法完整地把你想要的东西写清楚、只能靠训练数据去描述时,就要用机器学习。所以「编程」AI 的方式,其实是「创造数据」——这也是数据整理(data curation)如此重要的原因。
flowchart LR
A["难以手写规则的问题"] -->|"提供训练数据"| B["监督学习:学习 f(x) ≈ y"]
B --> C["在应用中对新输入做推理(inference)"]
C --> D["持续获得反馈 / 迭代"]
D --> B
4. 监督学习:四类数据
监督学习要求存在目标列 $y$。按数据类型可分为四类:
(1)表格数据(tabular data)
- 给定房屋特征,预测售价——这是一份真实数据集(Kaggle 上有)。注意:训练出的房价模型不能做因果解释(例如「多一间卧室能多卖多少」),因为改变特征可能让你落到数据分布之外。
- 给定收入、教育程度、信用卡数量,预测个人是否会违约——这对发放信用卡 / 贷款的机构极有价值:利率就是风险定价,谁能更准地识别好客户,谁就能赢得这些生意。它同时也有社会价值:帮助信用记录不佳但实际可靠的人获得贷款,缓解现有系统中的不公平。
- 购物篮分析(market basket analysis):预测某位消费者会购买哪些商品、预测沃尔玛在 40 个门店的天气敏感商品销量——这能改善物流、减少食物浪费。
- 给定病人数据,预测临床结局或再入院。
📷 表格数据上的监督学习(房价、违约、购物篮、病人数据)
回到原视频 (00:12:35)
(2)图像 / 计算机视觉(image / CV)
- 经典的猫狗分类;
- 给定钢材图像判断是否有缺陷(真实数据集)——坐飞机、开车、住楼房的人都会在意钢材缺陷;
- 给定田间图像估计麦穗密度,这在农业上非常重要。
图像的关键区别在特征数量:一张 $n \times n$ 的图就有 $n^2$ 个特征;彩色图还要乘 3(红、绿、蓝)。我们要让模型从这些海量数字中判断「是否有缺陷」。
编者说明:讲师强烈建议去 Kaggle 上看这些竞赛——不仅能看到真实数据集,还能看到论坛里人们尝试的各种方法(特征工程、验证、优化……),以及你在这门课将要学到的所有技术。这些竞赛往往还有 $10{,}000–50{,}000 美元的奖金。参与它们能让你成为更好的机器学习实践者。
(3)时间序列(time series)
- EEG 记录:一维顺序信号(图像可以看成二维时间序列,但技术完全不同——时间序列通常用能利用序列结构的模型,而不是决策树或朴素线性回归);
- COVID 分城市预测、语音识别、音乐流派分类、金融时间序列预测等。
预测 EEG 有什么用?最直接的应用是癫痫发作预测:发作时 EEG 会剧烈变化,若能预测发作时刻,就能提前用药或帮助病人避免开车。预测的时间跨度越长(比如从 10 分钟延长到 1 小时),对患者生活的改善就越显著。
📷 时间序列上的监督学习(EEG、COVID 预测、语音)
回到原视频 (00:18:45)
(4)自然语言处理(NLP)
文本输入必须先转换成数字才能喂给模型。经典问题包括:Twitter 情感分类(关于可口可乐的推文是正面还是负面)、新闻分类(政治 / 体育 / 娱乐)、网络对话中的有害内容检测等。
5. 无监督学习
无监督学习中没有 $y$——你不预测某一列。那能做什么?
- 推荐系统:「买了这件商品的顾客也买了……」;
- 聚类(clustering):最经典的无监督学习——没有要预测的东西,只是寻找数据中隐藏的结构;
- 关联分析(association analysis):哪些商品常被一起购买。经典例子是「尿布与啤酒」——人们发现这两样常在超市一起被买走,于是把啤酒摆到尿布旁边,从而提升了啤酒销量;
- 异常检测(anomaly detection):你不知道要找什么,只知道要找「奇怪的、不同的」东西;
- 生成新数据:从 prompt 生成图像或文本——如今你已非常熟悉。它可以被转化为监督问题,但从根本上「从 prompt 生成新数据」是无监督问题,因为没有 $y$。
6. 机器学习简史与教材
(参考时间: 00:23)
AI 不是新学科,至少从 1950 年代的感知机(perceptron)论文就开始了。某种意义上,AI 比计算机科学更古老——先有「能否让机器思考」的想法,我们才发明了计算机科学。它经历了多次起落:50 年代的兴奋、AI 冬天、再次兴奋、第二次冬天;2010 年代 AlexNet 引发的深度学习革命让神经网络重新成为主流;而 2022 年 11 月开启的新革命,则让人们意识到重点不只是预测,更是生成文本、图像、视频与音频。
本课程使用的教材是 Machine Learning: A First Course for Engineers and Scientists。讲师建议大家下载它,课程会沿用书中的记号与概念(书中对概率框架的强调偏多,那部分我们不会全部遵循;且书中没有编程练习——编程活动会另行提供)。每次课都会给出对应的教材章节。
7. 课程路线图
(参考时间: 00:28)
- 第 1–2 讲:导论与机器学习机制(本讲所在位置);
- 第 3–6 讲:K-means、期望最大化(EM)、回归、分类、梯度下降;
- 第 7–8 讲:神经网络基础、反向传播、非线性与正则化;
- 期中考试;
- 更高级的架构:卷积网络、循环网络、Transformer 与大语言模型;
- 第 12–14 讲:生成模型、自编码器、降维等进阶主题;
- 最后两讲:嘉宾讲座与更高级的应用。
8. 机器学习的生命周期
(参考时间: 00:26)
一个真实机器学习系统的生命周期如下:
flowchart TD
A["现实问题"] --> B["把问题形式化<br/>(监督 / 无监督?预测什么?如何度量成功?用什么损失?)"]
B --> C["收集与整理数据<br/>(往往是最被低估、也最关键的一步)"]
C --> D["选择模型(假设空间)"]
D --> E["优化 / 训练参数"]
E --> F["在新数据上预测"]
F --> G["评估:训练/测试划分、交叉验证、正则化"]
G -->|"迭代"| D
- 形式化问题:把现实需求(例如「我要发信用卡」)翻译成模型能回答的问题(「给定这些特征,这个人会还款吗?」);
- 收集数据:讲师强调,这往往是最重要却最被忽视的一步。在真实公司里,最大的困难常常是「我有没有那些没有还款的人的数据?」「能不能 join 别的表把数据凑出来?」
- 选择模型 = 选择假设空间:树把空间划分成不规则的矩形区域,线性模型永远只能产生一个超平面。选模型族,本质上是在选择你对真实世界的假设;
- 优化:在训练数据上拟合参数(这是一门独立的优化课,CS 127);
- 评估泛化:通过训练 / 测试划分、交叉验证、正则化等,确保模型在新数据上也好——这正是本课要覆盖的内容。
📷 机器学习的生命周期
回到原视频 (00:26:10)
第二部分:Data Tools —— pandas 与可视化
(参考时间: 00:31)
2.1 为什么从数据开始
在机器学习中成功与否,取决于你如何处理实验的输入与输出。数据整理(data wrangling)与可视化,虽然可以自学,但讲师还是要做一个快速入门。今天要学的第一个工具是 pandas,第二个是可视化工具(Matplotlib / Plotly)。
📷 Data Tools 标题页
回到原视频 (00:31:53)
为什么先讲数据?因为数据是一切机器学习的基础:每个模型都始于数据、终于数据,它是训练与评估的原材料。处理输入输出的能力,无论进实验室还是进工业界,都是核心技能。
📷 为什么从数据开始
回到原视频 (00:32:00)
📷 本讲路线图
回到原视频 (00:32:15)
编者说明:pandas 的命名与由来——它代表「panel data(面板数据)」。历史上做机器学习的人用 MATLAB(没有 DataFrame),统计学家用 R(有 DataFrame);后来 pandas 把 DataFrame 原生引入 Python,在此之前大家用的是 NumPy,一切皆「矩阵」。
2.2 pandas 数据结构
pandas 让我们可以:把数据排成表格;按条件过滤提取信息;对数据运算获得新信息;用 NumPy 对数据做数值运算;以及做向量化(vectorized)计算以加速分析。它是科研与工业界处理表格数据的标准工具。
编者说明:讲师强调——你想做的每件事其实都能用
for循环写,之所以不这样写,是因为 pandas 的操作被优化成能对大表做并行化;表小的时候无所谓,但学会这种新的数据操作方式,处理大数据时会快得多。
📷 pandas 能做什么
回到原视频 (00:33:31)
📷 pandas 简介
回到原视频 (00:33:50)
pandas 的核心数据结构:一张表称为 DataFrame;表中的一列称为 Series;行、列的标签集合称为 Index。
📷 pandas 数据类型:DataFrame / Series / Index
回到原视频 (00:34:38)
- Series:一维带标签的数组。它由两部分组成——values(真实数据)与 index(标签,便于访问与操作)。
import pandas as pd
welcome_series = pd.Series(["welcome", "to", "CS 189"])
welcome_series.values
welcome_series.index
📷 Series
回到原视频 (00:35:00)
- DataFrame:由多个 Series 组成。例如把 Landmark、Type、Height、Year Built 四个 Series 拼成一张表。创建 DataFrame 的常见方式:从 CSV 文件、用字典、用「列表 + 列名」、或从 Series 构造。
📷 DataFrame
回到原视频 (00:36:30)
📷 创建 DataFrame
回到原视频 (00:37:05)
data = {
'Landmark': ['Sather Gate', 'Campanile', 'Doe Library',
'Memorial Glade', 'Sproul Plaza'],
'Type': ['Gate', 'Tower', 'Library', 'Open Space', 'Plaza'],
'Height': [30, 307, 80, 0, 0],
'Year Built': [1910, 1914, 1911, None, 1962]
}
df = pd.DataFrame(data)
# 实践中最常见:从 CSV 读取
event_data = pd.read_csv("data/uc_berkeley_events.csv", index_col='Year')
编者说明:讲师由此引出一个重要映射——在机器学习的语言里,列(columns)就是特征(features),行(rows/samples)就是样本。我们总是把特征按列堆叠;样本越多,行越多。
2.3 探索 DataFrame
理解 DataFrame 的结构与内容是数据分析的第一步。常用的「概览」方法有:head() / tail()、info()、describe()、sample()、value_counts()、unique()。
📷 探索 DataFrame
回到原视频 (00:37:42)
📷 DataFrame 的常用工具函数
回到原视频 (00:37:52)
head()/tail():显示前几行 / 后几行(默认 5 行;df.tail(3)显示后 3 行)。用机器学习的话说,head()显示前 5 个样本。
📷 head() 与 tail()
回到原视频 (00:38:12)
shape与size:df.shape给出「行数 × 列数」(如(5, 4));df.size给出元素总数($5 \times 4 = 20$)。
📷 shape 与 size
回到原视频 (00:38:48)
sample():随机抽取若干行(样本)。.sample(n=#)抽 $n$ 行;.sample(frac=#)按比例抽;.sample(n=#, replace=True)允许同一行被重复抽到(统计学上叫有放回抽样,用于 bootstrap);.sample(n=#, random_state=42)固定随机种子,保证可复现。
📷 sample()
回到原视频 (00:39:25)
编者说明:讲师特别强调可复现性(reproducibility)的重要性——你可能做出一个惊艳的结果,却在 57 个 notebook 里找不到是哪一个产生的。固定
random_state就能让每次运行得到相同结果。(至于为什么是 42?——它是《银河系漫游指南》里「生命、宇宙以及一切终极问题的答案」。)
value_counts():统计一个 Series 中每个唯一值出现的次数。unique():返回一个 Series 中所有唯一值(用 NumPy 数组返回)。
df['Type'].value_counts() # 各类型出现次数
df['Type'].unique() # 所有唯一值
📷 value_counts() 与 unique()
回到原视频 (00:40:50)
2.4 选择与提取数据:iloc 与 loc
(参考时间: 00:41)
按位置提取数据用 .iloc[]:
- 第一个位置是整数索引 0(Python 惯例);
.iloc的参数可以是:一个列表、一个切片(语法不含右端)、或一个单值;- 记忆要点:先行后列。
df.iloc[[1, 2]] # 第 1、2 行
df.iloc[[1, 2], [1, 2, 3]] # 第 1、2 行,第 1、2、3 列
df.iloc[2:4] # 第 2、3 行(不含右端 4)
df.iloc[:, 1:2] # 所有行,第 1 列
df.iloc[:, 0] # 所有行,第 0 列(得到一个 Series)
df.iloc[2] # 第 2 行
df.iloc[0, 1] # 第 0 行、第 1 列的元素
📷 按整数位置提取:iloc
回到原视频 (00:41:45)
📷 iloc 的参数与示例
回到原视频 (00:42:20)
📷 iloc:列表与切片
回到原视频 (00:43:05)
📷 iloc:切片语法不含右端
回到原视频 (00:43:45)
📷 iloc:( `:` 取全部行 )
回到原视频 (00:44:15)
📷 iloc:单值与元素定位
回到原视频 (00:45:15)
按标签提取数据用 .loc[]:
- 行标签、列标签(列名就是特征名,非常有用;而行标签在机器学习中通常没什么意义);
.loc的参数同样可以是列表、切片(语法含右端)、或单值。
df.loc[[1, 2]] # 第 1、2 行
df.loc[[1, 2], ['Type', 'Height', 'Year Built']]
df.loc[2:3] # 第 2、3 行(含右端 3!)
df.loc[:, 'Landmark':'Height'] # 所有行,Landmark 到 Height
df.loc[:, 'Landmark'] # 所有行,Landmark 列(Series)
df.loc[2] # 第 2 行
df.loc[0, 'Type'] # 第 0 行、Type 列
📷 按标签提取:loc
回到原视频 (00:45:55)
📷 loc 的参数与切片(含右端)
回到原视频 (00:46:38)
📷 loc:列表选择行列
回到原视频 (00:46:50)
📷 loc:切片含右端
回到原视频 (00:47:30)
📷 loc:单值选择
回到原视频 (00:48:35)
编者说明:讲师吐槽了
iloc与loc切片语义不一致带来的困惑——df.iloc[2:4]不含右端(2、3),而df.loc[2:3]含右端(2、3)。一个合理的解释是:把它们分别想象成「Python 列表切片」与「标签列表」——作为列表时当然要包含 3;作为 Python 切片时则会丢掉最后一个元素。实际使用中,请务必打印结果确认它做了你以为的事。
2.5 上下文相关的选择 []
[] 只接受一个参数,它可能是:
- 一个行号的切片(
df[1:3]); - 一个列标签的列表(
df[['Landmark', 'Year Built']]); - 一个单列标签(
df['Year Built'])。
也就是说,[] 是上下文敏感的。注意:df[1:3] 按位置切片;df[[1,2]] 若 1、2 不是列名会报错——这正是它让人困惑的地方。
📷 上下文相关的选择:只用方括号
回到原视频 (00:49:15)
📷 方括号:行切片
回到原视频 (00:49:22)
📷 方括号:列标签列表
回到原视频 (00:49:28)
📷 方括号:单列(Series)
回到原视频 (00:49:33)
2.6 过滤数据
(参考时间: 00:49)
我们学会了按位置(.iloc)或标签(.loc)提取数据。如果我们要提取满足某个条件的行呢?
.loc与[]也接受布尔数组:True对应的行被保留,False对应的行被丢弃;- 条件表达式(如
df['Height'] > 50)会产生一个布尔 Series; - 把这个布尔 Series 放进选择器,就完成过滤。
df['Height'] > 50 # 产生布尔 Series
df[df['Height'] > 50] # 过滤
df.loc[df['Height'] > 50] # 等价写法
📷 过滤数据
回到原视频 (00:49:48)
📷 用布尔数组过滤 DataFrame
回到原视频 (00:49:55)
多个条件可以用运算符组合:&(与)、|(或)、~(非)、^(异或)。
df[(df['Height'] > 50) & (df['Type'] == 'Library')]
📷 组合布尔 Series 进行过滤
回到原视频 (00:50:45)
| 符号 | 用法 | 含义 |
|---|---|---|
~ |
~p |
p 取反 |
\| |
p \| q |
p 或 q |
& |
p & q |
p 且 q |
^ |
p ^ q |
p 异或 q |
📷 位运算符
回到原视频 (00:51:16)
2.7 修改 DataFrame
(参考时间: 00:51)
添加 / 修改列很简单:用 [] 引用新列,再赋一个长度合适的 Series 或数组。
df['Experience'] = [2, 5, 1, 8, 4]
df['Height_Increase'] = df['Height'] * 0.1 # 向量化运算
📷 添加与修改列
回到原视频 (00:51:28)
📷 添加与修改列(续)
回到原视频 (00:51:38)
删除列——这是最容易踩坑的地方:
df.drop(columns=['Experience'])
print(df) # 咦?什么都没发生!
原因是:pandas 的大多数 DataFrame 操作不是原地(in-place)的——它计算出了结果,却没有「物化」回原对象(这样做是为了省内存)。要真正删除,需要:
df.drop(columns=['Experience'], inplace=True)
# 或直接赋值
df = df.drop(columns=['Experience'])
📷 删除列:不是原地操作
回到原视频 (00:51:58)
📷 删除列:inplace 或重新赋值
回到原视频 (00:52:42)
编者说明:讲师反复叮嘱——千万不要写一百行代码再
model.train(),因为几乎可以肯定某处埋着这类「看似成功实则没生效」的错误。每做一次切片或修改就打印出来看一眼,确认它真的按你想的做了。
排序用 sort_values(),可按一列或多列,升序或降序:
df = df.sort_values(by='Height') # 单列,默认升序
df = df.sort_values(by=['Height', 'Type'], ascending=[True, False]) # 多列,方向可不同
📷 排序 DataFrame
回到原视频 (00:53:24)
📷 按单列排序
回到原视频 (00:53:38)
📷 按多列排序
回到原视频 (00:53:48)
2.8 处理缺失值
(参考时间: 00:54)
缺失值是真实数据集的常见问题。处理方式有两类:检测与处理(删除或插补 imputation)。
df_missing.isnull() # 检测:返回布尔 DataFrame,标记所有缺失位置
df_missing.dropna() # 处理:删除任何含缺失的行/列(会显著缩小数据集)
df_missing.fillna() # 处理:插补
📷 处理缺失值
回到原视频 (00:54:05)
📷 用 isnull() 检测缺失值
回到原视频 (00:54:38)
📷 用 dropna() 删除缺失值
回到原视频 (00:54:55)
📷 用 fillna() 插补缺失值
回到原视频 (00:55:32)
编者说明:讲师给了一个重要判断——只有在缺失值极少时才建议直接
dropna(),否则会丢掉大量数据。更好的做法是插补:填补服从同一分布的值。fillna(0)是「非常糟糕」的做法——模型会以为这座建筑建于公元 0 年;退而求其次,可以填列的均值。你做的每一个假设,都在给你的模型增加或减少难度。
2.9 聚合与分组
(参考时间: 00:56)
聚合(aggregation)是对数据计算均值、和等汇总统计量。
df['Height'].mean() # 83.4
df['Height'].std() # 129.2...
df['Height'].idxmax() # 1(最大值的索引)
常见的聚合分三类:
- 基础:
summeanmedianminmaxcountnuniqueprod; - 统计:
stdvarsem(均值标准误)skew; - 逻辑与索引:
anyallfirstlastidxminidxmax。
📷 聚合 DataFrame
回到原视频 (00:56:30)
📷 在 pandas 中聚合数据
回到原视频 (00:56:52)
分组(grouping)稍复杂:把同一类别的行分组,再对每组做聚合。它强大在能够一次性完成大规模运算,并概括数据中的趋势。一个 .groupby() 操作包含「拆分(split)— 应用(apply)— 合并(combine)」三步。
📷 分组数据
回到原视频 (00:57:26)
📷 groupby:拆分—应用—合并
回到原视频 (00:57:42)
augmented_df.groupby('Type').agg(mean) # 各类地标的平均高度/年份
📷 groupby 示例
回到原视频 (00:57:55)
.agg() 里可以放任何把多个值汇总成一个值的函数,包括内置 Python 函数、NumPy 函数、pandas 函数:
.agg(sum) .agg(np.sum) .agg("sum")
.agg(max) .agg(np.max) .agg("max")
.agg(min) .agg(np.min) .agg("min")
.agg(np.mean) .agg("mean")
.agg("first")
.agg("last")
有些常用聚合甚至可以省略 .agg() 直接调用,例如 df.groupby("Type").mean()。
📷 聚合函数
回到原视频 (00:59:05)
按多列分组会得到一个二维表:
augmented_df.groupby(['Type', 'Campus']).agg('max')[['Height']]
它等价于一个透视表(pivot table):
pivot_table = pd.pivot_table(
augmented_df,
index='Type', # 行
columns='Campus', # 列
values='Height', # 值
aggfunc='max'
)
📷 按多列分组
回到原视频 (01:01:10)
📷 pivot_table
回到原视频 (01:01:50)
编者说明:讲师提醒——对缺失值做
mean聚合时,结果的实现细节(是否把 NaN 计入分母)可能出乎意料,实现里甚至可能有 bug(尤其在 PyTorch 中),所以永远要检查角落情况。
2.10 连接 DataFrame
(参考时间: 01:02)
连接(join)基于公共键或索引把不同来源的表格合并起来——这是从 SQL 继承来的操作,也非常重要。现实中数据常常分散在多张表里;如果连接得低效,计算会浪费巨大。连接前往往需要数据清洗:先意识到「这两张表可以按某一列连接」,而现实中列名往往并不相同。
例如把 event_data(活动数据)与 landmarks(地标)按年份连接:
# 内连接:只保留两张表中都能匹配上的行
result_join_inner = landmarks.join(
event_data.set_index('Year'), on='Year Built', how='inner')
result_merge_inner = landmarks.merge(
event_data, how='inner', left_on='Year Built', right_on='Year')
📷 连接 DataFrame
回到原视频 (01:02:30)
📷 连接事件与地标表
回到原视频 (01:02:52)
📷 内连接
回到原视频 (01:03:32)
# 外连接:保留两张表的所有行,无匹配处填 NaN
result_merge_outer = landmarks.merge(
event_data, how='outer', left_on='Year Built', right_on='Year')
📷 外连接
回到原视频 (01:04:20)
四类连接:
| 类型 | 含义 |
|---|---|
| Inner Join | 只返回两张表中键都匹配的行 |
| Outer Join | 返回两张表的所有行,无匹配处用 NaN 填充 |
| Left Join | 返回左表所有行,以及右表中匹配的行 |
| Right Join | 返回右表所有行,以及左表中匹配的行 |
📷 连接类型总结
回到原视频 (01:04:50)
第三部分:课堂测验(Slido)
(参考时间: 01:10)
讲师用 Slido 做了一个随堂小测,检验大家对 DataFrame 的理解。测验题目如下:
df['Type']返回什么?——返回一个 Series(该列)。df.tail(3)做什么?——显示最后 3 行。df['Type'].unique()返回什么?——一个包含Type列所有唯一值的 Series(对原始行标签建立索引,出现在每个值首次出现的位置)。
📷 Slido 课堂测验入口
回到原视频 (01:09:45)
📷 测验:选取 Type 列返回什么?
回到原视频 (01:10:37)
📷 测验:df.tail(3) 做什么?
回到原视频 (01:11:05)
📷 测验:Type 列的 unique 方法返回什么?
回到原视频 (01:11:51)
📷 自由提问环节
回到原视频 (01:12:26)
📷 Slido 课堂测验界面(视频画面)
回到原视频 (01:11:00)
编者说明:视频的后半段(约 01:05 之后)主要是课程事务与问答:助教介绍选课、同步选课(concurrent enrollment)、办公时间与讨论课安排、期中考试(3 月 17 日晚 7–9 点,线下)、作业发布时间等。这些内容与机器学习知识无关,此处从略。
总结(Takeaways)
- 机器学习要解决的是「容易演示、难以硬编码」的问题;因此「编程」AI 的方式本质上是创造数据。
- 监督学习按数据类型分为表格、图像、时间序列、文本四类;无监督学习包括聚类、关联分析、异常检测、生成。
- 贯穿始终的主线是泛化 vs 过拟合:要避免「记忆模型」,用奥卡姆剃刀与正则化去偏爱简单的模型。
- pandas 是处理表格数据的第一工具:核心对象是 DataFrame / Series / Index;列是特征,行是样本。
- 掌握四组操作:探索(head/tail、shape/size、sample、value_counts/unique)、选择(
iloc按位置、loc按标签、[]上下文相关)、过滤与修改(布尔过滤、增删列、排序、缺失值处理)、聚合与连接(groupby、pivot_table、join)。 - 一条实用的工程纪律:每做一步操作就打印出来检查——因为 pandas 的多数操作不是原地的,错误往往悄无声息。
附录:课堂未展示的幻灯片
以下幻灯片属于本讲官方 deck 的「可视化(Visualization)」部分,本次录像未讲到,作为延伸阅读收录。
🖼️ 可视化(章节页)
🖼️ 为什么要可视化数据
🖼️ 绘图库概览
🖼️ Matplotlib(章节页)
🖼️ Matplotlib 简介
🖼️ Plotly(章节页)
🖼️ 为什么用 Plotly
🖼️ 用 Plotly 绘图的三种方式
🖼️ 使用 pandas 内置绘图函数
🖼️ 使用 Plotly Express
🖼️ 如何进一步学习
🖼️ 致谢与参考
附:官方参考与延伸阅读
版权说明:本讲视频、幻灯片与课程材料版权归 UC Berkeley EECS 189/289A 课程团队(Jennifer Listgarten、Alex Dimakis 及幻灯片作者 Joseph E. Gonzalez、Narges Norouzi)所有。本书为课堂内容的学习性中文重构,仅供学习交流。