代码语言

知识点思维导图

29 个知识节点

Python(21) - Pandas 数据分析

读完后,你应能完成以下任务:

  • 绘制“Python(21) - Pandas 数据分析 / 先给锚点:DataFrame ≈ 你后端拿到的「对象数组」”的关键对象与数据流,解释“边界一:取出一列得到的不是 Python list,而是 Series。”,并用源码位置、日志或 Trace 标注证据。
  • 为“Python(21) - Pandas 数据分析 / 读数据:CSV / Excel 一行搞定”设计正常与异常输入,验证“边界二:df.shape 这种是属性(无括号),df.head() 这种是方法(有括号)。”,输出首个偏差位置与回归测试结果。
  • 实现“Python(21) - Pandas 数据分析 / 选列与选行:loc / iloc 是新坑”的最小代码或配置,检验“边界三:iloc 切片左闭右开(同 JS),loc 切片左闭右闭(多取一个)。”,输出命令、结果与 Diff,并说明不适用边界。

你在前端天天和「一坨数据」打交道:后端返回的 [{name, age}, {name, age}, ...],你用 map / filter / reduce 一通处理,再渲染成表格。Pandas 干的就是这件事——只不过它把这个「对象数组」升级成了一张真正的二维表,并内置了 Excel 的「整列运算」和 SQL 的「筛选 / 分组 / 聚合」能力。本篇先用 array of objects 给你建立直觉,再立刻划清三处关键边界:列不是普通数组(是 Series)取行有 loc / iloc 两套语法别用 for 循环遍历(要向量化)

一、零、它在生态里的位置

Pandas 建在 NumPy(详见第 20 篇,NumPy ≈ 批量运算的「超级 Array」)之上。一句话分工:

类比 干什么
NumPy 超级 Array(纯数字) 底层数值计算引擎
Pandas 加强版 Excel / SQL 带列名、带索引的二维表,做数据分析
matplotlib 后端版 ECharts / D3(详见第 22 篇) 把表画成图

安装与导入(约定俗成 import pandas as pd,几乎所有教程都这么写,照做即可):

pip install pandas   # pandas 会自动把 numpy 一起装上

二、先给锚点:DataFrame ≈ 你后端拿到的「对象数组」

前端最熟悉的数据形态,就是后端返回的一个对象数组:

// JavaScript:一个「对象数组」,每个对象是一行
const users = [
  { name: "Tom", age: 18, city: "上海" },
  { name: "Amy", age: 25, city: "北京" },
  { name: "Bob", age: 30, city: "上海" },
]

Pandas 的 DataFrame 就是这个东西的「表格化升级版」——同样是一行行记录,但它知道自己有哪些、每行有个索引(index)

核心概念就两个,先记牢:

概念 类比 说明
DataFrame 整张 Excel 表 / SQL 表 二维:有行有列
Series 表里的一列 / 一个带标签的数组 一维:df["age"] 取出来就是它
index Excel 最左边的行号 默认 0,1,2…,也可设成日期、ID 等

边界一:取出一列得到的不是 Python list,而是 Seriesdf["age"] 不是 [18, 25, 30] 这种普通列表,而是一个带索引、能直接做整列运算的 Series(下一节就用到)。别下意识把它当 list 来 for 遍历。

三、读数据:CSV / Excel 一行搞定

前端读数据靠 fetch,Pandas 读数据靠一组 read_* 函数,最常用的是 CSV 和 Excel:

读进来后,第一件事永远是先「体检」,这几个方法你会天天用:

边界二:df.shape 这种是属性(无括号),df.head() 这种是方法(有括号)。这俩很容易混。判断标准:要不要「执行一个动作」——取已有的形状信息是属性,让它去算/去取前几行是方法。

四、选列与选行:loc / iloc 是新坑

4.1 选列:像取对象属性

4.2 选行:用 loc / iloc(这里和 JS 思路不同,重点)

JS 里取第 0 行你写 users[0]。Pandas 里 df[0] 会报错或被当成取列,取行必须用 loc / iloc

需求 JS Pandas
取一列 users.map(u => u.age) df["age"]
取第 N 行(按位置) users[n] df.iloc[n]
取前 3 行 users.slice(0, 3) df.iloc[0:3](左闭右开)
按标签取行 (无直接对应) df.loc[label]

边界三:iloc 切片左闭右开(同 JS),loc 切片左闭右闭(多取一个)。这是 Pandas 最反直觉的点之一。记法:iloc 是「位置」走数组那套,loc 是「标签」,标签区间天然包含两端。

五、筛选:布尔索引 ≈ filter(但写法是新的)

前端筛选用 arr.filter(条件)。Pandas 用一种叫布尔索引的写法——先算出一列「True/False」,再用它去框选行:

// JavaScript
const adults = users.filter(u => u.age >= 18)                       // 单条件
const shAdults = users.filter(u => u.age >= 18 && u.city === "上海")  // 多条件

两个高频坑,前端 100% 会踩:

常用的还有 isin(≈ JS 的 includes 判断)和 str 系列(针对字符串列):

六、整列运算:向量化,别写 for(性能关键边界)

这是 Pandas 最该改掉的 JS 习惯。前端给每个对象加字段,你会 for 一遍。Pandas 里直接对整列运算,底层走 NumPy 批量处理,又快又短:

// JavaScript:循环逐个处理
users.forEach(u => { u.ageNextYear = u.age + 1 })
const names = users.map(u => u.name.toUpperCase())

边界四(性能):能向量化就别 forfor i in range(len(df)): df.loc[i, ...] 这种逐行循环在 Pandas 里又慢又难读,几万行就明显卡。心智转变:从「遍历每个元素」改成「对整列下达一条指令」——这正是 NumPy/Pandas 的灵魂。真要逐行处理逻辑时用 df.apply(函数),但优先找向量化写法。

七、分组聚合:groupby ≈ SQL 的 GROUP BY

这是 DataFrame「像 SQL」的部分。需求:按城市分组,算每个城市的平均年龄、人数。SQL 你会写,对照看 Pandas:

-- SQL
SELECT city, AVG(age) AS avg_age, COUNT(*) AS cnt
FROM users
GROUP BY city;

常用聚合函数和 SQL 一一对应:mean() / sum() / count() / max() / min() / median()

value_counts() 是个超高频快捷方式——统计某列每个值出现多少次(≈ GROUP BY x COUNT(*) 再排序):

八、缺失值处理:真实数据一定有 NaN

读进来的真实数据,几乎必然有空值。Pandas 用 NaN(Not a Number)表示缺失,约等于 JS 的 null / undefined,但判空方式不同:

边界五:判断空值不能用 == None== NaNNaN == NaN 结果竟然是 False(IEEE 浮点规定,NaN 不等于任何值,包括它自己)。所以必须用 df["x"].isnull() / .notnull() 来判空,不要手写等号比较。

九、串起来:一个最小数据分析流程

把前面的拼成你真实会写的样子——读数据 → 清洗 → 派生 → 分组 → 导出:

这套流程就是阶段四的核心肌肉记忆:读 → 看 → 洗 → 算 → 出。出图的部分交给下一篇 matplotlib(第 22 篇,后端版 ECharts/D3)。

十、和前端思维的速查对照

操作 JavaScript(对象数组) Pandas
数据形态 [{...}, {...}] DataFrame
一列数据 arr.map(o => o.x) df["x"](是 Series)
行数 arr.length df.shape[0] / len(df)
取第 N 行 arr[n] df.iloc[n]
筛选 arr.filter(o => o.x > 1) df[df["x"] > 1]
多条件筛选 && / || & / |(每段加圆括号)
新增/派生列 forEach 里赋值 df["new"] = df["x"] + 1(整列)
映射转换 arr.map(...) 整列运算 / df["x"].apply(fn)
包含判断 [...].includes(o.x) df["x"].isin([...])
分组统计 reduce 手撸 df.groupby("x").agg(...)
计数 手动累加 df["x"].value_counts()
判空 o.x == null df["x"].isnull()(不能用 ==)
排序 arr.sort((a,b)=>...) df.sort_values("x")

十一、总结

  • 先给锚点:DataFrame ≈ 你后端拿到的「对象数组」:| Series | 表里的一列 / 一个带标签的数组 | 一维:df["age"] 取出来就是它 |
  • 读数据:CSV / Excel 一行搞定:边界二:df.shape 这种是属性(无括号),df.head() 这种是方法(有括号)。
  • 选列与选行:loc / iloc 是新坑:边界三:iloc 切片左闭右开(同 JS),loc 切片左闭右闭(多取一个)。
  • 整列运算:向量化,别写 for(性能关键边界):这是 Pandas 最该改掉的 JS 习惯。
  • 分组聚合:groupby ≈ SQL 的 GROUP BY:这是 DataFrame「像 SQL」的部分。
  • 缺失值处理:真实数据一定有 NaN:边界五:判断空值不能用 == None 或 == NaN。

学完自测

选择所有正确答案;提交后逐项核对判断依据。

1在“Pandas 数据分析”中,需要同时满足“零、它在生态里的位置”与“先给锚点:DataFrame ≈ 你后端拿到的「对象数组」”。给定正文约束“Pandas 建在 NumPy(详见第 20 篇,NumPy ≈ 批量运算的「超级 Array」)之上。”,哪些判断保持了原有处理机制?多选
2“Pandas 数据分析”出现偏差:“在“Pandas 数据分析 / 读数据:CSV / Excel 一行搞定”中,即使不满足“前端读数据靠 fetch,Pandas 读数据靠一组 read 函数,最常用的是 CSV 和 Excel”,结果与副作用仍会保持不变。”已成为实际行为。围绕“读数据:CSV / Excel 一行搞定”与“选行:用 loc / iloc(这里和 JS 思路不同,重点)”,哪些判断能定位被改变的职责或边界?多选
3评审“Pandas 数据分析”方案时,验收条件包含“Pandas 用一种叫布尔索引的写法——先算出一列「True/False」,再用它去框选行。”。关于“筛选:布尔索引 ≈ filter(但写法是新的)”与“整列运算:向量化,别写 for(性能关键边界)”的哪些决策符合正文机制?多选