Pandas 数据读取与写入(IO 操作)详细总结

第四章:数据读取与写入(IO 操作)

🎯 目标:掌握从各种数据源读取数据和保存数据的方法,打通数据流通的任督二脉。


1.1 为什么需要 IO 操作?

1.1.1 数据在哪里?

在现实工作中,数据分散在各个角落:
#mermaid-svg-WRs3NRDVP7ilha2D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WRs3NRDVP7ilha2D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WRs3NRDVP7ilha2D .error-icon{fill:#552222;}#mermaid-svg-WRs3NRDVP7ilha2D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WRs3NRDVP7ilha2D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WRs3NRDVP7ilha2D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WRs3NRDVP7ilha2D .marker.cross{stroke:#333333;}#mermaid-svg-WRs3NRDVP7ilha2D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WRs3NRDVP7ilha2D p{margin:0;}#mermaid-svg-WRs3NRDVP7ilha2D .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WRs3NRDVP7ilha2D .cluster-label text{fill:#333;}#mermaid-svg-WRs3NRDVP7ilha2D .cluster-label span{color:#333;}#mermaid-svg-WRs3NRDVP7ilha2D .cluster-label span p{background-color:transparent;}#mermaid-svg-WRs3NRDVP7ilha2D .label text,#mermaid-svg-WRs3NRDVP7ilha2D span{fill:#333;color:#333;}#mermaid-svg-WRs3NRDVP7ilha2D .node rect,#mermaid-svg-WRs3NRDVP7ilha2D .node circle,#mermaid-svg-WRs3NRDVP7ilha2D .node ellipse,#mermaid-svg-WRs3NRDVP7ilha2D .node polygon,#mermaid-svg-WRs3NRDVP7ilha2D .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WRs3NRDVP7ilha2D .rough-node .label text,#mermaid-svg-WRs3NRDVP7ilha2D .node .label text,#mermaid-svg-WRs3NRDVP7ilha2D .image-shape .label,#mermaid-svg-WRs3NRDVP7ilha2D .icon-shape .label{text-anchor:middle;}#mermaid-svg-WRs3NRDVP7ilha2D .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WRs3NRDVP7ilha2D .rough-node .label,#mermaid-svg-WRs3NRDVP7ilha2D .node .label,#mermaid-svg-WRs3NRDVP7ilha2D .image-shape .label,#mermaid-svg-WRs3NRDVP7ilha2D .icon-shape .label{text-align:center;}#mermaid-svg-WRs3NRDVP7ilha2D .node.clickable{cursor:pointer;}#mermaid-svg-WRs3NRDVP7ilha2D .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WRs3NRDVP7ilha2D .arrowheadPath{fill:#333333;}#mermaid-svg-WRs3NRDVP7ilha2D .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WRs3NRDVP7ilha2D .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WRs3NRDVP7ilha2D .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WRs3NRDVP7ilha2D .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WRs3NRDVP7ilha2D .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WRs3NRDVP7ilha2D .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WRs3NRDVP7ilha2D .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WRs3NRDVP7ilha2D .cluster text{fill:#333;}#mermaid-svg-WRs3NRDVP7ilha2D .cluster span{color:#333;}#mermaid-svg-WRs3NRDVP7ilha2D div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WRs3NRDVP7ilha2D .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WRs3NRDVP7ilha2D rect.text{fill:none;stroke-width:0;}#mermaid-svg-WRs3NRDVP7ilha2D .icon-shape,#mermaid-svg-WRs3NRDVP7ilha2D .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WRs3NRDVP7ilha2D .icon-shape p,#mermaid-svg-WRs3NRDVP7ilha2D .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WRs3NRDVP7ilha2D .icon-shape .label rect,#mermaid-svg-WRs3NRDVP7ilha2D .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WRs3NRDVP7ilha2D .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WRs3NRDVP7ilha2D .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WRs3NRDVP7ilha2D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 你的分析任务
CSV 文件
Excel 表格
数据库
JSON API
Parquet 文件
Pandas DataFrame
分析结果
保存到文件
写入数据库
生成报告

IO 操作 = 数据的"进口"和"出口"


1.2 CSV 文件操作

1.2.1 读取 CSV(read_csv)

CSV(Comma-Separated Values)是最常见的数据格式。

python 复制代码
import pandas as pd

# 🌟 基础读取
df = pd.read_csv('data.csv')

# 🌟 指定编码(处理中文乱码)
df = pd.read_csv('data.csv', encoding='utf-8')      # UTF-8 编码
df = pd.read_csv('data.csv', encoding='gbk')        # 中文 Windows 常用
df = pd.read_csv('data.csv', encoding='gb2312')     # 国标编码

# 🌟 指定分隔符(默认是逗号)
df = pd.read_csv('data.txt', sep='\t')     # Tab 分隔
df = pd.read_csv('data.csv', sep=';')      # 分号分隔
df = pd.read_csv('data.csv', sep='|')      # 竖线分隔

# 🌟 指定列名(如果文件没有表头)
df = pd.read_csv('data.csv', header=None)  # 没有表头
df = pd.read_csv('data.csv', header=None, names=['姓名', '年龄', '城市'])  # 自定义列名

# 🌟 指定索引列
df = pd.read_csv('data.csv', index_col=0)           # 第1列作为索引
df = pd.read_csv('data.csv', index_col='姓名')       # 指定列名作为索引
df = pd.read_csv('data.csv', index_col=['部门', '姓名'])  # 多级索引

# 🌟 只读取部分列
df = pd.read_csv('data.csv', usecols=['姓名', '年龄', '月薪'])
df = pd.read_csv('data.csv', usecols=[0, 2, 4])      # 按位置选择列

# 🌟 只读取前 N 行
df = pd.read_csv('data.csv', nrows=1000)

# 🌟 跳过前 N 行
df = pd.read_csv('data.csv', skiprows=5)

# 🌟 处理大文件(分块读取)
chunk_size = 10000
for chunk in pd.read_csv('big_data.csv', chunksize=chunk_size):
    # 每次处理 10000 行
    print(f"处理 {len(chunk)} 行数据")
    # 在这里进行数据处理...

1.2.2 写入 CSV(to_csv)

python 复制代码
# 🌟 基础写入
df.to_csv('output.csv', index=False)  # 不保存行索引

# 🌟 完整参数
df.to_csv(
    'output.csv',
    index=False,          # 不保存行索引
    encoding='utf-8',     # 编码
    sep=',',              # 分隔符
    na_rep='NULL',        # 缺失值显示为 NULL
    float_format='%.2f',  # 浮点数保留2位小数
    columns=['姓名', '年龄'],  # 只保存指定列
    header=True,          # 保存列名
    mode='w'              # 写入模式('w'覆盖,'a'追加)
)

# 🌟 追加到已有文件
df_new.to_csv('output.csv', mode='a', header=False, index=False)

1.2.3 CSV 最佳实践

python 复制代码
# ✅ 推荐:读取时处理好编码和索引
df = pd.read_csv(
    'data.csv',
    encoding='utf-8',
    index_col='id',
    parse_dates=['日期'],      # 自动解析日期列
    dtype={'类别': 'category'}  # 指定列的数据类型
)

# ✅ 推荐:写入时不保存索引,避免重复列
df.to_csv('output.csv', index=False, encoding='utf-8-sig')  # utf-8-sig 让 Excel 正确识别中文

1.3 Excel 文件操作

1.3.1 读取 Excel(read_excel)

python 复制代码
# 🌟 基础读取(默认读取第一个 Sheet)
df = pd.read_excel('data.xlsx')

# 🌟 读取指定 Sheet
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')      # 按名称
df = pd.read_excel('data.xlsx', sheet_name=0)              # 按位置(从0开始)
df = pd.read_excel('data.xlsx', sheet_name=['Sheet1', 'Sheet2'])  # 读取多个 Sheet

# 🌟 读取所有 Sheet(返回字典)
all_sheets = pd.read_excel('data.xlsx', sheet_name=None)
print(all_sheets.keys())  # dict_keys(['Sheet1', 'Sheet2', 'Sheet3'])
df1 = all_sheets['Sheet1']

# 🌟 指定行作为表头
df = pd.read_excel('data.xlsx', header=0)   # 第1行作为表头(默认)
df = pd.read_excel('data.xlsx', header=1)   # 第2行作为表头
df = pd.read_excel('data.xlsx', header=None)  # 没有表头

# 🌟 跳过行和指定列
df = pd.read_excel('data.xlsx', skiprows=2, usecols='A:C')  # 跳过前2行,只读A-C列
df = pd.read_excel('data.xlsx', usecols=[0, 2, 4])          # 按位置选择列

# 🌟 指定数据类型
df = pd.read_excel('data.xlsx', dtype={'工号': str, '年龄': int})

1.3.2 写入 Excel(to_excel)

python 复制代码
# 🌟 基础写入
df.to_excel('output.xlsx', index=False)

# 🌟 写入指定 Sheet
df.to_excel('output.xlsx', sheet_name='员工数据', index=False)

# 🌟 多个 DataFrame 写入不同 Sheet
with pd.ExcelWriter('output.xlsx') as writer:
    df_employees.to_excel(writer, sheet_name='员工', index=False)
    df_sales.to_excel(writer, sheet_name='销售', index=False)
    df_products.to_excel(writer, sheet_name='产品', index=False)

# 🌟 追加到已有 Excel 文件(需要 openpyxl)
with pd.ExcelWriter('output.xlsx', mode='a', engine='openpyxl') as writer:
    df_new.to_excel(writer, sheet_name='新数据', index=False)

1.3.3 Excel 引擎选择

引擎 读取 写入 特点
openpyxl 支持 .xlsx,功能最全
xlrd 只支持 .xls(旧格式)
xlsxwriter 写入功能强大,支持格式
python 复制代码
# 指定引擎
df = pd.read_excel('data.xlsx', engine='openpyxl')
df.to_excel('output.xlsx', engine='xlsxwriter')

1.4 JSON 文件操作

1.4.1 读取 JSON(read_json)

JSON 是 Web API 最常用的数据格式。

python 复制代码
# 🌟 从文件读取
df = pd.read_json('data.json')

# 🌟 从字符串读取
json_str = '''
[
    {"姓名": "张三", "年龄": 25},
    {"姓名": "李四", "年龄": 30}
]
'''
df = pd.read_json(json_str)

# 🌟 从 API 获取(配合 requests)
import requests
response = requests.get('https://api.example.com/data')
df = pd.read_json(response.text)

# 🌟 指定 orient(JSON 结构)
# orient='records': [{"col1": "a", "col2": "b"}, ...]  最常用
df = pd.read_json('data.json', orient='records')
# orient='index': {"row1": {"col1": "a", ...}, ...}
df = pd.read_json('data.json', orient='index')
# orient='columns': {"col1": {"row1": "a", ...}, ...}
df = pd.read_json('data.json', orient='columns')

1.4.2 写入 JSON(to_json)

python 复制代码
# 🌟 基础写入
df.to_json('output.json')

# 🌟 指定 orient
df.to_json('output.json', orient='records', force_ascii=False)  # force_ascii=False 保证中文正常显示

# 🌟 写入 JSON 字符串
json_str = df.to_json(orient='records', force_ascii=False)
print(json_str)
# [{"姓名":"张三","年龄":25}, {"姓名":"李四","年龄":30}]

1.5 SQL 数据库操作

1.5.1 连接数据库

python 复制代码
from sqlalchemy import create_engine

# 🌟 MySQL
engine = create_engine('mysql+pymysql://用户名:密码@主机:端口/数据库名')

# 🌟 PostgreSQL
engine = create_engine('postgresql://用户名:密码@主机:端口/数据库名')

# 🌟 SQLite(本地文件数据库)
engine = create_engine('sqlite:///mydatabase.db')

# 🌟 SQL Server
engine = create_engine('mssql+pyodbc://用户名:密码@DSN名')

1.5.2 读取 SQL(read_sql)

python 复制代码
# 🌟 读取整个表
df = pd.read_sql('SELECT * FROM employees', engine)

# 🌟 读取指定 SQL
df = pd.read_sql('''
    SELECT 姓名, 部门, 月薪 
    FROM employees 
    WHERE 月薪 > 20000
    ORDER BY 月薪 DESC
''', engine)

# 🌟 使用参数化查询(防止 SQL 注入)
df = pd.read_sql(
    'SELECT * FROM employees WHERE 部门 = %s',
    engine,
    params=('技术',)
)

# 🌟 分块读取大数据
df_iter = pd.read_sql('SELECT * FROM big_table', engine, chunksize=10000)
for chunk in df_iter:
    print(f"处理 {len(chunk)} 行")

1.5.3 写入 SQL(to_sql)

python 复制代码
# 🌟 基础写入(如果表存在会报错)
df.to_sql('employees', engine, index=False)

# 🌟 如果表存在,替换
df.to_sql('employees', engine, index=False, if_exists='replace')

# 🌟 如果表存在,追加
df.to_sql('employees', engine, index=False, if_exists='append')

# 🌟 指定数据类型
df.to_sql(
    'employees',
    engine,
    index=False,
    dtype={
        '姓名': sqlalchemy.types.VARCHAR(50),
        '年龄': sqlalchemy.types.INTEGER(),
        '月薪': sqlalchemy.types.DECIMAL(10, 2)
    }
)

1.6 其他常用格式

1.6.1 Parquet 格式(大数据推荐)

python 复制代码
# 🌟 读取 Parquet
df = pd.read_parquet('data.parquet')

# 🌟 写入 Parquet
df.to_parquet('output.parquet', index=False)

# 🌟 压缩(节省空间)
df.to_parquet('output.parquet', compression='gzip')

💡 Parquet 优势:列式存储,压缩率高,读写速度快,大数据生态标准格式。

1.6.2 HDF5 格式

python 复制代码
# 🌟 读取 HDF5
df = pd.read_hdf('data.h5', key='df')

# 🌟 写入 HDF5
df.to_hdf('output.h5', key='df', mode='w')

# 🌟 追加到 HDF5
df.to_hdf('output.h5', key='df', mode='a')

1.6.3 剪贴板操作

python 复制代码
# 🌟 从剪贴板读取(从 Excel 复制后直接读取)
df = pd.read_clipboard()

# 🌟 写入剪贴板(粘贴到 Excel)
df.to_clipboard(index=False)

1.6.4 格式对比

格式 优点 缺点 适用场景
CSV 通用、可读 慢、占空间、无类型 小数据、交换
Excel 人人会用 慢、大小限制 报告、人工编辑
JSON Web 标准 占空间 API、Web
Parquet 快、压缩、有类型 不可读 大数据存储
HDF5 快、可追加 依赖多 科学计算
SQL 可查询、事务 需要数据库 企业应用

1.7 实战案例:数据导入导出全流程

场景

你需要从多个数据源整合数据,处理后生成报告。

python 复制代码
import pandas as pd
from sqlalchemy import create_engine

# 1. 从 CSV 读取销售数据
sales_df = pd.read_csv('sales_2024.csv', encoding='utf-8', parse_dates=['日期'])
print(f"销售数据:{len(sales_df)} 行")

# 2. 从 Excel 读取产品信息
product_df = pd.read_excel('products.xlsx', sheet_name='产品清单')
print(f"产品数据:{len(product_df)} 行")

# 3. 从数据库读取客户信息
engine = create_engine('sqlite:///crm.db')
customer_df = pd.read_sql('SELECT * FROM customers', engine)
print(f"客户数据:{len(customer_df)} 行")

# 4. 数据合并(后续章节详细讲解)
merged_df = sales_df.merge(product_df, on='产品ID').merge(customer_df, on='客户ID')

# 5. 数据处理
merged_df['销售额'] = merged_df['数量'] * merged_df['单价']
merged_df['月份'] = merged_df['日期'].dt.to_period('M')

# 6. 生成月度汇总报告
monthly_report = merged_df.groupby('月份').agg({
    '销售额': 'sum',
    '数量': 'sum',
    '订单ID': 'count'
}).rename(columns={'订单ID': '订单数'})

# 7. 保存到多个格式
# 保存到 Excel(多个 Sheet)
with pd.ExcelWriter('月度报告.xlsx') as writer:
    monthly_report.to_excel(writer, sheet_name='月度汇总')
    merged_df.to_excel(writer, sheet_name='详细数据', index=False)

# 保存到 CSV
monthly_report.to_csv('月度报告.csv', encoding='utf-8-sig')

# 保存到 Parquet(用于后续分析)
merged_df.to_parquet('销售数据.parquet', index=False)

# 保存到数据库
monthly_report.to_sql('monthly_report', engine, if_exists='replace')

print("✅ 报告生成完成!")

1.8 本章小结

核心要点

CSVread_csv() / to_csv() ------ 最通用,注意编码和分隔符

Excelread_excel() / to_excel() ------ 需要 openpyxl,注意 Sheet 选择

JSONread_json() / to_json() ------ Web 数据标准,注意 orient

SQLread_sql() / to_sql() ------ 需要 SQLAlchemy,注意连接字符串

Parquetread_parquet() / to_parquet() ------ 大数据推荐格式

最佳实践

  • 读取时指定 encoding='utf-8'
  • 写入时设置 index=False
  • 大文件使用 chunksize 分块读取
  • 日期列使用 parse_dates 自动解析
相关推荐
糖果店的幽灵13 小时前
Pandas DataFrame 数据结构详解
数据结构·pandas
SilentSamsara14 小时前
Pandas 工程化:多层索引、分组聚合与窗口函数的进阶用法
开发语言·python·青少年编程·pandas
牵牛花主人15 小时前
【无标题】
python·pandas
糖果店的幽灵16 小时前
时间序列处理
开发语言·python·pandas
一晌小贪欢2 天前
第19节:地理空间分析——使用 Geopandas 绘制热力地图
开发语言·python·数据分析·pandas·数据可视化
星越华夏2 天前
pandas字符串运算列在字母前后添加字符
pandas
wayz112 天前
pandas_ta 库指标分类
pandas·pandas_ta
ranchor6663 天前
groupby.filter() 与 df.query()
pandas
程序大视界4 天前
【Python系列课程】Pandas(六):数据读写——CSV与Excel文件操作
python·excel·pandas