跳到主要内容

数据怎么进到程序里

这一章讲三件事: f.read() 里那个点号到底是什么; 几千张图和它们的标签在程序里该长什么样; 以及从一个压缩包到「训练集 / 验证集」两个清单,中间要走哪四步。 它在全书链条里的位置是第 2 级台阶: 能指挥计算机了,接下来得把数据喂进去。 遇到的生词都在当场解释。

1. 顶层全景

硬盘上:Vehicle_Data.zip ← 300 张车辆图片,压在一个包里

│ ① 解压

一堆文件夹,文件夹名就是类别名(car / truck / …)

│ ② 遍历,从文件夹名提出标签

内存里:一串「文件路径 → 标签」

│ ③ 打乱

同一串,但顺序被彻底搅过

│ ④ 按 9:1 切开

train.txt(270 条) eval.txt(30 条)


后面第 09 章起,每个项目都从这两个文件开始

图说:这四步是全书每一个项目的固定前奏,书自己也是这么说的。
这一章的主走查就是它——第 8 节从头走一遍。

在走这四步之前,要先把三样东西讲清楚:点号是什么(第 2 节)、 内存里那一串该用什么装(第 3—5 节)、怎么把文件里的东西读进内存(第 6 节)。

2. 先解决一个符号:f.read() 里那个点是什么

这一节只有一个概念,但你从下一节开始每一页都会看到它。

先看现象

你会在这本书后面看到大量这种写法:

f.read(5) # 从文件里读 5 个字符
img.convert("L") # 把图片转成灰度
"20230801.jpg".split(".") # 把文件名按点号切开

共同点是:一个东西,一个点,一个命令。 这个写法是什么意思?

做法:Python 里几乎所有东西都是「对象」

书在讲字符串的时候顺手交代了这件事:在 Python 解释器内部, 所有数据类型都是用面向对象方式实现的,封装为一个类; 字符串同样是一个类,有自己的方法,用的时候采用 <a>.<b> 的形式1

翻译成人话:

一个对象 = 一份数据 + 一组只对这份数据有效的操作。 点号左边是那份数据,右边是你对它下的命令。

书还给了这两部分各自的名字2:

部分名字例子
那份数据属性一张图片的宽、高、格式
那些操作方法「把自己转成灰度」「把自己存到磁盘上」
img ──▶ 是一个对象,里面装着:
属性: size = (640, 480) format = "JPEG"
方法: convert() resize() save() show()

img.size ← 取它的一个属性,得到 (640, 480)
img.convert("L")← 让它执行一个方法,得到一张新的灰度图

图说:点号的意思永远是「这个东西的……」。
后面不再解释这个符号。

为什么在这里讲、而不是等到第 05 章: 因为本章和第 04 章通篇都在调方法, 而**「怎么自己写一个类」是另一回事,那个留给第 05 章。** 现在你只需要会别人给你的对象。

3. 一个变量装一个值,为什么不够用

这一节从书自己的开头起手 —— 它的问题设置很好。

先看现象

书一上来给了三个真实问题3:

  1. 给定一组标签 {car, truck, bus, pedestrian, bicycle},统计每类各有多少张;
  2. 给定一段行驶数据,统计其中「加速」状态占多大比例;
  3. 车载摄像头一次采集多张图,要批量分析。

拿第一个来看,有两种写法:

# 写法一:一个标签一个变量
a1 = 0 # car
a2 = 0 # truck
a3 = 0 # bus
a4 = 0 # pedestrian
a5 = 0 # bicycle

# 写法二:一个结构装一组,用序号区分
a = [0, 0, 0, 0, 0] # a[0] 是 car,a[1] 是 truck,……

看起来只是写法差别,其实是能不能扩展的差别:

写法一写法二
五个标签能写能写
一百个标签要敲一百行一行不变
想「每个标签都加一」要敲五句一个循环就完了
标签数量运行时才知道做不到照样能做

书的结论很直白:第二种方案「既可以减少程序中的变量数量,又便于程序循环遍历」4而第 01 章那 16000 张图,只有第二种写法扩得上去。

三类容器,按「数据之间是什么关系」分

Python 把这类「一次装一组」的东西叫组合数据类型,分成三类5:

关系长什么样什么时候用
序列有先后顺序,可以重复[3, 1, 3](3, 1, 3)"313"一批按顺序排开的东西
集合没有顺序,不许重复{3, 1}只关心「有没有」「有哪些不重复的」
映射一个键配一个值{"001.jpg": 0.5}「按名字查东西」

记住这张表的判据:先问「这组数据之间是什么关系」,再选容器。

4. 序列:列表、元组、字符串

列表:最常用的那个

列表用方括号写,里面什么都能放,而且随时可以增删改6。 它是这本书后面装数据集的默认选择。

ls = ["car", "truck", "bus"]
ls[0] # "car" —— 正着数,从 0 开始
ls[-1] # "bus" —— 倒着数,从 -1 开始
ls[0:2] # ["car", "truck"] —— 切一段出来,右边那个位置不包括在内
ls.append("bicycle") # 尾部加一个

正反两套编号是序列类型共有的:正向从 0 递增,反向从 −1 递减7

一个最容易踩的坑:lt = ls 不产生新列表

这个坑值得单独立一段,因为它不报错、只是安静地算错。

ls = [1, 2, 3]
lt = ls # 看起来是「复制一份」
ls[0] = 0 # 只改了 ls
print(lt) # 却打印出 [0, 2, 3] —— lt 也变了

书讲得很清楚:这句赋值并没有真的生成一个新列表, 只是让 lt指向了 ls 里那份数据,相当于生成了一个引用8

赋值前 lt = ls 之后
ls ──▶ [1,2,3] ls ──┐
├──▶ [1,2,3] ← 只有一份数据,两个名字
lt ──┘

图说:改任何一个名字下的数据,另一个都跟着变——因为本来就是同一份。
真要复制一份,得用 ls.copy() 或者 ls[:]。

这个坑第 05 章还会以另一副面孔出现: 把列表传给一个函数,函数里改了它, 外面那个也会跟着变 —— 根子是同一件事。

元组:一旦造好就不许改

元组用圆括号写,造好之后里面的元素不能替换、不能删除9

它有一个反直觉的细节:只有一个元素时必须多写一个逗号 —— 写 (3) 得到的是数字 3,因为圆括号本身是个运算符;要写 (3,) 才是元组10

书还澄清了一件事:所谓「只读」指的是里面的元素不可改, 元组本身可以被拼接、可以被整个替换掉11

字符串:也是序列,而且中文算一个字

字符串是一串字符,同样支持正反索引(索引 = 按位置取出其中一个)和切片。切片还能带步长: s[N:M:K],如果 K 是负数就从后往前取12

一个很实用的例子 —— 从文件名里切出编号:

name = "20230801_0137.jpg"
name[9:13] # "0137" —— 第 9 到第 12 个字符
name.split("_")[1].split(".")[0] # "0137" —— 另一种写法,更稳

中文怎么算: Python 的字符串按 Unicode 存储 —— 那是一套给世界上所有文字 (汉字、字母、假名、符号)统一编号的标准; 中英文字符都算 1 个字符13。所以 len("智能车") 是 3,不是 9。 (记住这句,第 6 节那个走查会用它来制造一个惊讶。)

5. 集合与字典

集合:去重和「有没有」

集合用大括号写,无序、不许重复。书给了它的三大用途: 成员关系测试(在不在里面)、元素去重、删除数据项14

四则运算和数学里的定义完全一样:交 &、并 |、差 -、补 ^15

在这本书里,集合最实在的用处是去重: 采数据的时候同一张图可能被录进去两次, 把文件名列表转成集合就都清掉了。

字典:这本书真正要用的那个

字典是「一个键配一个值」,而且是 Python 唯一的内建映射类型; 键必须是不可变类型(数字、字符串、元组都行,列表不行),值可以是任何东西16

d = {"001.jpg": 0.5, "002.jpg": -0.3}
d["001.jpg"] # 0.5 —— 用键去查值
d["003.jpg"] = 0.0 # 直接添一个新的
"004.jpg" in d # False —— 判断键在不在

主走查那对数据,在这里第一次有了形状

第 01 章说过,全书就围着「一张图 + 一个转角」转。现在它在程序里长这样:

control = {"001.jpg": 0.5,
"002.jpg": -0.3,
"003.jpg": 0.0}

书自己给的实例比这还多一层:同一张图可能被录入多次, 所以值不是一个数,而是一个列表,取的时候求平均17

录入三次: setControl("001.jpg", 0.48)
setControl("001.jpg", 0.52)
setControl("001.jpg", 0.50)


字典里: {"001.jpg": [0.48, 0.52, 0.50]}

│ getControl("001.jpg") —— 取出来求平均

结果: 0.50

图说:这三个数是为演示编的,书只给了做法没给数值。
为什么要录几次求平均——因为人手遥控本来就抖,单次读数不可靠。

这是全书主走查那对数据第一次有了「程序里的形状」。 第 6 节它会被存到文件里,第 13 章它会变成训练数据。

一处书内错误,照实指出

原书第 5 章讲一个画词云的库怎么安装,整段命令写的却是上一节那个分词库 (分词 = 把一句中文切成一个个词)的名字 —— 安装命令、验证导入,全都写错了对象18。这是从上一节复制粘贴没改。

这类错误无害但很显眼,是这本书缺一轮统稿的信号之一。 (词云和分词这两节与主线无关,我们整体不采用,这里只是照实指出。)

6. 从硬盘到内存:文件怎么读

这一节是本章的第一个承重点。

文本文件和二进制文件,分野只在「怎么解释这堆字节」

书说了一句很要紧的话:从本质上讲,所有的文件都是以二进制形式存储的19。 分成两类只是因为解释方式不同:

靠什么解释例子
文本文件字符编码 —— 每几个字节代表一个字符.txt.py.csv
二进制文件值编码 —— 每几个字节代表什么,由格式自己规定.png.jpg.avi

书举的例子很具体:Windows 的 BMP 图片文件,开头 2 个字节记「我是 BMP」, 接着 8 个字节记文件长度,再 4 个字节记文件头长度20

还有一条要记住:文件的格式和扩展名没有必然联系。.txt 改成 .bin,文件一个字节都没变;用二进制方式打开它,只会看到乱码 —— 因为解码方式和编码方式对不上21

打开 — 操作 — 关闭

Python 对文件的操作固定这三步22。打开之后你拿到的是一个对象 (还记得第 2 节那个点号吗),后面所有操作都通过它:

f = open("test_file.txt", "r", encoding="utf-8") # 打开,"r" 表示只读
content = f.read() # 操作
f.close() # 关闭

嵌一个小走查:读 5 个中文字,指针停在 15

这是全书讲得最漂亮的一个小实验,书是现成给的,我们只是把它讲透。

文件 test_file.txt 里写着六个字:全国大学生智能汽车竞赛(共 11 个字)。

① f.read(5) → 打印出「全国大学生」
✅ 符合预期

② f.read() → 打印出「智能汽车竞赛」
⚠️ 咦?「全国大学生」没了

③ f.tell() → 返回 15
⚠️ 再咦?明明才读了 5 个字

第 ② 步的解释:文件对象里有一个会移动的指针。 刚打开时它指在第 0 个字符处;f.read(5) 读走五个字之后,指针停在了第 5 个字符处; 再 f.read() 只能读到指针后面的东西23

第 ③ 步的解释:指针的单位是字节,不是字符。 在 UTF-8 编码下,一个中文字占 3 个字节,所以 5 个中文字 = 15 个字节24

字符视角: 全 国 大 学 生 │ 智 能 汽 车 竞 赛
↑ ↑
第 0 个字符 第 5 个字符 ← read(5) 之后指针在这

字节视角: ███ ███ ███ ███ ███│
↑ ↑
第 0 字节 第 15 字节 ← tell() 返回的是这个数

图说:同一个位置,按字符数是 5,按字节数是 15。
这就是「中文比英文更容易在文件处理上出错」的根源。

要把指针挪回去用 seek() 但有个限制:文本模式下只能从文件开头算偏移量, 从当前位置或文件末尾算会直接报错25

读整个文件的三种方法,和一条内存红线

方法给你什么内存
f.read()整个文件,一个字符串全部装进内存
f.readlines()整个文件,一行一个元素的列表全部装进内存
for line in f:一次一行只留当前这一行

书专门为第三种写法立了一条口径:「分行读入,逐行处理」。 理由很实在:前两种是把整个文件一次性读进内存,文件一大就吃掉大量内存; 用 for 循环则每次只保留一行,下一次迭代(迭代 = 循环的下一圈)时, 上一次的内容就被销毁了26

这是全书唯一一处讲内存代价的地方,而它后面很要紧: 第 01 章那个线上赛数据集有 16000 张图的清单; 到第 09 章要把数据「封装成批」送进模型时,靠的就是同一个道理 —— 一次只搬一小撮,不要把整座仓库搬进屋里。

7. 数据在文件里怎么摆:三种维度,三种格式

这一节回答:内存里那些结构,存到文件里该长什么样。

书先给了一个通用的框子:任何数据都有同一个周期 —— 存储、表示、操作27。 「存储」是它在磁盘上什么样,「表示」是它在程序里什么样, 而所谓「处理数据」,大部分时候就是在这两者之间来回搬。

一维:一行,用分隔符隔开

空格分隔: 80 0 50 90 0.5 0.5 0.5
逗号分隔: 80,0,50,90,0.5,0.5,0.5
特殊符号: 80$0$50$90$0.5$0.5$0.5

「分隔符」就是上面那个用来把数据隔开的符号(空格、逗号、$ 都是)。 书给了三条口径,每一条都是从坑里爬出来的28:

  1. 同一组文件用同一种分隔符(不然解析代码要写两份);
  2. 分隔符不能出现在数据里(城市名里有逗号,就不能用逗号分隔);
  3. 用英文符号(中文逗号和英文逗号长得像,但是两个不同的字符)。

有顺序的一维数据用列表装,没顺序的用集合装29

二维:表格,用 CSV

CSV 是国际通用的表格文件格式:纯文本,一行一条记录,字段之间用英文逗号分隔30。 在程序里用「列表里装列表」表示,索引的顺序是 先行后列:ls[row][column]31

书里有一个很漂亮的例子,值得单独说 —— 它讲的其实是「接口」这个思想。

书写了一个画赛道的程序,数据放在一个 CSV 文件里,一行七个数32:

80,0,50,90,0.5,0.5,0.5
─┬ ─┬ ─┬ ─┬ ──────┬─────
│ │ │ │ └── 画笔颜色的三个分量(0—1 的小数)
│ │ │ └────────── 弧的角度(缺了就画整圆)
│ │ └───────────── 弧的半径
│ └──────────────── 画弧方向:1 顺时针,0 逆时针
└─────────────────── 先直行多远

图说:一行 = 一段路。程序循环读每一行,照着画。

关键在于:换一个数据文件就画出另一条赛道,一行代码都不用改。 书把这一步叫「定义数据文件格式(接口)」。

这件事值得从这本书里单独带走(判断,我们的,不是书里的): 「把变化的部分挪到数据文件里,让代码只负责解释」 —— 这是整个第 12 章调参数的思想源头(阈值调好之后手抄进配置文件), 也是第 16 章那五个配置文件的思想源头。书没有把这三处连起来,但它们是同一件事。 如果错,会错在: 如果那五个配置文件其实是框架强加的形式、而不是主动的接口设计, 那这条连线就是我们读出来的、不是作者写下的。判据是:那些配置项改起来是不是真的不用碰代码。

三维及以上:统一用键值对,这个格式叫 JSON

书的处理很干脆:二维是一维的集合、三维是二维的集合,层层嵌套下去会没法读; 所以三维及以上统一采用键-值对的形式表示33

这种格式叫 JSON。 书给的定位是:一种轻量级的数据交换格式, 用完全独立于编程语言的文本来存储数据,人能读、机器也好解析34。 它长得和 Python 的字典几乎一样:

{
"001.jpg": 0.5,
"002.jpg": -0.3,
"003.jpg": 0.0
}

这不是随便举的例子。 书里那个 JSON 实例的内容, 就是这场比赛自动巡航模块数据集的一部分:键是图片编号,值是转向角度35。 第 13 章真正训练时用的数据,就是这个格式。

Python 处理它用一个同名的库,四个方法,两两成对36:

方向对字符串对文件
Python 对象 → JSONdumps()dump()
JSON → Python 对象loads()load()

两个参数要记住: indent 控制缩进(让人读得清), ensure_ascii=False 才能正常输出中文,否则中文会变成一串转义码37

表格还有另一条路:让一个库替你读

上面那种「自己 split(",")」的写法在数据量小的时候够用。 数据一多,就该换成专门做这件事的库 —— 它叫 pandas。

它的定位书讲得很实在:根据一线研发人员的经验, 「数据预处理可以说是机器学习中最耗费时间的环节」; 而多数团队并不研究全新模型,时间大都花在处理甚至清洗数据上38

import pandas as pd
df = pd.read_csv("Data_middlepoint.csv") # 一句话读成一张带列名的表
df.head() # 看前几行
df["x"].mean() # 直接对某一列求平均

它和第 04 章要讲的那种数组的分工,书也说清楚了39:

数组(第 04 章讲)pandas 的表
装什么必须同一种类型的数,任意维每列一种类型即可,只管一维和二维
怎么找只能按数字位置还能按列名找
干什么用数值计算、矩阵(一张按行列排开的数表)运算读写、清洗、分析、画图一条龙

8. 主走查:从一个压缩包到两个清单

这是本章的落点。书自己说:「解压缩文件是大数据分析、机器学习的第一步。」

输入

Vehicle_Data.zip —— 书说这是从真实项目数据里摘出来的 300 个样本40

四步,每步带具体结果

① 解压
用 zipfile 库把包打开
结果:得到三个文件夹,名字就是类别名
Vehicle_Data/car/ Vehicle_Data/truck/ Vehicle_Data/bus/

② 遍历目录,从文件夹名提标签
用 os 库列出每个文件夹里的文件
结果:一个列表,300 条,每条是「路径 + 标签」
["Vehicle_Data/car/001.jpg 0",
"Vehicle_Data/car/002.jpg 0",
...
"Vehicle_Data/bus/100.jpg 2"]
⚠️ 注意这时候的顺序:同类的全挤在一起

③ 乱序
random.shuffle(列表)
结果:同一批 300 条,顺序被彻底打散
["Vehicle_Data/bus/067.jpg 2",
"Vehicle_Data/car/013.jpg 0",
"Vehicle_Data/truck/088.jpg 1", ...]

④ 按 9:1 切开
前 90% 写进 train.txt,后 10% 写进 eval.txt
结果:train.txt 270 条 eval.txt 30 条

图说:三个类别名和文件名是我们为演示编的(书只说数据集有 300 个样本、
文件夹名里带标签值);300 和 9:1 这两个数是书给的。

示范代码(我们写的,不是书里的):

import os, zipfile, random

zipfile.ZipFile("Vehicle_Data.zip").extractall("data/") # ① 解压

items = [] # ② 提标签
labels = {"car": 0, "truck": 1, "bus": 2}
for folder, label in labels.items():
for name in os.listdir("data/Vehicle_Data/" + folder):
items.append("data/Vehicle_Data/{}/{} {}".format(folder, name, label))

random.seed(42) # ③ 乱序
random.shuffle(items) # (定了种子,下次跑还是这个顺序)

cut = int(len(items) * 0.9) # ④ 切开
with open("train.txt", "w") as f:
f.write("\n".join(items[:cut]))
with open("eval.txt", "w") as f:
f.write("\n".join(items[cut:]))

第 ③ 步为什么不能省 —— 这是本章最要紧的一句

书给的理由只有一句,但这一句解释了全部: 解压出来的数据排列大都很规律,相同类型的数据基本依次排列; 不打乱,训练出的模型泛化能力(泛化能力 = 模型在没见过的数据上还能不能答对)就会变差41

学得好不好,不看它在做过的题上的分数,看它在新题上的分数。

把不乱序的后果想具体一点:

不乱序,模型看到的顺序是:
车 车 车 车 车 …(100 张)… 卡车 卡车 卡车 …(100 张)… 巴士 巴士 …

它前 100 步在被反复告知「答车」,于是把内部的数往「答车」调;
接下来 100 步全是卡车,它又把数往「答卡车」调,把刚才学的推翻;
最后 100 步再推翻一次。

图说:这不是「学得慢」,是「学到的东西被后面的数据来回覆盖」。

第 ④ 步:切出来的那一份是干什么的

  • 训练集(这里 270 条):模型拿它来调自己内部那些数;
  • 验证集(这里 30 条):模型训练时不许看,专门用来考它。

书给的比例是验证集占总数的 10%~20%,实例里取 10%42

为什么要留一份不给它看: 因为「在做过的题上得高分」不说明任何问题。 第 09 章评估模型时会回到这里,第 13 章会看到一个更狠的例子 —— 验证集上分数更高的模型,实车跑起来反而更差。

9. 作者的判断与证据

说法是哪一类
lt = ls 只产生引用、不复制数据有证据: 语言事实,书给了可复现的例子
UTF-8 下中文占 3 字节、tell() 返回 15有证据: 编码事实,书给了完整走查
「分行读入、逐行处理」更省内存有证据,而且是书里唯一一处讲内存代价的地方
「数据预处理是机器学习中最耗费时间的环节」作者转述一线经验,没给数据来源。方向可信,当成经验判断而不是统计结论
「多数团队不研究全新模型,而是用现有经典模型」同上,作者的行业观察。这句话其实解释了这本书的整个定位
验证集占 10%~20%行业惯例,书没说依据。这类比例本来就没有权威版本
「不乱序会让泛化能力变差」有证据(机制上说得通),但书没做对照实验。 我们把机制补全了

10. 边界与局限

  • 这一章合并了原书三处: 第 2 章的数字与字符串、第 5 章的组合数据类型、 第 6 章前半的文件与数据格式化。三处讲的是同一件事:把外面的数据变成程序里的结构。
  • 「对象 = 数据 + 方法」这一小块,我们从原书第 4 章前移到了这里。 原书要到第 4 章才讲这个写法,而第 5、6 章通篇都在用它 —— 顺序是倒的。 「怎么自己写一个类」仍然留在第 05 章。
  • pandas 我们从原书第 7 章前移到了这里,只讲「读表格」这一个用途。 它剩下的能力(清洗、分析、画图)与本书主线无关。
  • API 清单整体不采用: 列表 / 集合 / 字典各自几十个方法、字符串 43 种方法、 格式化输出的 6 个控制标记 —— 这些在原书里就是图片,而且属于「查文档就有」。
  • 词云与中文分词两节整体不采用。 与主线无关,是通用 Python 教材的标配内容。
  • 书没有讲这四步之外的数据质量问题。 比如重复图、糊掉的图怎么办 —— 那要到第 16 章才第一次出现(「手动筛选剔除非常模糊的图片」)。

11. 可带走的

全章主走查一行写完: Vehicle_Data.zip(300 个样本)→ 解压出三个以类别命名的文件夹 → 遍历目录、从文件夹名提出标签,得到 300 条「路径 + 标签」→ 打乱 → 按 9:1 切成 train.txt(270 条)和 eval.txt(30 条)。 类别名和文件名是为演示编的;300 和 9:1 是书给的。

  1. 对象.方法() 里那个点号的意思永远是「这个东西的……」 —— 点号左边是一份数据,右边是对它下的命令;
  2. 一个变量装一个值扩展不了,要用容器;三类容器按数据之间的关系选: 有顺序的用序列、要去重的用集合、按名字查的用字典;
  3. lt = ls 不复制数据,只是多一个名字 —— 改一个另一个跟着变;
  4. 字典是这本书装「图片名 → 转角」的那个容器,同一张图录多次就把值存成列表再取平均;
  5. 所有文件本质上都是二进制,分文本和二进制只是解释方式不同;改扩展名不改变格式;
  6. 文件对象里有一个会移动的指针,而它的单位是字节不是字符 —— 读 5 个中文字之后,tell() 返回 15;
  7. 大文件必须「分行读入、逐行处理」,read()readlines() 会把整个文件搬进内存;
  8. 一维用分隔符、二维用 CSV、三维以上统一用键值对(JSON); 这本书的巡航数据集就是 JSON,键是图片编号、值是转角;
  9. 把变化的部分挪进数据文件,代码就不用改 —— 这是「定义接口」,后面两章都在用它;
  10. 切数据集之前必须打乱,因为解压出来的数据同类挤在一起; 定一个随机种子,打乱之后还能复现。

12. 原文地图

主题原书章原文位置
所有数据类型都是类,用 <a>.<b> 调方法第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:283(搜「面向对象方式实现」)
类、方法、实例变量的名词定义第4章 函数和类text/05-ch04.txt:181(搜「用来描述具有相同属性和方法」)
三个引子问题;两种方案对比第5章 组合数据类型text/06-ch05.txt:15(搜「统计数据集中每一类标签的数量」) · text/06-ch05.txt:21(搜「便于程序循环遍历」)
组合数据类型三分法第5章 组合数据类型text/06-ch05.txt:23(搜「序列类型、集合类型和映射类型」)
列表创建与操作;lt=ls 只是引用第5章 组合数据类型text/06-ch05.txt:67(搜「列表没有长度限制」) · text/06-ch05.txt:77(搜「生成了一个引用」)
元组只读;单元素必须带逗号第5章 组合数据类型text/06-ch05.txt:57(搜「一定要加上逗号」) · text/06-ch05.txt:59(搜「只读」)
集合的三大用途;四则运算第5章 组合数据类型text/06-ch05.txt:165(搜「成员关系测试」) · text/06-ch05.txt:139(搜「交集」)
字典是唯一的内建映射类型;键必须不可变第5章 组合数据类型text/06-ch05.txt:177(搜「唯一的内建映射类型」)
巡航字典:同一图片多次录入取平均第5章 组合数据类型text/06-ch05.txt:231(搜「求多次输入转向角的平均值」) · text/06-ch05.txt:235(搜「值采用列表形式」)
词云安装命令写成了分词库(书内错误)第5章 组合数据类型text/06-ch05.txt:279(搜「测试jieba库是否安装成功」)
浮点精度第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:175(搜「0.30000000000000004」) · text/03-ch02-2-python.txt:183(搜「15个数字」)
字符串正反索引、切片、步长;Unicode 计数第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:253(搜「正向和反向两种索引体系」) · text/03-ch02-2-python.txt:267(搜「从后往前截取」) · text/03-ch02-2-python.txt:279(搜「都算作1个字符」)
文本 vs 二进制;所有文件都是二进制;扩展名无关第6章 文件和数据格式化text/07-ch06.txt:23(搜「所有的文件都是以二进制形式」) · text/07-ch06.txt:17(搜「改变扩展名不会改变文件的格式」) · text/07-ch06.txt:21(搜「BMP」)
打开—操作—关闭;open 的模式第6章 文件和数据格式化text/07-ch06.txt:45(搜「打开—操作—关闭」) · text/07-ch06.txt:49(搜「open()方法打开文件」)
句柄指针走查:read(5) → tell() 返回 15第6章 文件和数据格式化text/07-ch06.txt:73(搜「句柄指针」) · text/07-ch06.txt:77(搜「3个字节」)
seek 在文本模式下的限制第6章 文件和数据格式化text/07-ch06.txt:83(搜「nonzero end-relative seeks」)
分行读入、逐行处理第6章 文件和数据格式化text/07-ch06.txt:109(搜「一次性读取所有内容」) · text/07-ch06.txt:113(搜「上一次读取到的内容就会被销毁」)
赛道自动绘制:一行七个数、定义数据文件格式(接口)第6章 文件和数据格式化text/07-ch06.txt:167(搜「画弧线方向」) · text/07-ch06.txt:173(搜「定义数据文件格式」)
数据的通用周期:存储—表示—操作第6章 文件和数据格式化text/07-ch06.txt:231(搜「存储—表示—操作」)
一维数据三种分隔法与三条口径第6章 文件和数据格式化text/07-ch06.txt:237(搜「空格分隔」) · text/07-ch06.txt:263(搜「同种分隔符号」)
二维数据与 CSV;先行后列第6章 文件和数据格式化text/07-ch06.txt:285(搜「每一行对应表格中的一条数据记录」) · text/07-ch06.txt:287(搜「先行后列」)
高维统一用键值对;JSON 的定位与四个方法第6章 文件和数据格式化text/07-ch06.txt:313(搜「统一采用键-值对」) · text/07-ch06.txt:315(搜「轻量级的数据交换格式」) · text/07-ch06.txt:333(搜「json.dumps」)
JSON 实例就是巡航数据集第6章 文件和数据格式化text/07-ch06.txt:341(搜「智能车转向角度」)
数据集处理四步:解压、提标签、乱序、切分第6章 文件和数据格式化text/07-ch06.txt:223(搜「解压缩文件是大数据分析」)
pandas 的定位与它和数组的分工第7章 Python计算生态及机器学习概述text/08-ch07-7-python.txt:225(搜「最耗费时间的环节」) · text/08-ch07-7-python.txt:229(搜「标签索引」) · text/08-ch07-7-python.txt:253(搜「read_csv」)

Footnotes

  1. 出处:「第2章 Python基本语法元素及数据类型」第 283 段(text/03-ch02-2-python.txt:283,搜「面向对象方式实现」)。原文:「在 Python 解释器内部,所有数据类型都是用面向对象方式实现的,封装为一个类。字符串同样是一个类,具有类方法,类方法使用时采用 <a>.<b> 的形式处理字符串。」这句话原书出现在讲字符串方法的地方,我们把它提到本章开头当作总纲用。

  2. 出处:「第4章 函数和类」第 181—197 段(text/05-ch04.txt:181,搜「用来描述具有相同属性和方法」)。原文给出类、方法、实例变量、对象等一组名词定义。「怎么自己写一个类」我们留在第 05 章讲,这里只用「属性 / 方法」这两个名字。

  3. 出处:「第5章 组合数据类型」第 15—19 段(text/06-ch05.txt:15,搜「统计数据集中每一类标签的数量」)。

  4. 出处:「第5章 组合数据类型」第 21 段(text/06-ch05.txt:21,搜「便于程序循环遍历」)。

  5. 出处:「第5章 组合数据类型」第 23—31 段(text/06-ch05.txt:23,搜「序列类型、集合类型和映射类型」)。

  6. 出处:「第5章 组合数据类型」第 67 段(text/06-ch05.txt:67,搜「列表没有长度限制」)。原文的建议是:「当程序需要使用组合数据类型管理批量数据时,请尽量使用列表类型。」

  7. 出处:「第5章 组合数据类型」第 47 段(text/06-ch05.txt:47,搜「正向递增序号和反向递减序号」);字符串那一侧见「第2章 Python基本语法元素及数据类型」第 253 段(text/03-ch02-2-python.txt:253,搜「正向和反向两种索引体系」)。

  8. 出处:「第5章 组合数据类型」第 77 段(text/06-ch05.txt:77,搜「生成了一个引用」)。原文给的复现步骤就是:lt=ls 之后修改 ls[0]=0,查看 lt 会发现 lt[0] 也变成了 0。

  9. 出处:「第5章 组合数据类型」第 41 段(text/06-ch05.txt:41,搜「不可变序列」)。

  10. 出处:「第5章 组合数据类型」第 57 段(text/06-ch05.txt:57,搜「一定要加上逗号」)。原文的理由是:圆括号本身是一个运算符,不加逗号会直接返回括号内的内容。

  11. 出处:「第5章 组合数据类型」第 59 段(text/06-ch05.txt:59,搜「只读」)。原文:「『只读』是指其中元素不可被删除或者更改,而不是元组本身不可更改。」

  12. 出处:「第2章 Python基本语法元素及数据类型」第 265—267 段(text/03-ch02-2-python.txt:267,搜「从后往前截取」)。

  13. 出处:「第2章 Python基本语法元素及数据类型」第 279 段(text/03-ch02-2-python.txt:279,搜「都算作1个字符」)与第 273 段(text/03-ch02-2-python.txt:273,搜「Unicode编码」)。

  14. 出处:「第5章 组合数据类型」第 165 段(text/06-ch05.txt:165,搜「成员关系测试」)。

  15. 出处:「第5章 组合数据类型」第 139 段(text/06-ch05.txt:139,搜「交集」)。

  16. 出处:「第5章 组合数据类型」第 177 段(text/06-ch05.txt:177,搜「唯一的内建映射类型」)。原文还说明:每个键只能对应一个值,不允许同一个键在字典中重复出现。

  17. 出处:「第5章 组合数据类型」第 231 段(text/06-ch05.txt:231,搜「求多次输入转向角的平均值」)与第 235 段(text/06-ch05.txt:235,搜「值采用列表形式」)。原文用两个方法分别负责录入和取出:录入时把每次的转角都追加进列表,取出时求平均。走查里的三个数值(0.48 / 0.52 / 0.50)是我们为演示编的,书只给了做法。

  18. 出处:「第5章 组合数据类型」第 279 段(text/06-ch05.txt:279,搜「测试jieba库是否安装成功」)。这一段的标题讲的是词云库的安装,正文的命令和验证导入却全部写成了上一节那个中文分词库的名字。正确的安装命令应当是 pip install wordcloud

  19. 出处:「第6章 文件和数据格式化」第 23 段(text/07-ch06.txt:23,搜「所有的文件都是以二进制形式」)。

  20. 出处:「第6章 文件和数据格式化」第 21 段(text/07-ch06.txt:21,搜「BMP」)。

  21. 出处:「第6章 文件和数据格式化」第 17 段(text/07-ch06.txt:17,搜「改变扩展名不会改变文件的格式」)。原文补充:改完之后用二进制软件打开会出现乱码,「这是因为解码方式与编码方式不匹配」。

  22. 出处:「第6章 文件和数据格式化」第 45 段(text/07-ch06.txt:45,搜「打开—操作—关闭」)与第 49 段(text/07-ch06.txt:49,搜「open()方法打开文件」)。

  23. 出处:「第6章 文件和数据格式化」第 73 段(text/07-ch06.txt:73,搜「句柄指针」)。原文完整给出了这个实验:文件内容是「全国大学生智能汽车竞赛」,f.read(5) 读到「全国大学生」,再 f.read() 只输出「智能汽车竞赛」。

  24. 出处:「第6章 文件和数据格式化」第 77 段(text/07-ch06.txt:77,搜「3个字节」)。原文:「当前指针位置并不是 5,而是 15。这是因为在 UTF-8 编码模式下,每一个中文字符都由 3 个字节的二进制内容构成。」

  25. 出处:「第6章 文件和数据格式化」第 83 段(text/07-ch06.txt:83,搜「nonzero end-relative seeks」)。

  26. 出处:「第6章 文件和数据格式化」第 109 段(text/07-ch06.txt:109,搜「一次性读取所有内容」)与第 113 段(text/07-ch06.txt:113,搜「上一次读取到的内容就会被销毁」)。

  27. 出处:「第6章 文件和数据格式化」第 231 段(text/07-ch06.txt:231,搜「存储—表示—操作」)。

  28. 出处:「第6章 文件和数据格式化」第 261—267 段(text/07-ch06.txt:263,搜「同种分隔符号」)。

  29. 出处:「第6章 文件和数据格式化」第 269 段(text/07-ch06.txt:269,搜「有序一维数据」)。

  30. 出处:「第6章 文件和数据格式化」第 285 段(text/07-ch06.txt:285,搜「每一行对应表格中的一条数据记录」)。原文还提醒:CSV 里的逗号是英文半角,逗号与数据之间没有额外空格,元素缺失时逗号仍要保留。

  31. 出处:「第6章 文件和数据格式化」第 287 段(text/07-ch06.txt:287,搜「先行后列」)。

  32. 出处:「第6章 文件和数据格式化」第 167 段(text/07-ch06.txt:167,搜「画弧线方向」)与第 173 段(text/07-ch06.txt:173,搜「定义数据文件格式」)。原文的目标写得很明确:「不改变代码,仅通过改变 csv 文件数据来绘制不同图形。」

  33. 出处:「第6章 文件和数据格式化」第 313 段(text/07-ch06.txt:313,搜「统一采用键-值对」)。

  34. 出处:「第6章 文件和数据格式化」第 315 段(text/07-ch06.txt:315,搜「轻量级的数据交换格式」)。

  35. 出处:「第6章 文件和数据格式化」第 341 段(text/07-ch06.txt:341,搜「智能车转向角度」)。原文:那个字典的内容就是本赛项自动巡航模块数据集的一部分,键为图片编号,对应值为图片对应的智能车转向角度。

  36. 出处:「第6章 文件和数据格式化」第 333 段(text/07-ch06.txt:333,搜「json.dumps」)。

  37. 出处:「第6章 文件和数据格式化」第 339 段(text/07-ch06.txt:339,搜「indent参数」)。

  38. 出处:「第7章 Python计算生态及机器学习概述」第 225 段(text/08-ch07-7-python.txt:225,搜「最耗费时间的环节」)。原文同段还说:「多数研发团队不会投入太多精力从事全新机器学习模型的研究,而是针对具体的项目和特定的数据,使用现有的经典模型进行分析。」

  39. 出处:「第7章 Python计算生态及机器学习概述」第 229 段(text/08-ch07-7-python.txt:229,搜「标签索引」)与第 231 段(text/08-ch07-7-python.txt:231,搜「数据处理与分析」)。读 CSV 的接口见第 253 段(text/08-ch07-7-python.txt:253,搜「read_csv」)。这一小块原书放在第 7 章,我们前移到本章,因为它讲的正是「把文件里的表格变成程序里的结构」。

  40. 出处:「第6章 文件和数据格式化」第 223 段(text/07-ch06.txt:223,搜「300个样本」)。

  41. 出处:「第6章 文件和数据格式化」第 223 段(text/07-ch06.txt:223,搜「相同类型的数据基本依次排列」)。「泛化能力」的正式定义见「第7章 Python计算生态及机器学习概述」第 331 段(text/08-ch07-7-python.txt:331,搜「泛化能力」):「使得学到的函数能够很好地适用于新样本,而非仅仅只是在训练样本上面表现良好。」

  42. 出处:「第6章 文件和数据格式化」第 223 段(text/07-ch06.txt:223,搜「10%~20%」)。原文的实例取 10% 作验证集、90% 作训练集。