Skip to content

Ch01: Python数据处理学习笔记

本文对应教程:第1章: Python数据处理

1. DataFrame 是什么?

  • 可以把 DataFrame 理解成“带列名的表格”。
  • 通常是一条样本记录(一个乘客),是特征字段(年龄、舱位等)。
  • 两个最常用的对象:
    • df:整张表(DataFrame)
    • s:一列(Series,类似单列)

关键区别:

  • df["age"] 取出来是一列(Series)
  • df[["age", "fare"]] 取出来是两列(DataFrame)

2. 读取数据与路径(本地优先)

这章建议用本地 CSV(已经在工作区准备好):

  • 数据文件:ml-work/data/titanic.csv

常见坑:

  • 相对路径是“相对于当前运行目录(working directory)”,不是相对于你以为的文件夹。
  • 如果找不到文件(FileNotFoundError),先确认当前工作目录:os.getcwd()

3. “体检三件套”:结构、类型、样例

刚读入数据后,建议按顺序做:

3.1 看数据有多大

  • df.shape:返回 (行数, 列数)
  • len(df):行数

3.2 看有哪些列

  • df.columns:所有列名
  • list(df.columns):把列名变成列表,方便复制/挑选

3.3 看每列是什么类型

  • df.dtypes:每列 dtype(数值、字符串、布尔、类别等)

要关注的信号:

  • 本该是数值的列却显示为 object(通常是字符串混入/缺失值格式不统一)
  • 类别列(例如 sex、embarked)通常是 object,后续建模需要编码(第 5 章会系统做)

3.4 看几行样例

  • df.head():看前 5 行
  • df.tail():看最后 5 行
  • df.sample(n=5, random_state=0):随机抽 5 行(更能发现脏数据)

4. 缺失值:怎么发现、怎么表达、怎么处理

4.1 怎么发现缺失

  • df.isna():True/False 表
  • df.isna().sum():每列缺失数量
  • df.isna().mean():每列缺失比例(0~1)

常见做法:

  • 先把缺失率按从高到低排序:sort_values(ascending=False)
  • 只看前 10 个缺失最多的列:head(10)

4.2 缺失值策略(不要“默认填 0”)

你需要能说清楚“为什么这样做”,常见策略:

  • 删除(drop):
    • 适合:缺失极多且列不重要,或缺失行很少
    • 风险:可能引入偏差(缺失并非随机)
  • 填充(fill):
    • 数值列:常用中位数(median)或均值(mean)
    • 类别列:常用众数(mode)或填一个特殊值如 "UNK"
    • 风险:会改变分布;要在 README 里记录

建议在 Titanic 上先做“最简单且可解释”的:

  • age:中位数填充(对极端值更稳)
  • embarked:填 "UNK"(明确表示未知类别)

5. 频数统计:value_counts(非常常用)

当一列是“类别/标签”时,第一眼看:

  • s.value_counts():每个类别的计数
  • s.value_counts(normalize=True):每个类别的比例

典型用途:

  • 看标签是否不均衡(比如 survived 的 0/1 比例)
  • 看某个类别列是否有脏值(拼写不一致、大小写混乱等)

6. 选列、删列、改列名(让数据变“你能控制”)

6.1 只保留一组列

  • 先写一个 keep = [...] 列表,然后用 df = df[keep]

6.2 删除列

  • df.drop(columns=[...])

6.3 改列名

  • df.rename(columns={"old": "new"})

为什么要做这些:

  • EDA 时列太多会分散注意力;本章先聚焦“最常用的 7~10 列”即可。

7. 过滤与排序:把“问题”变成“子集”

常见操作:

  • 过滤行:df[条件]
    • 例:df[df["age"].notna()] 表示只取年龄不缺失的行
  • 排序:df.sort_values("fare", ascending=False)

你在写问题时可以用这种句式:

  • “只看某个舱位的人”
  • “只看有年龄记录的人”
  • “按票价从高到低看极端样本”

8. 分组统计:groupby(从“表”得到“结论数字”)

核心思路:

  • 先按某列分组(比如 pclass)
  • 再对另一列做聚合(比如 survived 的均值 = 幸存率)

常见聚合:

  • mean:均值(二分类的均值就是比例)
  • median:中位数(更稳)
  • count/size:数量

Titanic 最常用:

  • df.groupby("pclass")["survived"].mean():不同舱位幸存率
  • df.groupby("sex")["survived"].mean():男女幸存率

9. describe:快速得到数值列分布概览

  • df.describe():数值列的 count/mean/std/min/四分位数/max

你要关注:

  • count 明显小于总行数:说明缺失多
  • min/max 极端离谱:可能有异常值或录入错误

10. 画图的最小心法(本章只要“能回答问题”)

不需要追求复杂可视化,先掌握 3 种图:

  1. 直方图(分布):一个数值列长什么样
  • 适合:age、fare
  1. 柱状图(对比):不同类别的均值/比例
  • 适合:pclass 对 survival rate
  1. 箱线图(对比分布):两组之间的差异
  • 适合:fare 在 survived=0/1 的差异

画图时写结论的模板(强烈建议你直接照抄):

  • “图回答的问题是:____”
  • “我观察到:____”
  • “可能的解释是:____(可选)”
  • “下一步我想验证:____(可选)”

11. 导出干净数据(让结果可复现)

  • df.to_csv("clean.csv", index=False):导出 CSV

练习

  • 画一张不同舱位对应存活率的柱状图
python
import matplotlib.pyplot as plt

# 1) 分组 + 求均值(survived 是 0/1,均值就是存活率)
survival_by_class = df.groupby("pclass")["survived"].mean().sort_index()

# 上面这种链式调用看起来会比较混乱,对于新手来说不是很友好,所以选择下面这四行的方式会更轻松一些

g = df.groupby("pclass")          # ① 按 pclass 分组:把数据按 1/2/3 舱位分成三堆
s = g["survived"]                 # ② 只取每一堆里的 survived 这一列(0/1)
rate = s.mean()                   # ③ 对每一堆求均值:0/1 的均值 = 1 的比例 = 存活率
survival_by_class = rate.sort_index()  # ④ 按索引排序(让 1,2,3 按顺序显示)


# 2) 画柱状图
ax = survival_by_class.plot(kind="bar", title="Survival rate by pclass")
ax.set_xlabel("pclass")
ax.set_ylabel("survival rate")

# 3) 显示
plt.show()

output

数据清洗

数据清洗这件事,你可以按一个固定流程来做(每一步都能解释“我为什么这么做”)。我用 Titanic 做例子,但你以后换数据集也一样。

0) 先定目标:这次“干净”指什么

  • 你后面要做监督学习(预测 survived),所以清洗目标通常是:
    • 选出一组你要用的列(特征 + 标签)
    • 处理缺失值(让表里没有模型不能接受的 NaN,或明确保留 NaN)
    • 处理类型(数值列真的是数值;类别列统一格式)
    • 输出一个可复现的 clean.csv

1) 选列(先少后多) 建议先只保留最常用的 8 列,降低复杂度:

  • 标签:survived
  • 特征:pclass, sex, age, sibsp, parch, fare, embarked

为什么这么做:这些列信息量大、缺失相对可控、后续建模也方便。

2) 检查缺失:缺失率 + 缺失在哪里 你已经会算缺失率 top10 了。接下来你要做两件事:

  • 记录哪些列缺失多(Titanic 通常是 ageembarked 少量缺失,deck 很多缺失)
  • 决定策略:删/填/保留

3) 缺失值策略(Titanic 的“新手可解释方案”)

  • age(数值):用中位数填充
    理由:中位数对极端值更稳;先跑通流程最重要。
  • embarked(类别):用 "UNK" 填充
    理由:明确表示未知类别,不会把缺失“伪装成真实港口”。
  • 其他列如果缺失很少:你也可以选择“直接删掉缺失行”,但要写清楚删了多少行、为什么删。

4) 类型清洗(保证每列是你以为的类型) 重点看:

  • survived:确保是整数 0/1
  • pclass, sibsp, parch:应该是整数
  • age, fare:应该是数值(float)
  • sex, embarked:字符串/类别都可以,但要保证没有奇怪空格、大小写混乱

一个简单的习惯:对字符串列做 strip() 去掉首尾空格(如果有)。

5) 异常值 / 逻辑检查(轻量但很重要) 不用复杂,先做“常识检查”:

  • age 是否有 <0 或特别离谱的值
  • fare 是否有 <0
  • pclass 是否只包含 1/2/3 这些检查能帮你发现数据读错或脏值。

6) 产出与记录

  • 导出:保存为 clean.csv
  • 记录(写在 README 或 notebook 文字里):
    • 你保留了哪些列
    • 每个缺失值处理的理由
    • 清洗前后数据行数变化、缺失率变化(至少写一句)