Pandas: 数据读写

最后更新:2026-08-26

真实项目中的数据不会凭空出现在代码里——它来自 CSV 文件、Excel 表格、数据库、API 接口。Pandas 提供了 20+ 种 IO 函数,让你一行代码就能加载和保存各种格式的数据。本节覆盖最常用的 4 种格式(CSV / Excel / JSON / SQL),以及编码和大文件处理的实战技巧。

⚠️ 注意: 以下代码需在本地 Python 环境中运行。部分示例使用 StringIO 模拟文件读写。

1. 你将学到


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 决策树

100%
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.xlspip 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 如何只读部分列?
Ausecols 参数: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 保留。

📖 小节


📝 作业

  1. 基础题(难度⭐):用 StringIO 模拟 CSV 文件,用 read_csv 加载(指定 dtype 和 usecols),然后 to_csv 保存(index=False)。
  2. 进阶题(难度⭐⭐):创建 2 个 DataFrame,用 ExcelWriter 写入同一个 Excel 文件的不同 Sheet,再用 read_excel 的 sheet_name=None 读回所有 Sheet。
  3. 挑战题(难度⭐⭐⭐):模拟一个 1000 行的 CSV(含 NaN 和日期列),完成:read_csv(na_values/parse_dates/dtype)→ 填充缺失值 → to_csv/to_json(to_sql) 三种格式导出 → 用 read_json 读回验证一致性。

← 上一课:数据选取 · 下一课:缺失值处理 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏