RSS
菜单
全部文章快讯开发科技深度热点

第 4 章 数据读取与写入

内容摘要

数据分析的第一步永远是**把数据读进来**。本篇文章系统讲解 pandas 如何读写 CSV、Excel、JSON、SQL、剪贴板等常见格式,以及各种格式下的关键参数和踩坑点。

数据分析的第一步永远是把数据读进来。本篇文章系统讲解 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 章 数据查看与探索 —— 拿到数据后如何快速摸清它的全貌。
— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《第 4 章 数据读取与写入》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。