数据分析的第一步永远是把数据读进来。本篇文章系统讲解 pandas 如何读写 CSV、Excel、JSON、SQL、剪贴板等常见格式,以及各种格式下的关键参数和踩坑点。
目录
1. 读写总览
2. 读写 CSV
3. 读写 Excel
4. 读写 JSON
5. 读写 SQL 数据库
6. 其他格式:HTML / 剪贴板 / Pickle / Parquet
7. 编码问题的终极解决方案
8. 大文件读取优化
9. 常见坑与注意事项
10. 本章小结与练习
1. 读写总览
pandas 为常见格式提供了"对称"的读写接口:
| 格式 | 读取函数 | 写出函数 | 说明 |
|------|----------|----------|------|
| CSV | pd.read_csv | df.to_csv | 最常用,纯文本表格 |
| Excel | pd.read_excel | df.to_excel | 需要 openpyxl/xlrd |
| JSON | pd.read_json | df.to_json | 网页/API 常用 |
| SQL | pd.read_sql | df.to_sql | 需要 SQLAlchemy 或连接器 |
| HTML 表格 | pd.read_html | df.to_html | 网页表格抓取 |
| 剪贴板 | pd.read_clipboard | df.to_clipboard | 复制粘贴神器 |
| Pickle | pd.read_pickle | df.to_pickle | pandas 原生序列化 |
| Parquet | pd.read_parquet | df.to_parquet | 列式存储,大数据推荐 |
| Feather | pd.read_feather | df.to_feather | 高速格式 |
读取函数的通用模式:pd.read_格式(文件路径, 参数...),返回 DataFrame。2. 读写 CSV
CSV(逗号分隔值)是最通用的数据交换格式。
2.1 基本读取
import pandas as pd
# 最简单用法
df = pd.read_csv("sales.csv")
# 常用参数组合
df = pd.read_csv(
"sales.csv",
encoding="utf-8", # 文件编码
sep=",", # 分隔符
header=0, # 第 0 行作为列名
index_col=0, # 第 0 列作为行索引
usecols=["日期", "金额"], # 只读取指定列
nrows=1000, # 只读取前 1000 行
skiprows=2, # 跳过前 2 行
dtype={"金额": float}, # 指定列类型
parse_dates=["日期"], # 把列解析为日期
na_values=["", "NA", "null"], # 指定哪些值视为缺失
)
2.2 核心参数详解
| 参数 | 作用 | 示例 |
|------|------|------|
| sep | 分隔符 | sep="\t" 制表符、sep=";" 分号 |
| header | 哪一行作为列名 | header=None 无列名 |
| names | 手动指定列名 | names=["a","b","c"] |
| index_col | 哪一列作为行索引 | index_col="id" 或 index_col=0 |
| usecols | 只读部分列 | usecols=["a","c"] 或 usecols=[0,2] |
| nrows | 读取行数上限 | 大文件先看前几行 |
| skiprows | 跳过开头行 | 跳过注释行 |
| encoding | 文件编码 | "utf-8"、"gbk" |
| dtype | 指定列类型 | dtype={"id": str} |
| parse_dates | 解析日期列 | parse_dates=[0] |
| na_values | 额外缺失值标记 | na_values=["-", "N/A"] |
| thousands | 千分位符号 | thousands="," |
2.3 无表头文件
df = pd.read_csv(
"no_header.csv",
header=None, # 文件没有列名
names=["id", "name", "age"], # 自己指定
)
2.4 写出 CSV
df.to_csv("output.csv", index=False) # 不写行索引(最常用)
df.to_csv("output.csv", index=True) # 写行索引
df.to_csv("output.csv", encoding="utf-8-sig") # Windows Excel 打开不乱码
df.to_csv("output.csv", sep=";") # 自定义分隔符
df.to_csv("output.csv", columns=["a", "b"]) # 只导出部分列
重点坑:在 Windows 上用 Excel 打开utf-8编码的 CSV 会乱码。解决办法:写出时用encoding="utf-8-sig"(带 BOM)。
3. 读写 Excel
前提:需要安装openpyxl(读写 .xlsx)。pip install openpyxl
3.1 读取
# 读取默认工作表
df = pd.read_excel("report.xlsx")
# 读取指定工作表
df = pd.read_excel("report.xlsx", sheet_name="销售数据")
df = pd.read_excel("report.xlsx", sheet_name=0) # 按位置(第 0 个表)
# 读取多个工作表 -> 返回字典 {表名: DataFrame}
sheets = pd.read_excel("report.xlsx", sheet_name=None)
print(sheets.keys())
# 其他常用参数(与 read_csv 类似)
df = pd.read_excel(
"report.xlsx",
sheet_name="销售",
header=0,
index_col=0,
usecols="A:D", # 支持 Excel 列区间写法
skiprows=1,
dtype={"金额": float},
)
3.2 写出
# 写入默认工作表
df.to_excel("output.xlsx", index=False)
# 一个 Excel 文件写多个工作表
with pd.ExcelWriter("多表输出.xlsx") as writer:
df1.to_excel(writer, sheet_name="销售", index=False)
df2.to_excel(writer, sheet_name="库存", index=False)
# 设置工作表起始位置
df.to_excel("output.xlsx", sheet_name="Sheet1", startrow=2, startcol=1)
3.3 查看 Excel 有哪些工作表
# 使用 openpyxl
from openpyxl import load_workbook
wb = load_workbook("report.xlsx")
print(wb.sheetnames) # ['销售', '库存', '人员']
# 或用 pandas 的 ExcelFile
xl = pd.ExcelFile("report.xlsx")
print(xl.sheet_names)
4. 读写 JSON
4.1 读取
# 读取 JSON 文件
df = pd.read_json("data.json")
# 读取 API 返回的 JSON 字符串
import requests
resp = requests.get("").json()
df = pd.DataFrame(resp)
read_json 的 orient 参数控制 JSON 结构:
| orient | JSON 结构 | 说明 |
|--------|-----------|------|
| "records" | [{"a":1,"b":2}, ...] | 列表的字典(最常见) |
| "index" | {"0":{"a":1}, ...} | 字典的字典(外层是行索引) |
| "columns" | {"a":{"0":1}, ...} | 字典的字典(外层是列名) |
| "split" | {"columns":[...],"index":[...],"data":[...]} | 分离式 |
| "table" | {"schema":..., "data":...} | 含 schema |
# records 方向最常用
df = pd.read_json("data.json", orient="records")
4.2 写出
df.to_json("out.json", orient="records", force_ascii=False)
# force_ascii=False 保证中文不以 \uXXXX 转义
df.to_json("out.json", orient="records", lines=True) # JSON Lines 格式(每行一个 JSON)
5. 读写 SQL 数据库
前提:安装 SQLAlchemy 和对应数据库驱动,例如 pip install sqlalchemy pymysql。5.1 建立连接
from sqlalchemy import create_engine
# MySQL
engine = create_engine("mysql+pymysql://用户名:密码@主机:3306/数据库名?charset=utf8mb4")
# PostgreSQL
engine = create_engine("postgresql://用户名:密码@主机:5432/数据库名")
# SQLite(无需密码,最方便练习)
engine = create_engine("sqlite:///mydb.db")
5.2 读取
# 方式一:SQL 查询
df = pd.read_sql("SELECT * FROM orders WHERE status='已支付'", engine)
# 方式二:直接读整张表
df = pd.read_sql_table("orders", engine)
# 方式三:自动生成查询
df = pd.read_sql_query("SELECT 城市, COUNT(*) AS cnt FROM users GROUP BY 城市", engine)
5.3 写入
df.to_sql(
"orders_backup", # 目标表名
engine, # 连接
if_exists="append", # append 追加 / replace 重建 / fail 报错
index=False, # 不写索引
chunksize=10000, # 分批写入,大数据推荐
)
6. 其他格式:HTML / 剪贴板 / Pickle / Parquet
6.1 从网页抓取表格(read_html)
tables = pd.read_html("")
# 返回列表,每个元素是一个 DataFrame(页面里每张表一个)
df = tables[0]
依赖lxml或html5lib:pip install lxml html5lib。
6.2 剪贴板(read_clipboard)
复制 Excel/网页中的表格后,直接粘贴读取:
# 1. 在 Excel 中复制一块区域
# 2. 执行:
df = pd.read_clipboard()
print(df)
这是数据探索阶段最方便的工具,无需保存文件。
6.3 Pickle(pandas 原生序列化)
# 保存(速度快,保留全部类型信息)
df.to_pickle("data.pkl")
# 读取
df = pd.read_pickle("data.pkl")
Pickle 保留索引、dtype、甚至自定义对象,但不跨语言/跨版本安全,仅适合临时缓存。
6.4 Parquet(列式存储,大数据推荐)
df.to_parquet("data.parquet")
df = pd.read_parquet("data.parquet")
需要pyarrow:pip install pyarrow。Parquet 压缩率高、读写快,是大数据场景首选。
7. 编码问题的终极解决方案
中文环境下最常遇到的坑就是编码错误:
# 报错示例
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd6 in position 0
# 解决方案(按优先级尝试)
df = pd.read_csv("f.csv", encoding="utf-8")
df = pd.read_csv("f.csv", encoding="gbk")
df = pd.read_csv("f.csv", encoding="gb18030") # gbk 超集,兼容性最好
df = pd.read_csv("f.csv", encoding="utf-8-sig") # 带 BOM 的 utf-8
df = pd.read_csv("f.csv", encoding="latin1") # 兜底,永远不报错但可能乱码
快速检测编码:
import chardet
with open("f.csv", "rb") as f:
raw = f.read(10000)
print(chardet.detect(raw))
# {'encoding': 'GB2312', 'confidence': 0.99, ...}
小技巧:Windows 下 Excel 另存的 CSV 默认是 GBK/GB2312 编码;记事本另存的可能是 UTF-8。
8. 大文件读取优化
处理几个 GB 的大文件时,用以下技巧:
# 1. 只看结构:只读前 5 行
df_preview = pd.read_csv("big.csv", nrows=5)
# 2. 只读需要的列,指定类型(内存可减少 80%+)
df = pd.read_csv(
"big.csv",
usecols=["id", "日期", "金额"],
dtype={"id": "int32", "金额": "float32"},
parse_dates=["日期"],
)
# 3. 分块处理(chunk 是迭代器)
chunk_iter = pd.read_csv("big.csv", chunksize=100000)
total = 0
for chunk in chunk_iter:
total += chunk["金额"].sum()
print(total)
# 4. 低内存模式
df = pd.read_csv("big.csv", low_memory=False)
9. 常见坑与注意事项
| 坑 | 现象 | 解决办法 |
|----|------|----------|
| 中文乱码 | 读出来全是乱码 | 正确指定 encoding,写出用 utf-8-sig |
| ModuleNotFoundError: openpyxl | 读 Excel 报错 | pip install openpyxl |
| 数字被读成字符串 | id 列显示 '001' 变 1 | dtype={"id": str} 或 converters |
| 日期变成字符串 | 无法做时间运算 | parse_dates=["日期"] |
| 列名前后有空格 | 访问列报 KeyError | 读取后 df.columns = df.columns.str.strip() |
| 表头不在第一行 | 数据错位 | 用 skiprows 或 header |
| index 被当成数据列 | 多出一列 Unnamed: 0 | 读取时 index_col=0 |
10. 本章小结与练习
小结
- CSV/Excel/JSON/SQL 是四大常用格式,接口对称:
read_xxx读、to_xxx写; - 中文编码问题用
encoding="utf-8-sig"写、按需检测读; - 大文件用
nrows预览、usecols裁剪、chunksize分块、指定dtype降内存; read_clipboard是交互探索的神器;- Parquet 是大数据场景的推荐格式。
练习题
1. 创建一个 DataFrame,用 to_csv 分别以 utf-8 和 utf-8-sig 编码导出,用 Excel 打开对比。
2. 用 read_csv 读取一个不含表头的文件,正确指定列名。
3. 用 pd.read_clipboard() 从 Excel 复制一段数据并读取。
4. 将两个 DataFrame 分别写入同一个 Excel 文件的两个工作表。
5. 用 chunksize 分块读取一个大 CSV 并累加某列总和。
下一篇预告:第 5 章 数据查看与探索 —— 拿到数据后如何快速摸清它的全貌。
文章回复
0 条公开回复