Pandas: 数据读写
最后更新:2026-08-26
真实项目中的数据不会凭空出现在代码里——它来自 CSV 文件、Excel 表格、数据库、API 接口。Pandas 提供了 20+ 种 IO 函数,让你一行代码就能加载和保存各种格式的数据。本节覆盖最常用的 4 种格式(CSV / Excel / JSON / SQL),以及编码和大文件处理的实战技巧。
⚠️ 注意: 以下代码需在本地 Python 环境中运行。部分示例使用 StringIO 模拟文件读写。
1. 你将学到
- ❶ read_csv / to_csv 详解
- ❷ read_excel / to_excel 多 Sheet 处理
- ❸ read_json / to_json 格式处理
- ❹ read_sql / to_sql 数据库交互
- ❺ 编码问题与大文件策略(chunksize)
2. Bob 的编码噩梦
(1) 痛点:CSV 打开是乱码
Bob 收到一份客户数据 CSV,用默认参数加载——中文全变乱码:
PYTHON
import pandas as pd
# This fails or produces garbled text
# df = pd.read_csv('customers.csv') # UnicodeDecodeError!
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
原因:文件是 GBK 编码,Pandas 默认用 UTF-8 读取。
(2) 解法:指定 encoding
▶ 示例:编码处理(难度⭐)
PYTHON
import pandas as pd
from io import StringIO
# Simulate GBK-encoded CSV
csv_gbk = "name,age,city\nAlice,28,Beijing\nBob,34,Shanghai"
# In real scenario: pd.read_csv('file.csv', encoding='gbk')
# UTF-8 (default) — works for most modern files
csv_utf8 = "name,age,city\nAlice,28,New York\nBob,34,London"
df = pd.read_csv(StringIO(csv_utf8))
print(df)
# name age city
# 0 Alice 28 New York
# 1 Bob 34 London
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) 收益:IO 函数一行搞定
| 场景 | 一行代码 |
|---|---|
| 读 CSV | pd.read_csv('data.csv') |
| 写 CSV | df.to_csv('out.csv', index=False) |
| 读 Excel | pd.read_excel('data.xlsx') |
| 读 SQL | pd.read_sql('SELECT * FROM t', conn) |
3. CSV 读写
(1) read_csv 常用参数
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:read_csv 参数详解(难度⭐⭐)
PYTHON
import pandas as pd
from io import StringIO
csv_data = """product_id,product_name,price,stock,category
P001,Laptop,999.99,50,Electronics
P002,Phone,699.99,120,Electronics
P003,Tablet,349.99,80,Electronics
P004,Monitor,449.99,35,Electronics
P005,Keyboard,79.99,200,Accessories"""
# Basic read
df = pd.read_csv(StringIO(csv_data))
print(df.columns) # auto-detected from first row
# Key parameters (shown with simulated data)
# pd.read_csv('file.csv',
# encoding='utf-8', # file encoding
# sep=',', # delimiter (default comma)
# header=0, # row number for column names
# index_col='product_id', # column to use as index
# usecols=['product_name', 'price'], # only load these columns
# dtype={'price': float, 'stock': int}, # force types
# na_values=['N/A', 'NULL'], # treat these as NaN
# parse_dates=['order_date'], # parse as datetime
# nrows=1000, # only read first N rows
# chunksize=5000 # iterate in chunks
# )
# Select specific columns (saves memory)
df_selected = pd.read_csv(StringIO(csv_data), usecols=['product_name', 'price'])
print(df_selected)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) to_csv 保存
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:to_csv 保存(难度⭐)
PYTHON
import pandas as pd
from io import StringIO
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [28, 34, 25],
'city': ['New York', 'London', 'Tokyo']
})
# Save to CSV string (simulating file output)
output = StringIO()
df.to_csv(output, index=False) # index=False — don't save row numbers
print(output.getvalue())
# name,age,city
# Alice,28,New York
# Bob,34,London
# Charlie,25,Tokyo
# Real file: df.to_csv('output.csv', index=False, encoding='utf-8')
# Append to existing file
# df.to_csv('output.csv', mode='a', header=False, index=False)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
4. Excel 读写
(1) read_excel 多 Sheet
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:Excel 多 Sheet 读取(难度⭐⭐)
PYTHON
import pandas as pd
from io import BytesIO
# Create a multi-sheet Excel file in memory
buffer = BytesIO()
df1 = pd.DataFrame({'name': ['Alice', 'Bob'], 'score': [85, 92]})
df2 = pd.DataFrame({'product': ['Laptop', 'Phone'], 'price': [999, 699]})
with pd.ExcelWriter(buffer) as writer:
df1.to_excel(writer, sheet_name='Students', index=False)
df2.to_excel(writer, sheet_name='Products', index=False)
buffer.seek(0)
# Read specific sheet
students = pd.read_excel(buffer, sheet_name='Students')
print(students)
# Read all sheets as dict
buffer.seek(0)
all_sheets = pd.read_excel(buffer, sheet_name=None) # dict of DataFrames
print(all_sheets.keys()) # dict_keys(['Students', 'Products'])
# Read by sheet position
buffer.seek(0)
second_sheet = pd.read_excel(buffer, sheet_name=1) # 0-indexed
print(second_sheet)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
💡 提示: read_excel 需要安装额外引擎:
pip install openpyxl(.xlsx)或 pip install xlrd(.xls)。Pandas 2.x 默认使用 openpyxl。
(2) to_excel 保存
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:Excel 保存与格式(难度⭐)
PYTHON
import pandas as pd
from io import BytesIO
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'salary': [75000, 92000, 68000]
})
# Save to single sheet
buffer = BytesIO()
df.to_excel(buffer, sheet_name='Employees', index=False)
# Save multiple DataFrames to different sheets
buffer2 = BytesIO()
with pd.ExcelWriter(buffer2) as writer:
df.to_excel(writer, sheet_name='Employees', index=False)
df.describe().to_excel(writer, sheet_name='Statistics')
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
5. JSON 读写
(1) JSON 格式类型
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:JSON 多格式读写(难度⭐⭐)
PYTHON
import pandas as pd
from io import StringIO
# orient='records' (most common for APIs)
json_records = '[{"name":"Alice","age":28},{"name":"Bob","age":34}]'
df = pd.read_json(StringIO(json_records), orient='records')
print(df)
# name age
# 0 Alice 28
# 1 Bob 34
# orient='columns' (column-oriented)
json_cols = '{"name":{"0":"Alice","1":"Bob"},"age":{"0":28,"1":34}}'
df2 = pd.read_json(StringIO(json_cols), orient='columns')
print(df2)
# orient='index' (row-oriented)
json_idx = '{"0":{"name":"Alice","age":28},"1":{"name":"Bob","age":34}}'
df3 = pd.read_json(StringIO(json_idx), orient='index')
print(df3)
# Write to JSON
output = df.to_json(orient='records', indent=2)
print(output)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) JSON orient 对比
| orient | 结构 | 适用场景 |
|---|---|---|
| records | [{col:val}, ...] |
API 响应(最常用) |
| columns | {col:{idx:val}} |
列优先 |
| index | {idx:{col:val}} |
行优先 |
| split | {index:[], columns:[], data:[[]]} |
完整拆分 |
| values | [[v1,v2], ...] |
纯数据无标签 |
6. SQL 读写
(1) read_sql 数据库查询
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:SQL 数据库交互(难度⭐⭐)
PYTHON
import pandas as pd
import sqlite3
from io import StringIO
# Create in-memory SQLite database (for demo)
conn = sqlite3.connect(':memory:')
# Write data to SQL
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'department': ['Sales', 'Engineering', 'Marketing'],
'salary': [75000, 92000, 68000]
})
df.to_sql('employees', conn, if_exists='replace', index=False)
# Read entire table
df_read = pd.read_sql('SELECT * FROM employees', conn)
print(df_read)
# Read with SQL query
high_salary = pd.read_sql(
'SELECT name, salary FROM employees WHERE salary > 70000',
conn
)
print(high_salary)
# name salary
# 0 Alice 75000
# 1 Bob 92000
# Read with parameters (safe from SQL injection)
dept = 'Engineering'
result = pd.read_sql(
'SELECT * FROM employees WHERE department = ?',
conn,
params=[dept]
)
print(result)
conn.close()
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
💡 提示: read_sql 支持 SQLite / PostgreSQL / MySQL / SQL Server 等所有 Python DB-API 兼容数据库。需要安装对应驱动:
pip install psycopg2(PostgreSQL)、pip install pymysql(MySQL)。
7. 大文件策略
(1) chunksize 分块读取
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:chunksize 大文件处理(难度⭐⭐)
PYTHON
import pandas as pd
from io import StringIO
# Simulate a large CSV
csv_large = "id,value\n" + "\n".join([f"{i},{i*10}" for i in range(100)])
# Read in chunks of 30 rows
chunks = pd.read_csv(StringIO(csv_large), chunksize=30)
total_sum = 0
total_count = 0
for chunk in chunks:
total_sum += chunk['value'].sum()
total_count += len(chunk)
print(f"Total rows: {total_count}")
print(f"Sum of values: {total_sum}")
# Alternative: process and save each chunk
# for i, chunk in enumerate(chunks):
# chunk.to_csv(f'chunk_{i}.csv', index=False)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 只读部分列节省内存
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:选择性列加载(难度⭐)
PYTHON
import pandas as pd
from io import StringIO
csv_data = """id,name,age,salary,department,address,phone
1,Alice,28,75000,Sales,123 Main St,555-0100
2,Bob,34,92000,Engineering,456 Oak Ave,555-0200
3,Charlie,25,68000,Marketing,789 Pine Rd,555-0300"""
# Only load columns you need
df = pd.read_csv(StringIO(csv_data), usecols=['name', 'salary', 'department'])
print(df)
# Also works: usecols=[1, 3, 4] (by position)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) IO 格式对比
| 格式 | 读取 | 写入 | 速度 | 大小 | 适用 |
|---|---|---|---|---|---|
| CSV | read_csv | to_csv | 中 | 中 | 通用交换 |
| Excel | read_excel | to_excel | 慢 | 大 | 业务报表 |
| JSON | read_json | to_json | 慢 | 大 | API / Web |
| SQL | read_sql | to_sql | 慢 | — | 数据库 |
| Parquet | read_parquet | to_parquet | 快 | 小 | 大数据存储 |
| HDF5 | read_hdf | to_hdf | 快 | 小 | 科学数据 |
| Feather | read_feather | to_feather | 最快 | 小 | 临时存储 |
8. 完整示例:数据加载→清洗→多格式导出
(5) ▶ IO 决策树
graph TB
A[数据源] --> B{文件大小?}
B -->|小| C[CSV / Excel / JSON]
B -->|中| D[CSV + chunksize]
B -->|大| E[Parquet / Feather]
A --> F{需要数据库?}
F -->|是| G[read_sql / to_sql]
F -->|否| H{需要 API?}
H -->|是| I[read_json]
H -->|否| J[read_csv]
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:IO 全流程(难度⭐⭐⭐)
PYTHON
import pandas as pd
import sqlite3
from io import StringIO, BytesIO
# ============================================
# Comprehensive example: Full IO pipeline
# Load CSV → Clean → Export CSV/Excel/JSON/SQL
# ============================================
# 1. Load from CSV
csv_data = """name,age,salary,department,hire_date
Alice,28,75000,Sales,2022-03-15
Bob,34,92000,Engineering,2019-08-01
Charlie,25,NaN,Marketing,2023-01-10
Carol,30,88000,Sales,2020-06-20
David,45,105000,Management,2015-11-01"""
df = pd.read_csv(StringIO(csv_data), na_values=['NaN'])
# 2. Clean data
df['salary'] = df['salary'].fillna(df['salary'].median())
df['hire_date'] = pd.to_datetime(df['hire_date'])
print("=== Cleaned Data ===")
print(df)
# 3. Export to CSV
csv_out = StringIO()
df.to_csv(csv_out, index=False)
print(f"\n✅ CSV export: {len(csv_out.getvalue())} characters")
# 4. Export to Excel
excel_out = BytesIO()
with pd.ExcelWriter(excel_out) as writer:
df.to_excel(writer, sheet_name='Employees', index=False)
df.describe().to_excel(writer, sheet_name='Stats')
print(f"✅ Excel export: {len(excel_out.getvalue())} bytes, 2 sheets")
# 5. Export to JSON
json_out = df.to_json(orient='records', indent=2, date_format='iso')
print(f"✅ JSON export: {len(json_out)} characters")
# 6. Export to SQL
conn = sqlite3.connect(':memory:')
df.to_sql('employees', conn, if_exists='replace', index=False)
df_from_sql = pd.read_sql('SELECT * FROM employees', conn)
print(f"✅ SQL round-trip: {len(df_from_sql)} rows")
conn.close()
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
❓ 常见问题
Q CSV 编码错误怎么办?
A 常见编码:UTF-8(现代默认)、GBK/GB2312(中文 Windows)、ISO-8859-1(西欧)。先用
encoding='utf-8' 尝试,失败则用 encoding='gbk'。万能兜底:encoding='latin1'(不会报错但可能乱码)。用 chardet 库可自动检测编码。Q read_excel 需要额外库吗?
A 需要。
.xlsx 文件需 pip install openpyxl,.xls 需 pip install xlrd。Pandas 2.x 默认用 openpyxl 引擎。如果报错 "Missing optional dependency",安装对应库即可。Q JSON 格式有几种?
A 5 种 orient 模式——records(API 最常用)、columns(列优先)、index(行优先)、split(完整拆分)、values(纯数据)。API 交互用 records,Pandas 内部存储用 columns 或 split。
Q chunksize 怎么用?
A
pd.read_csv(path, chunksize=N) 返回 TextFileReader 对象,每次迭代返回 N 行的 DataFrame。适合处理超过内存的大文件——逐块处理、逐块聚合、逐块保存。注意:chunksize 模式不支持随机访问,只能顺序读取。Q 如何只读部分列?
A 用
usecols 参数:pd.read_csv(path, usecols=['col1', 'col3']) 按列名选取,或 usecols=[0, 2, 4] 按位置选取。只读需要的列可大幅节省内存,尤其对宽表(100+ 列但只用 5 列)。Q Parquet 和 CSV 区别?
A Parquet 是列式存储格式,读取速度比 CSV 快 5-50 倍,文件小 50-80%(内置压缩)。但 Parquet 不是纯文本(需
pip install pyarrow),不适合人类直接查看。建议:原始数据用 CSV 交换,处理后的数据用 Parquet 存储。Q to_csv 的 index=False 是什么意思?
A 默认 to_csv 会把 DataFrame 的 Index 作为第一列写入。绝大多数场景你不需要保存默认的 RangeIndex(0,1,2,...),所以用
index=False 省略它。如果你的 Index 是有意义的标签(如日期),可以 index=True 保留。📖 小节
- read_csv 是最常用的 IO 函数,核心参数:encoding / sep / usecols / dtype / parse_dates
- to_csv 保存时 index=False 避免写入无意义的行号
- Excel 读写需 openpyxl,支持多 Sheet 读写(sheet_name 参数)
- JSON 5 种 orient 模式,API 交互用 records
- SQL 读写通过 DB-API 连接,支持参数化查询防注入
- 大文件用 chunksize 分块读取 + usecols 选择性加载
- Parquet/HDF5/Feather 比CSV快5-50倍,适合大数据存储
📝 作业
- 基础题(难度⭐):用 StringIO 模拟 CSV 文件,用 read_csv 加载(指定 dtype 和 usecols),然后 to_csv 保存(index=False)。
- 进阶题(难度⭐⭐):创建 2 个 DataFrame,用 ExcelWriter 写入同一个 Excel 文件的不同 Sheet,再用 read_excel 的 sheet_name=None 读回所有 Sheet。
- 挑战题(难度⭐⭐⭐):模拟一个 1000 行的 CSV(含 NaN 和日期列),完成:read_csv(na_values/parse_dates/dtype)→ 填充缺失值 → to_csv/to_json(to_sql) 三种格式导出 → 用 read_json 读回验证一致性。