CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
机器学习入门/课时/Python 与数据栈
RawBlame
课时目录12 节

机器学习入门

  1. 01机器学习是什么
  2. 02数学基础
  3. 03Python 与数据栈
  4. 04数据预处理
  5. 05监督学习
  6. 06无监督学习
  7. 07模型评估
  8. 08Scikit-learn 工作流
  9. 09深度学习基础
  10. 10NLP 与 Transformer
  11. 11TensorFlow 与 PyTorch
  12. 12综合练习

Python 与数据栈

NumPy、Pandas、Matplotlib。

35 分钟

Python 与数据栈

这一课你将能做到

  1. 用 numpy 做向量化统计(均值、布尔筛选),不写 for 循环
  2. 用 pandas 加载做题记录表,完成筛选、新增列、groupby 聚合,算出每道题/每个知识点/每个用户的正确率
  3. 用 matplotlib 画出正确率柱状图和用时分布直方图,导出成图片

为什么要学

机器学习的工作流里,建模只占两成,剩下八成是「把数据变成模型能吃的形状」。numpy 是所有 Python 数值库的底层(sklearn、pandas、PyTorch 的数据结构都向它看齐),pandas 是表格数据的瑞士军刀(本站的做题记录、题目表、用户表全靠它),matplotlib 是你观察数据的第一双眼睛。

这一课不做模型,只练「数据操作肌肉」——后面每一课的代码都默认你已经会这些。

先建立图像

numpy        pandas         matplotlib
ndarray   →  DataFrame   →  图表
一列数字     一张带表名的表    柱状/折线/直方/散点
  ↓            ↓              ↓
算得快        行列都能筛选     肉眼找规律
(底层C实现)   (能按名字取列)   (趋势/异常一目了然)

本站数据流:
原始做题记录 → pandas 清洗聚合 → 特征表(矩阵) → 模型

跟着做

步骤 1:环境与 numpy 向量化

python -m venv .venv && .venv\Scripts\activate
pip install numpy pandas matplotlib
import numpy as np

scores = np.array([1, 0, 1, 1, 0, 1])          # 6 次作答,1=对
print(scores.mean())                            # 0.667 正确率
durations = np.array([45, 120, 60, 40, 200, 55])
print(durations.mean(), durations.std())        # 平均用时和波动

mask = durations < 90                           # 布尔掩码
print(scores[mask].mean())                      # 只统计 90 秒内作答的正确率

注意 scores[mask]:没有 for 循环,一行完成「筛选+统计」,这叫向量化,比 Python 循环快一个数量级。

步骤 2:pandas 构造做题记录表

import pandas as pd

records = pd.DataFrame({
    "user":     ["u1", "u1", "u1", "u2", "u2", "u3", "u3", "u3", "u3", "u2"],
    "question": ["q1", "q1", "q2", "q1", "q2", "q2", "q3", "q3", "q1", "q3"],
    "topic":    ["循环", "循环", "集合", "循环", "集合", "集合", "多线程", "多线程", "循环", "多线程"],
    "correct":  [1, 1, 0, 1, 1, 0, 0, 1, 0, 0],
    "seconds":  [42, 51, 130, 38, 66, 145, 210, 160, 98, 175],
})
print(records.head())       # 前几行长什么样
print(records.describe())   # 数值列的统计摘要

DataFrame 就是「带名字的 Excel 表」:records["seconds"] 取一列(Series),records[records["correct"] == 0] 筛行。

步骤 3:筛选与新增列

# 筛出多线程的所有作答
thread = records[records["topic"] == "多线程"]
print(thread["correct"].mean())          # 多线程正确率

# 新增列:是否超时(超过 2 分钟算卡壳)
records["is_slow"] = records["seconds"] > 120
print(records[["question", "seconds", "is_slow"]])

步骤 4:groupby 聚合——题目难度和用户画像的雏形

# 每道题的正确率 → 难度评分的雏形(正确率越低越难)
difficulty = records.groupby("question")["correct"].mean()
print(difficulty.sort_values())          # 正确率最低的题排最前

# 每个知识点:正确率、平均用时、作答次数,一次算完
topic_stat = records.groupby("topic").agg(
    accuracy=("correct", "mean"),
    avg_seconds=("seconds", "mean"),
    attempts=("correct", "size"),
)
print(topic_stat)

groupby 的逻辑是「拆分-应用-合并」:按 topic 拆成小表 → 各自算均值 → 拼回一张汇总表。这是特征工程里最高频的操作。

步骤 5:matplotlib 出图

import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]   # Windows 中文字体
plt.rcParams["axes.unicode_minus"] = False

fig, axes = plt.subplots(1, 2, figsize=(10, 4))
difficulty.plot(kind="bar", ax=axes[0], title="题目正确率(越低越难)")
records["seconds"].plot(kind="hist", bins=6, ax=axes[1], title="作答用时分布")
plt.tight_layout()
plt.savefig("stats.png", dpi=120)
plt.show()

两张图直接告诉你:哪道题最需要修(正确率异常低)、用户卡壳集中在什么时间段(用时直方图的长尾)。

讲清楚要点

  1. 向量化是 pandas/numpy 的灵魂:df["correct"].mean() 比逐行 for 循环快得多也更不容易错。看到自己写了 for i in range(len(df)),九成是写法有问题。
  2. Series 和 DataFrame 是两级结构:单列是 Series(带索引的数组),整表是 DataFrame(多个 Series 共用索引)。搞混这两级是初学者报错的重灾区。
  3. groupby 是特征工程的发动机:「该题全站正确率」「该用户历史正确率」「该知识点平均用时」全都是 groupby 出来的,ml-practice 综合项目会大量使用。
  4. 图表选型:类别对比用柱状图,数值分布用直方图,两变量关系用散点图,时间趋势用折线图。选错图,数据会撒谎。
  5. describe() 先看一眼再动手:均值、分位数、最大值扫一遍,缺失和异常往往当场现形。

你可能会懵的地方

  • loc 和 iloc 有什么区别? loc 按标签(行名/列名),iloc 按整数位置。df.loc[0, "seconds"] 是「行标签为 0、seconds 列」,df.iloc[0, 4] 是「第 0 行第 4 列」。筛选后索引不连续时两者差异最明显。
  • NaN 是什么?和 None 一样吗? NaN(Not a Number)是浮点世界的缺失值标记,df.isna() 统一识别 NaN 和 None。它有个坑:NaN == NaN 是 False,判断缺失必须用 isna()。
  • SettingWithCopyWarning 是怎么回事? 链式筛选后赋值可能作用在副本上,改动不生效。正确姿势是单次定位:df.loc[mask, "col"] = value,或者先 df = df.copy() 再改。
  • Jupyter 和脚本怎么选? 探索数据、画图、试特征用 Jupyter(即时反馈);可复用的清洗/训练流程写成 .py 脚本进版本库。上线的东西永远别从 notebook 里直接拷。
  • 数据量大 pandas 卡怎么办? 先确认真的卡(10 万行 pandas 毫无压力)。真到了千万级,用 pd.read_csv(chunksize=...) 分块处理,或者改用 Polars/DuckDB——但那是后话。

错法对照

错法问题正解
for i in range(len(df)) 逐行算正确率慢且易错df.groupby("question")["correct"].mean()
df[col] == None 判断缺失永远 Falsedf[col].isna()
链式写法 df[a][b] = 1 赋值可能改在副本上df.loc[mask, col] = 1
中文标签没设字体直接 plt图上全是方框先设 font.sans-serif(见步骤 5)
修改了切片以为改了原表SettingWithCopyWarning用 .loc 单次定位或显式 .copy()

卡点急救

  1. matplotlib 中文全是方框:Windows 设 SimHei,macOS 设 Arial Unicode MS/PingFang SC;还乱就检查 axes.unicode_minus = False。
  2. 读 CSV 中文乱码:Excel 导出的文件用 pd.read_csv(path, encoding="utf-8-sig") 或 "gbk" 试一遍。
  3. pip 安装慢/超时:换国内镜像 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy pandas matplotlib。

面试常问

  • pandas 的 groupby 原理是什么? 拆分-应用-合并(Split-Apply-Combine):按 key 把表拆成组,对每组应用聚合函数,再把结果合并成新表。配合 agg 一次算多个指标,是特征工程的核心操作。
  • 为什么 numpy 比 Python 列表快? numpy 底层是 C 实现的连续内存同类型数组,支持 SIMD 向量指令和广播;Python 列表是对象指针数组,每次运算都有解释器开销和类型检查。
  • 如何用 pandas 找出异常值? describe() 看分位数轮廓;用 quantile 的 IQR 法(低于 Q1-1.5IQR 或高于 Q3+1.5IQR)或 3σ 法筛出离群行,再结合业务判断是删、是截断还是单独分箱。

自测三问

  1. 不用 for 循环,怎么算「每道题的正确率」?
  2. df.loc 和 df.iloc 的区别是什么?
  3. 想看「作答用时有没有长尾」,该画什么图?

小结一句话

numpy 管数组、pandas 管表格、matplotlib 管出图,groupby 聚合是特征工程的发动机——这三件套熟练了,建模前的八成工作就顺了。

延伸

  • pandas 官方文档
  • 下一课:ml-preprocess 数据预处理——缺失值、编码、标准化,以及最要命的「数据泄漏」。
加载本节练习…
← 上一课数学基础下一课 →数据预处理