Pandas — 一次真实的数据清洗全流程
Pandas — 一次真实的数据清洗全流程
这一章讲 Pandas——Python 的数据分析库。 原书的教法值得称道:不背 API, 而是拿一份网上找来的、有真实毛病的脏数据,一步步洗到能用。 走完这一遍,你学到的不是函数清单,而是 Pandas 的心智模型: 表格 = 带名字的列;一切操作 = 先造一张「真假表」(掩码),再拿它筛行、改列。
1. 这一章讲什么
Pandas 建立在 NumPy 之上,提供表格和时间序列的数据结构,接口对使用者更友好; 因为底层是 NumPy,所以大数据集也能高效处理。1
书里坦白:「其实 NumPy 什么都能做,用 Pandas 只是省大量功夫。」——这句实话定位了两者的关系。
本章结构不是参考书的 A-Z,而是一条叙事线:
一份脏数据(txt,制表符分隔,有缺失、有「订房公司」散行)
→ 读入 → 看清结构(head)
→ 定位特殊行(布尔掩码)→ 把公司名回填给每一行(bfill)
→ 删脏行(~掩码)→ 类型修正(float → int)
→ 删多余列 → 造日期列、造价格列
→ 统计(count/sum/corr)→ 排序
图说:每一步只干一件事——这本身就是第 05/07 章「别合并步骤」的示范。2. 核心原理:主线例子逐步走
2.0 先立模型:DataFrame 是什么
读代码之前,花十秒钟把 Pandas 的核心对象DataFrame的形状装脑子里—— 它就是一张 Excel 表在 Python 里的样子:2
Date Company Person Name Room number
0 1-Jan-2022 Avamba Anatole Ridehalgh 4008.0 ← 最左列 0,1,2,… 是行索引(自动生成)
1 1-Jan-2022 Fatz Aldrich McKevin 2002.0
…三样东西就够了:列(有名字,按名字取:data["Room number"])、行(每行挂一个编号,这个编号叫索引)、格子。
之后本章的每个操作,都只是对这三样东西的统一动作:按列取、按行筛、按格改。
NumPy 血统带来的那条性质也在这张图上:对一列的运算作用于整列(500 行和 5 行,写法相同)。
2.0b 这份数据的三宗罪,逐条诊断
在动手之前,书里先对原始数据做了「病历登记」,这个诊断顺序值得学:3
| 症状 | 例子 | 病根 |
|---|---|---|
| 公司名缺失 | 第 8、9 行 Company 是 NaN | 数据本身漏填 |
| 「订房公司」写在独立行 | 第 3 行整行只有 "Hotels" | 上游格式反常规:公司名放在它管辖段的下方 |
| 房号显示成 4008.0 | 整列浮点 | NaN 把列拖成了浮点(第 2.5 节修复) |
作者的态度也分层:缺公司名「不太担心,值会被填成 NaN,机械部分自动处理」; 真正烦的是订房公司行——「这数据本该写成正常的 csv 或 json」。 这个分层是数据工作的常态:机械问题(缺值)留给工具的默认行为,格式问题(结构违反约定)才需要人想办法。 顺序也别反:先看清三宗罪,再写第一行清洗代码。3
2.1 读入与第一眼
数据文件长这样(制表符分隔的四列,其中混着两行「订房公司名」):
Date Company Person Name Room number
1-Jan-2022 Avamba Anatole Ridehalgh 4008
1-Jan-2022 Fatz Aldrich McKevin 2002
...
Hotels ← 这一行不是预订,是「上面几行属于 Hotels 这家公司」
...import pandas as pd
import numpy as np
data = pd.read_csv("data.txt", sep="\t") # \t 是制表符
print(data.head(12))pd.read_csv 读入后得到 DataFrame(Pandas 的表格类型:带名字的列 + 自动编号的行);
head(12) 打印前 12 行看一眼。第一眼的发现很重要:3
| 观察 | 含义 |
|---|---|
| 有行的 Date 是 "Hotels"/"Booking" 而 Company 是 NaN | 订房公司写在单独一行,位置在它管辖的预订段之后 |
| 有些行 Company 是 NaN | 缺公司名的普通预订 |
| Room number 显示 4008.0 | 列被读成了浮点(因为 NaN 是浮点) |
NaN(Not a Number,非数——这里泛指「缺失」)是 Pandas 的占位符:
缺了的格子自动填 NaN,这正是「缺失别担心」的机械部分;真正麻烦的是那些「Hotels/Booking 行」——
它们违反了一行一条记录的约定。4
2.2 定位特殊行:布尔掩码
解决什么问题: 把「Hotels/Booking 行」和正常预订行分开。
怎么做: 这些行的特征是「Room number 是 NaN」。造一张布尔掩码(Boolean mask)—— 一个和表格等长、每格 True/False 的序列:
mask = data["Room number"].isna() # 每行一个判断:该行的 Room number 是不是 NaN
print(mask.head(12))
# 0 False / 1 False / 2 False / 3 True(Hotels 行!) / …为什么有效: 掩码把「哪几行符合条件」从循环里解放出来—— 后面所有「筛/改」都以它为输入,一步一个意图(书里的纪律:「一次只做一件事」)。5
掩码的形状值得在脑子里固化:data["Room number"] 是一列(每行一个数),
.isna() 对它逐格判断,得到的 mask 还是「每行一个值」,只是数变成了 True/False。
表 → 列 → 掩码,三个对象等长对齐——这是 Pandas 全部花式操作的地基:
对齐不上的操作(长度不同)会直接报错,这也是 Pandas 比手写循环安全的地方之一。
# 0 False / 1 False / 2 False / 3 True(Hotels 行!) / 4 False / …这 12 行输出里,只有第 3、11 行是 True——正好就是 "Hotels"、"Booking" 那两行。 一张掩码就是一张「点名表」:点到的留下(或删去),一句话的事。5
2.2b np.where 的三参数,逐个对位
np.where(mask, data["Date"], np.nan) 是 NumPy 的「三元运算」,三个参数逐个对位:6
np.where(条件, 条件为 True 时取这个, 条件为 False 时取这个)
mask data["Date"] np.nan
逐行执行:第 0 行 mask=False → 取 np.nan;第 3 行 mask=True → 取 Date 的值 "Hotels"
结果:text_value 列 = [NaN, NaN, NaN, "Hotels", NaN, …, NaN, "Booking", NaN, …]为什么不直接 data["text_value"] = data["Date"] 再删掉非公司行?——因为那样会把所有行的 Date
先抄进 text_value,信息混在一起,后面没法分辨「谁是真公司行」。np.where 的好处是脏数据从未存在过:
非公司行的 text_value 从第一步就是 NaN,干净的起点带来干净的后处理。6
2.3 回填公司名:造列 + bfill
解决什么问题: 把每段的订房公司(在第 3、11 行的 Date 列里!)抄到它上面的每一行。
怎么做,两步:6
# 第一步:新列 text_value —— 是「公司行」就抄 Date 的值,否则 NaN
data["text_value"] = np.where(mask, data["Date"], np.nan)
# 0 NaN / … / 3 Hotels / 4 NaN / … / 11 Booking
# 第二步:bfill(backward fill,向后填充)——把每个 NaN 换成「它下面最近的一个非 NaN」
data["text_value"] = data["text_value"].bfill()
# 0 Hotels / 1 Hotels / 2 Hotels / 3 Hotels / 4 Booking / …等等——方向对不对?公司行写在段的后面,所以 0、1、2 行的公司要从第 3 行(Hotels)拿: 「向下看」填自己,正是 bfill 的语义。走一遍:第 3 行 Hotels 是非 NaN,保留;第 2 行 NaN → 看下面,第 3 行是 Hotels → 填 Hotels;第 4 行 NaN → 一路向下找到第 11 行 Booking → 填 Booking。6
细节:bfill 不改原列,只返回新列——所以必须 data["text_value"] = data["text_value"].bfill() 把结果赋回去。
这个「返回新对象而非原地改」是 Pandas 的普遍脾气(第 2.5 节的 astype、2.7 节的 sort_values 同理):
好处是每一步都是纯函数,可以随时回退;坏处是忘了赋回,结果就是白干——
新手在 Pandas 上最常见的「改了没反应」,七成是这个。6
方向再强调一次:公司行写在段的后面,所以要从下面的值往上填(bfill); 如果格式相反(公司名写在段首),就该用 ffill(forward fill,从上面往下填)。 一字之差,方向相反——动手前先确认「信息在段的哪一端」,这是 bfill/ffill 选型的全部依据。6
2.4 删脏行:~掩码
data = data[~mask] # ~ 是逐元素取反:保留「不是公司行」的行~mask 把 True/False 整张翻转;拿布尔序列当索引,True 的行留下。第 3、11 行消失。
书里的诚实时刻:「这段代码我得承认,是我的 AI 工具帮我写的,我自己想不出这个技巧」——
2026 年编程的日常。7
为什么不用 dropna 一步到位? 书里专门讨论了这条捷径:dropna() 会删掉任何含 NaN 的行——
不只是 Hotels/Booking 公司行,还包括第 8 行那种「公司名缺失但其余信息完好」的正常预订。
「这样就一步干了两件事:删掉订房公司行 + 筛掉公司名无效的预订。一般建议一次只做一件事。」
先只删公司行(本章 2.4),「要不要筛掉公司名为空的行」留作独立的、可以单独讨论的决定——
这正是「~mask 删行」存在的原因。8
这个「两步并一步」的诱惑在数据清洗里到处都是:dropna 顺手、query 叠加、assign 连写…… 每一处的代价都一样:出错了不知道是哪一步的错。调试成本 ≈ 步数 × 每步的不确定性; 拆开后每步可单独验证,总成本反而低——和第 15 章测试的「小步红绿」是同一个经济学:可验证的小步,胜过不可验证的大步,无论在代码里还是数据里——这句话写两次都嫌少,所以它出现在两章里,值得出现在你的每一次实操里——从这份酒店数据开始,就来得及——把本章的代码逐行敲一遍,胜过再读三遍——书里每一行都附了输出,正好自查。
删行后注意一个 Pandas 特性:行索引会「粘住」。 看排序后的输出,第一行行号是 166、第二行 118—— 这些是被删行之后的原始编号:DataFrame 删掉行,不会让剩下的行重新从 0 编号。 这不影响运算,但用行号找数据时会踩——记住「行号是标签,不是位置」。9
2.5 类型修正与删列
data["Room number"] = data["Room number"].astype(int) # 浮点 → 整数:4008.0 → 4008
data.drop(columns=["Company"], inplace=True) # 删列;inplace=True 表示改原表astype 转型之所以现在才做,是因为之前 NaN 还在、浮点里塞不下 NaN 之外的整数语义;
脏行删掉后,转型就安全了——顺序本身就在示范「一次一件事」。10
2.5b astype 为什么「现在才安全」
转型这步有个时序讲究:10
删公司行之前:列里有 NaN → 浮点是唯一能装 NaN 的数字类型 → astype(int) 会报错
删公司行之后:NaN 全没了 → 格子全是真整数 → astype(int) 安全这个时序是「一次只做一件事」的副产品:如果当初图省事用 dropna() 一刀切,
转型时机反而说不清(哪些 NaN 是「公司行」、哪些是「真缺公司」全混在一起)。
步骤干净的好处不只是好看——它让每个步骤的前提(这步为什么现在能做)变得可陈述。
可陈述的前提,是别人能接手你的代码的前提。10
2.6 造数据:日期列与价格列
原数据日期全相同,书里造一列「每隔 3 天的日期」让例子活起来(并提醒:别对真实数据做这种随机操作):
data["Date"] = pd.date_range(start="1/1/2022", periods=len(data), freq="3D")
# 2022-01-01 / 2022-01-04 / 2022-01-07 …
data["price"] = 100 + data["Room number"]//100 + data["Date"].dt.month
# 第 0 行:100 + 4008//100(=40) + 1月(=1) = 141走一遍价格公式:100 基础 + 楼层(房号整除 100:4008 → 40)+ 月份—— 整列运算,不用写循环(NumPy 血统的体现)。11
这一行公式是 Pandas 表达力的浓缩:五个运算符号、四列引用,作用在全部 134 行上。 等价的 Python 循环要六行,而且慢;Pandas 这行除了快,还有「整列即单位」的一致性—— 不会出现「第 37 行忘了除 100」的差一行错误,因为运算没有行号。 数据列运算的格言:如果你能写成一列的公式,就不要写成一行的循环。11
书里造日期那句提醒也原样保留:「当然,你不该对真实数据做这种随机操作——这只是为了演示。」 教科书式的诚实:演示操作与生产操作的边界,画给你看。11
2.7 统计与排序
number_of_bookings = data["price"].count() # 134 —— 有效条目数
total_price = data["price"].sum() # 18148
corr = data["price"].corr(data["Date"].dt.month) # 0.104… —— 与月份的相关性
data = data.sort_values(by="price", ascending=False) # 按价格降序书里的解读:「如预期,价格和月份有正相关——因为价格公式里本来就含月份。」 (这是个诚实的「人造相关」:数据是公式造的,相关当然存在——真实的相关分析要先排除这种结构性来源。)12
2.8 排序输出怎么读
书里的最后一张输出表,值得教一下读法:12
Date Person Name Room number text_value price
166 2022-12-12 Licha Attyeo 7002 Hotels 182
118 2022-09-01 Dukey Hansod 7001 Expedia 179
...- 最左的 166、118、33 是原始行号(删行后索引不粘重排,见 §2.4 的说明);
- 降序所以价格从 182 往下走;7002 房 → 楼层 70 → 100+70+12(12 月)= 182,公式对得上账;
- 每行的
text_value(订房公司)和Date都是干净字段——清洗的目标达成了:从「看不出结构」到「每列都能直接统计」。
把公式代入第一行验算:price = 100 + 7002//100 + 12 = 100 + 70 + 12 = 182。✓ 第二行:100 + 7001//100 + 9 = 100 + 70 + 9 = 179。✓ 整列运算的正确性,用两行手算就能抽查出来——这是数据清洗的土办法质检,比任何断言都快。12
2.9 统计三行的读法
number_of_bookings = data["price"].count() # 134
total_price = data["price"].sum() # 18148
corr = data["price"].corr(data["Date"].dt.month) # 0.104…count()数的是非缺失条目——134 就是「有效的预订行数」(公司行已删);sum()是全列求和:18148 除以 134 ≈ 135,与价格区间(111–182)对得上账;corr()是相关性(−1 到 1,0 表示无关):0.104 是弱正相关——书里的解读很诚实: 「如预期有正相关,因为价格公式里本来就含月份」——数据是造的,相关是设计出来的。 真实分析里,这种「结构性相关」是噪音,不是发现;发现相关前,先排除「我的公式造出来的相关」。12
3. 这一章的方法论落点
原书收尾的自白比技术更重要:「这个例子有点人工——我拿了一份随机数据集,把想展示的操作挨个往上套。 现实中你必须反过来:先理解问题,再选择合适的操作去解决它。」13
这一句是全书「需求先于实现」在数据分析里的版本(第 11 章需求工程的回声): Pandas 的函数不用背全,背「问题 → 操作」的映射思路: 筛选问题想掩码、缺值问题想 fill/dropna、类型问题想 astype、汇总问题想 groupby/聚合。
把本章用过的操作按「问题类型」归一下类(这张表是我们对全章操作的归拢,方便日后检索):13
| 你面对的问题 | 本章用过的操作 | 输出的形状 |
|---|---|---|
| 数据从哪读进来 | pd.read_csv(sep=…) | 新 DataFrame |
| 先看清长什么样 | data.head(12) | 打印,不改数据 |
| 找出「符合条件的行」 | 造列条件 → mask = data[列].isna() | 布尔序列(掩码) |
| 按条件筛行 | data[~mask]、data[mask] | 新 DataFrame(行变少) |
| 造新列(按条件取值) | np.where(mask, A, B) | 新列 |
| 缺值按方向填充 | 列.bfill()(注意赋回) | 新列 |
| 删行/删列 | data[~mask] / data.drop(columns=[…]) | 新 DataFrame |
| 改类型 | 列.astype(int) | 新列 |
| 造序列/造派生列 | pd.date_range(...)、列间四则运算 | 新列 |
| 统计一个数 | 列.count() / 列.sum() / 列.corr(另一列) | 单个数 |
| 排序后看前几行 | data.sort_values(by=…, ascending=False) | 新 DataFrame |
这张表覆盖了日常清洗的七八成;更复杂的分组聚合(groupby)与表连接(merge)本章没出现,见边界。
这张表还有一层用法书里没点破:它同时是「搜索关键词表」。 遇到不会的操作,拿「问题」列的词(筛选、缺值、类型、排序……)去搜文档或问 AI, 比描述症状(「我的表乱了」)命中率高得多——「问题 → 操作」的映射,本就是人类语言和库函数之间的翻译表。
3.1 「先理解问题再选操作」的操作版
原书收尾的自白比技术更重要:「这个例子有点人工——我拿了一份随机数据集,把想展示的操作挨个往上套。 现实中你必须反过来:先理解问题,再选择合适的操作去解决它。」13
把这句话落成可执行的三问:
问 1 我要回答什么问题?(比如「哪家订房公司贡献最多收入」)
问 2 回答它需要哪几列、干净到什么程度?(公司列必须无缺失 → bfill 那步是必需的)
问 3 哪些操作是「为了演示」而其实可以不做?(造日期列、造价格列——真实问题里没有这两问)
图说:三问过滤后,17 章的十步操作可能只剩五步;省下的五步不是浪费,是演示税。这道过滤也是区分「教程数据」和「业务数据」的分水岭:教程里每个操作都有展示价值, 业务里每个操作都要有问题价值——操作不是问题驱动的,再熟练也是杂技。
4. 作者的判断与证据
书里给了证据的: 每步操作的中间输出(掩码、bfill 前后的列)都完整打印,可直接对照; 「AI 帮我写」的自白是少见的诚实。67
那句自白也值一句展开:「我必须承认这段代码是拿 AI 工具生成的,这个技巧我自己想不出来」—— 2026 年的编程书里出现这句话,比任何一章都更能说明这本书的「诚实」基调: 作者不装全知,技巧来源照实交代。读者该学的不是「别用 AI」,而是用 AI 之后依然逐行看懂—— 看不懂的代码进不了自己的系统,这条规矩不因生成工具而改变。
作者的判断:
- 「先理解问题,再选操作」——正确且被普遍忽视;
- 「一次只做一件事」(删公司行和筛无效公司不该合并成一步)——流程纪律,与第 05 章字符串原则同构;
- 价格与月份的相关性解读——他点明了这是人造相关,没有过度解读。
判断(我们的,不是书里的): 这份数据的真正病根不在 NaN,而在**「订房公司写在段尾行」这个反常规格式**—— Pandas 技巧(bfill)只是止痛药,根治是让上游按 CSV/JSON 的正常形状给数据(书里也这么批评了原始数据)。 工程上请记住优先级:修上游 > 读时规范化 > 清洗时打补丁。 如果错,会错在: 你控制不了上游(别人的导出、历史遗产)时,「读时规范化」也做不到, bfill 这类补丁就是主战场——所以技巧本身必须会,只是别把它当成数据设计的范本。
另一条判断(我们的): 这一章最值得模仿的不是任何函数,是作者「边洗边打印中间结果」的节奏—— 每步之后
head()一次,肉眼对账。数据清洗的错误模式是「一步写十行、跑完才发现错了十行」; 他的节奏把错误隔离在一步之内。这个节奏与 TDD 的红绿循环是同构的:小步、可见、可回退。 如果错,会错在: 数据大到 head() 看不见代表性问题时(十亿行里的 0.1% 脏数据), 抽样检查会给出虚假安全感;那时要换「分布检查」(每列的取值统计)而不是「眼看几行」。
4.5 本章在全书里的位置
这一章夹在 Matplotlib 和数值数学之间,位置不是随手排的:
16 章:画出数据的形状(单变量直觉)
17 章:把脏数据洗成能算的形状(本章)
18 章:对干净数据做计算(积分、仿真)
图说:科学计算的流水线 = 看见 → 洗净 → 计算;Pandas 是「洗净」环节的默认工具。读完三章连起来,你会拿到科研日常的真正高频组合:read_csv → 清洗 → 画图确认 → 算指标。 原书把这三章排在书的最后三分之一,也是同一个意思:语言课在前,流水线的每个环节各一章在后。
5. 边界与局限
- groupby(分组聚合)——Pandas 最高频的操作——本章完全没有;count/sum/corr 只是单列入门;
merge(表连接)没提;时间序列按周按月重新对齐没提;inplace=True的用法在现代 Pandas 社区已被建议避免(链式写法更安全),书里还在用;- NaN 的处理策略(删掉 vs 填补 vs 保留)只给了「视目标而定」一句话,没有决策框架; 补一个最小框架(书外):看这一列对问题是否关键——关键列缺值就查上游,非关键列缺值才谈填补或丢弃;
- 没有讲「清洗脚本要可重跑」:所有操作从原始文件单向流到结果,中间不落盘改原始数据—— 书里没写,但这是数据清洗的第一纪律(覆盖了原始文件,就没有后悔药);
- 「相关性」一段是演示而非分析:真实分析要先排除结构性来源(书里点到了,未展开)。
5.5 版本时效
书写于 2026 年,Pandas 2.x 时代的语法(read_csv 参数、字符串列的 .str 访问器)
与今天一致;但 Pandas 生态正在分叉——Polars(更快的替代品)2026 年的份额持续上升(书外观察)。
学本章的心智模型(表、列、掩码),两个库通用;具体函数名以你项目里实际用的那个为准。
另外两条书外但关键的工程习惯,与本章直接相关:其一,清洗脚本要可重跑——从原始文件单向流到结果,
中间绝不改原始数据;其二,每一步的删除操作前先数行(len(data) 前后各打一次),
删多了立刻发现。两条都是「不可逆操作」的保险带,书里没写,但补上只需两行代码,省下的可能是半天的事故排查——以及在同事面前重新解释「数据去哪了」的尴尬。
6. 可带走的
本章主线例子,一行写完: read_csv(sep="\t") 读脏表 → isna() 造掩码 →
np.where + bfill 回填公司名 → ~mask 删脏行 → astype(int) 修类型 →
整列运算造价格 → sort_values 排序。3
这一行流水线如果漏背了,记这个最小骨架就够:读 → 看 → 掩码 → 填 → 筛 → 改 → 算 → 排—— 八个字,本章每节各占一个。3
- Pandas = NumPy 上的表格层:DataFrame 是带名字的列;大表也高效。
- 心智模型:先造布尔掩码,再拿它筛/改——别用循环逐行。
head()先看清结构再动手;读入第一眼要诊断的三件事:有没有特殊行、缺什么、类型对不对。- NaN 是缺失的占位符;它会把整列拖成浮点,删空后记得
astype修回来。 - bfill 从下面最近的有效值回填;它返回新列,要赋回去。
- 整列运算是常态:
100 + 列//100 + 列.dt.month不需要循环。 - 一次只做一件事:删公司行和筛公司别合并;
dropna会把两件事混成一步,慎用。8 - 行索引删行后不粘重排——行号是标签不是位置。9
- 统计前先想数据的来历:公式造的数据,相关是人为的。
- 先理解问题再选操作;函数不用背,背「问题 → 操作」的映射。
- 表→列→掩码等长对齐是 Pandas 的地基;对齐不上的操作会直接报错。
- bfill 看信息在段的哪一端;「返回新对象」的脾气意味着:记得赋回去。
- 每步的前提要可陈述(为什么现在能转型),可陈述才可交接。
- 删改前先数行:不可逆操作前
len(data)打两次,两行代码买半天排查时间——这买卖在任何市场都该做,在数据市场尤其该做——数据不会自己报错的,它只会悄悄错给你看——在你最不需要的时候——比如汇报前的那个晚上——所以,白天就把这两行写上,别等晚上。
7. 原文地图
全章操作速查与出处的对照:上面 §2 的每个小节都能在下表找到原文行,读不懂某一节时, 先回原书看那一段,再回来——大多数卡点是因为跳过了原书的一句铺垫——原书不贵,卡点时值得打开;打不开的时候,这张表就是你的临时原书——它把每一节的论证地基都钉在了原文的具体段落上——这张表本身就是「出处纪律」的一次演示:每条论断都能被一枚短语找回,这在这种体量的拆解里并不常见,值得珍惜——尤其是当多年后某个断言需要复核时——能找回出处的断言,才敢继续往上盖楼;找不回的,迟早要拆——拆的时候,别问是谁写的——多半是你自己。
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| Pandas 定位(基于 NumPy) | 12 Pandas | text/28-ch12-12-pandas.txt:4(搜「built on top of NumPy」) |
| 数据集的来历与毛病诊断 | 12 Pandas | text/28-ch12-12-pandas.txt:16(搜「barely readable」) · text/28-ch12-12-pandas.txt:44(搜「hard to understand the data」) |
| read_csv 与 head | 12 Pandas | text/28-ch12-12-pandas.txt:52(搜「read_csv」) · text/28-ch12-12-pandas.txt:53(搜「head(12)」) |
| NaN 与脏行观察 | 12 Pandas | text/28-ch12-12-pandas.txt:46(搜「NaN」) |
| 布尔掩码 | 12 Pandas | text/28-ch12-12-pandas.txt:73(搜「mask」) |
| np.where 造列 | 12 Pandas | text/28-ch12-12-pandas.txt:92(搜「np.where」) |
| bfill 与「要赋回去」 | 12 Pandas | text/28-ch12-12-pandas.txt:110(搜「bfill」) · text/28-ch12-12-pandas.txt:203(搜「in place」) |
| ~mask 删行与「AI 帮我写」 | 12 Pandas | text/28-ch12-12-pandas.txt:162(搜「element wise」) · text/28-ch12-12-pandas.txt:166(搜「AI tool」) |
| astype 修类型 | 12 Pandas | text/28-ch12-12-pandas.txt:184(搜「astype」) |
| drop 列与 inplace | 12 Pandas | text/28-ch12-12-pandas.txt:202(搜「drop」) |
| 造日期与造价格 | 12 Pandas | text/28-ch12-12-pandas.txt:225(搜「date_range」) · text/28-ch12-12-pandas.txt:246(搜「price」) |
| count/sum/corr | 12 Pandas | text/28-ch12-12-pandas.txt:267(搜「number_of_bookings」) · text/28-ch12-12-pandas.txt:273(搜「corr」) |
| 排序 | 12 Pandas | text/28-ch12-12-pandas.txt:280(搜「sort_values」) |
| 「先理解问题」收尾 | 12 Pandas | text/28-ch12-12-pandas.txt:298(搜「opposite approach」) |
Footnotes
-
出处:「12 Pandas」第 3–9 段(
text/28-ch12-12-pandas.txt:4,搜「built on top of NumPy」)。 ↩ -
出处:「12 Pandas」第 51–69 段(
text/28-ch12-12-pandas.txt:57,搜「Room number」——head(12) 的打印输出,行索引列在最左)。 ↩ -
出处:「12 Pandas」第 11–71 段(
text/28-ch12-12-pandas.txt:52,搜「read_csv」;「Hotels/Booking 行」的诊断见第 40–47 段)。 ↩ ↩2 ↩3 ↩4 ↩5 -
出处:「12 Pandas」第 46–47 段(
text/28-ch12-12-pandas.txt:46,搜「filled with a NaN」)。 ↩ -
出处:「12 Pandas」第 72–90 段(
text/28-ch12-12-pandas.txt:76,搜「Boolean mask」)。 ↩ ↩2 -
出处:「12 Pandas」第 90–148 段(
text/28-ch12-12-pandas.txt:92,搜「np.where」;「backward fill」与缩写解释见第 110–111 段;「不改原列」见第 115 段,搜「in place」)。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 -
出处:「12 Pandas」第 160–167 段(
text/28-ch12-12-pandas.txt:163,搜「~mask」;「AI 工具帮我写」见第 166 段,搜「AI tool」)。 ↩ ↩2 -
出处:「12 Pandas」第 150–161 段(
text/28-ch12-12-pandas.txt:155,搜「dropna」;「two things in one step」见第 160 段,搜「only one thing at a time」)。 ↩ ↩2 -
出处:「12 Pandas」排序输出(
text/28-ch12-12-pandas.txt:284,搜「166」——排序后首行行号 166,即原始行号)。 ↩ ↩2 -
出处:「12 Pandas」第 182–204 段(
text/28-ch12-12-pandas.txt:183,搜「float and not int」;drop 见第 203 段,搜「inplace」)。 ↩ ↩2 ↩3 -
出处:「12 Pandas」第 221–262 段(
text/28-ch12-12-pandas.txt:225,搜「date_range」;价格公式见第 246–247 段)。 ↩ ↩2 ↩3 -
出处:「12 Pandas」第 264–295 段(
text/28-ch12-12-pandas.txt:274,搜「corr」;解读见第 277–278 段,搜「relates positively」)。 ↩ ↩2 ↩3 ↩4 -
出处:「12 Pandas」第 296–299 段(
text/28-ch12-12-pandas.txt:298,搜「opposite approach」)。 ↩ ↩2 ↩3