📊 第3章 Pandas 入门
📄 一句话概括

read_excel 一行能读表,但四个参数不弄清楚,读进来的表常常是错的。 nrows 先试读几行,usecols 只留要用的列,index_col 把一列变行标签,sheet_name 挑工作表。 读完先看 shape。列数不对就是参数给错了,这时候往下算全是白算。

📝 本章和前面几章的关系

上一篇是用 read_excel 读了张现成的表,这一篇把它拆开,讲清四个参数各自管什么。 xlsx 由 openpyxl 解析,xls 由 xlrd 解析,本机两个都装好了,两种格式都能读。

一、最小的一行

pd.read_excel("成绩表.xlsx")——路径给了,别的一个不给,得到 10 行 6 列。 它默认读第一张工作表、把第一行当列名、保留所有列、行标签从 0 编号。 四条默认值多数时候都对,所以多数人从来没查过它们。

一旦默认值不对,表不会报错,只会悄悄错。这是最难查的一类错。

二、先读几行试试:nrows

nrows=3 只读前 3 行,shape 立刻变成 (3, 6),读得飞快。

姓名 班级 语文 数学 英语 总分
张伟 一班 88 92 85 265
王芳 一班 92 95 90 277
李娜 一班 75 68 80 223

大文件一律先 nrows=100 试读:列名对不对、值有没有错位、日期是不是变成了数字。 确认无误再读全量。几万行的表读错格式,等半分钟才发现,白等。

三、只留要用的列:usecols

usecols=['姓名', '语文'] 只保留这两列,shape 变成 (10, 2)。 列少内存就小。几十列的表只留五列,占用的内存能降到十分之一。 它也接受列号,写 usecols=[0, 2] 就是第 1 和第 3 列。

用列名比用列号稳:源文件插了一列,列号全错位,列名不受影响。

四、把一列变成行标签:index_col

index_col='姓名' 之后,行标签是姓名,读进来就少一列。

姓名 班级 语文 数学 英语 总分
张伟 一班 88 92 85 265
王芳 一班 92 95 90 277

这一步等价于读完再 set_index,但省一次内存拷贝,大表上差别明显。 代价是这一列从列里消失了。后面要按「姓名」这列算东西,得先 reset_index 换回来。

五、挑工作表:sheet_name

一个 xlsx 可以有多张表。不给 sheet_name,读的是第一张。

写法 读哪张
sheet_name=0 第一张(默认)
sheet_name='成绩' 按表名读
sheet_name=None 读全部,返回字典

本例文件只有一张表,名字叫「成绩」,两种写法结果一样。 读错表是「数不对」的头号原因:表名看着对,翻过去其实是另一张。 sheet_name=None 拿到的是 {表名: DataFrame} 的字典,一次读完整个文件时用它。

六、四个参数一起用

pd.read_excel(路径, sheet_name='成绩', usecols=['姓名','总分'], index_col='姓名')。 一句读完:只要一张表、两列、姓名做标签。读进来 shape 是 (10, 1)。 参数越多越要马上验证:读完全打 shape 和 head(),两秒的事。

七、动手 Demo:read_excel 的几个常用参数

先写一份 xlsx 当素材,再依次用 nrows、usecols、index_col、sheet_name 读四遍。 每次读完打 shape,用形状证明参数起了作用。

import pandas as pd

SRC = "成绩表.xlsx"
print("全量      %s" % (pd.read_excel(SRC).shape,))
print("nrows=3   %s" % (pd.read_excel(SRC, nrows=3).shape,))
print("usecols   %s" % (pd.read_excel(SRC, usecols=["姓名", "语文"]).shape,))
print("index_col %s" % (pd.read_excel(SRC, index_col="姓名").shape,))

one = pd.read_excel(SRC, index_col="姓名")
print("行标签:%s" % list(one.index)[:3])

print("表名:%s" % list(pd.read_excel(SRC, sheet_name=None).keys()))

实跑输出:

--------------------------------------------------------------------
read_excel 的几个常用参数
--------------------------------------------------------------------

  ① 只读前几行,先看看
  --------------------------------------------------------------------
  nrows=3 只读前 3 行,shape 是 (3, 6)。

| 行 | 姓名 | 班级 | 语文 | 数学 | 英语 | 总分 |
|---|---:|---:|---:|---:|---:|---:|
| 0 | 张伟 | 一班 | 88 | 92 | 85 | 265 |
| 1 | 王芳 | 一班 | 92 | 95 | 90 | 277 |
| 2 | 李娜 | 一班 | 75 | 68 | 80 | 223 |

  大文件先 nrows=100 试读,确认列名和格式对了再读全量。
  ! 这个习惯能省很多时间:几万行的表读错格式,等半分钟才发现白读。

  ② 跳过不要的列
  --------------------------------------------------------------------
  usecols 只保留指定的列,读进来 shape 是 (10, 2)。
  列少内存就小。几十列的表只留五列,内存能降到十分之一。
  ! usecols 也接受列号,比如 usecols=[0, 2],但用列名更稳,列顺序变了也不怕。

  ③ 把某一列设成行标签
  --------------------------------------------------------------------
  index_col='姓名' 之后,行标签就是姓名,列少了一列。

| 姓名 | 班级 | 语文 | 数学 | 英语 | 总分 |
|---|---:|---:|---:|---:|---:|
| 张伟 | 一班 | 88 | 92 | 85 | 265 |
| 王芳 | 一班 | 92 | 95 | 90 | 277 |
| 李娜 | 一班 | 75 | 68 | 80 | 223 |

  这一步等价于读完再 set_index,但省一次内存拷贝。
  ! index_col 只能给一个列名。要设多级索引得传列表,那是第 4 章的事。

  ④ 指定工作表
  --------------------------------------------------------------------
  一个 Excel 可以有多张表。sheet_name 不给就读第一张。
  sheet_name=0 读第一张,sheet_name='成绩' 按名字读,sheet_name=None 读全部并返回字典。
  本文件只有一张表,名字叫「成绩」。
  ! 读错了表是最常见的「数据不对」原因之一:表名看着对,其实是另一张。

pd.read_excel(SRC, sheet_name=None) 返回的是字典,键是表名,所以打 keys() 才看得到表名。 shape 是读取成功的唯一证据。读完不看 shape,等于闭着眼往下走。

30 秒实验

  1. 把 nrows 改成 100(比总行数大),看 shape 会不会变成 (100, 6)。
  2. usecols 传列号 [0, 2],和传列名比一比结果是否一样。
  3. 想一想:index_col 设了「姓名」之后,再想按姓名筛行,写法要不要变?

常见误区

  1. 以为 read_excel 只能读 xlsx:xls 也能读,靠 xlrd;旧版 xls 读不了才要转格式。
  2. 不给 sheet_name 就以为读的是「第一张有用的表」:它只认第一张,不管有没有用。
  3. 用列号写 usecols 又随手插列:源文件一改,取到的就是别的列。
  4. 读完不看 shape:列数不对照样往下算,最后结论全错还找不到原因。
自测三问(点开对答案) 1. read_excel 的四个默认行为是什么? —— 读第一张工作表、首行当列名、保留全部列、行标签从 0 编号。 2. 为什么建议 usecols 用列名而不是列号? —— 源文件插删列之后列号会整体错位,列名不受影响;写列名的代码更抗改动。 3. index_col 和读完再 set_index 有什么区别? —— 结果一样,但 index_col 在读的时候就把那列当标签,省一次内存拷贝,大表更明显。

Excel 讲完了,但实际数据一半在 csv 里、一小半在网页上。下一篇把这两种也收进来。

相关笔记