首页 / Pandas 入门教程 / CSV 文件读写

Pandas 入门教程

CSV 文件读写

本教程共 54 篇 · 第 11 篇 · 更新于 2026-08-11 · 约 8 分钟阅读

PandasPandas 入门教程read_csvto_csvCSV 读写数据导入导出

本节目标:掌握 read_csv 和 to_csv 的常用参数,能独立完成”读取 CSV → 处理 → 写回 CSV”的完整流程,包括编码和压缩文件等进阶场景。

CSV:最通用的表格文本格式

CSV(Comma-Separated Values,逗号分隔值)用纯文本存储表格:每行一条记录,字段之间用逗号隔开。打开任意一个 CSV 文件,你会看到:

姓名,年龄,城市
张三,25,北京
李四,30,上海

第一行是表头,后面每行是一条数据。它简单、通用,Excel 能打开,数据库能导出,各种编程语言都能处理,是数据交换的事实标准。

pandas 读写 CSV 就两个函数:读用 pd.read_csv(),写用 df.to_csv()

第一次读取:read_csv

import pandas as pd

df = pd.read_csv("数据.csv")
print(df)

一行代码,CSV 就变成了 DataFrame。pandas 会自动完成三件事:

  • 推断分隔符(默认逗号)
  • 把第一行当作列名(表头)
  • 为数据生成默认的 RangeIndex

想验证读取结果,用 df.head() 看前几行,或 df.info() 看列名、行数、dtype 总览。

Note

pandas 3.0 读取字符串列时,dtype 显示为 str 而不是 object——新字符串类型已是默认(§07 讲过)。这不影响使用,但你可能注意到输出和旧教程不一样。

分隔符 sep:不只是逗号

CSV 的分隔符不一定是逗号。Windows 导出的中文数据常用制表符,欧洲数据常用分号。用 sep 指定:

df = pd.read_csv("数据.tsv", sep="\t")     # 制表符分隔
df = pd.read_csv("数据.txt", sep=";")       # 分号分隔

sep 不传时,pandas 默认按逗号解析;遇到其他分隔符会解析出错或变成一列,这时显式指定 sep 就好。delimitersep 的别名,效果一样。

为了下面的例子不依赖真实文件,我们用 StringIO 把字符串伪装成文件:

from io import StringIO

csv_data = """姓名,年龄,城市
张三,25,北京
李四,30,上海
"""
df = pd.read_csv(StringIO(csv_data))
print(df)
Tip

想快速预览”到底用哪个分隔符”,可以用 sep=None 让 pandas 自动嗅探(sniff)——注意只有 engine="python" 才支持。不过自动检测有时不准,正式代码还是显式指定最稳。

表头 header 与列名 names

默认第一行是表头。如果文件没有表头,传 header=None,pandas 会生成 0、1、2 这样的默认列名:

csv_data = """张三,25,北京
李四,30,上海
"""
df = pd.read_csv(StringIO(csv_data), header=None)
print(df.columns)   # Index([0, 1, 2], dtype='int64')

想让列名更可读,用 names 指定:

df = pd.read_csv(StringIO(csv_data), header=None,
                 names=["姓名", "年龄", "城市"])
print(df)

还可以用 header=0 显式声明”第一行是表头”(默认行为),配合 names 可以覆盖文件里的原始列名:

df = pd.read_csv(StringIO(csv_data2), header=0,
                 names=["name", "age", "city"])

索引列 index_col

默认情况下,CSV 没有索引列,读进来是 RangeIndex。如果文件第一列本身是 ID,可以用 index_col 把它设为行索引:

csv_data = """编号,姓名,分数
S001,张三,85
S002,李四,92
"""
df = pd.read_csv(StringIO(csv_data), index_col=0)
print(df)

输出里”编号”变成了索引名,不再是一列数据。

有个特殊值 index_col=False:当文件每行末尾多了一个分隔符(比如 张三,25,北京,),pandas 可能误把第一列当索引。传 False 可以强制不做推断,直接生成 RangeIndex。

缺失值标记 na_values

CSV 里表示”没有数据”的方式五花八门:空字符串、NANULLN/ANaN……pandas 默认认识一大串常见标记(空串、NANULLNaNN/A 等),会自动转成 NaN

数据源用了别的标记,用 na_values 补充:

csv_data = """姓名,分数
张三,85
李四,缺考
"""
df = pd.read_csv(StringIO(csv_data), na_values=["缺考", "未统计"])
print(df)

“缺考”和”未统计”会被当作缺失值。默认标记仍然生效,na_values追加

想彻底重来,用 keep_default_na=False 关掉默认标记,只认你指定的:

df = pd.read_csv(StringIO(csv_data), keep_default_na=False,
                 na_values=["缺考"])
Warning

读取解析阶段,空字符串默认也算缺失值。如果你的数据里空串有实际含义(比如表示”无”),记得用 keep_default_na=False 调整,否则读进来全是 NaN。(注意这仅指 read_csv 解析阶段;数据读进内存后 "" 本身不是缺失值,见 §25。)

其他高频参数

再记几个常用的,都放在一个例子里:

df = pd.read_csv("数据.csv",
                 usecols=["姓名", "分数"],   # 只读这两列
                 dtype={"分数": "float64"},  # 强制列类型
                 skiprows=1,                 # 跳过前 1 行
                 nrows=100,                  # 只读前 100 行
                 encoding="utf-8")           # 指定编码

逐个说明:

  • usecols:只读指定列,省内存、省时间
  • dtype:字典指定每列类型,避免自动推断出错(比如”001”被读成 1)
  • skiprows:跳过开头若干行(文件前面有说明文字时很管用)
  • nrows:大数据先读几行看看结构
  • encoding:中文文件经常是 gbk 编码,乱码时试试 encoding="gbk"

日期列可以配 parse_datespd.read_csv("数据.csv", parse_dates=["日期"]) 会自动把日期列转成 datetime64 类型。数字里的千分位逗号(1,234)可以用 thousands="," 处理。

编码:中文乱码怎么办

CSV 文件本身不记录编码信息。Windows 上 Excel 导出的中文 CSV 常用 gbk 编码,直接按默认的 utf-8 读,轻则乱码,重则直接报 UnicodeDecodeError

df = pd.read_csv("中文数据.csv", encoding="gbk")

拿不准编码时,可以加 errors="replace" 兜底——解析不了的字符替换成占位符,程序至少不崩:

df = pd.read_csv("中文数据.csv", encoding="gbk", errors="replace")

写文件同理:to_csv(encoding="utf-8") 写出的文件,用 Excel 双击打开可能乱码(Excel 默认按 gbk 猜)。要么写入时用 gbk,要么在 Excel 里用”数据 → 从文本/CSV”导入并手动选 utf-8。

直接读 URL 和压缩文件

read_csv 的路径参数很宽容:支持 http(s) 链接,也支持压缩文件,压缩格式按扩展名自动识别(.gz.bz2.zip.xz),不用手动解压:

df = pd.read_csv("https://example.com/data.csv")   # 远程 URL
df = pd.read_csv("data.csv.gz")                    # gzip 压缩
df = pd.read_csv("data.zip")                       # zip 压缩

读远程文件要注意网络可能慢、可能失败,高频访问的接口建议先下载到本地缓存。压缩文件的好处是省磁盘、省流量,读取速度反而更快(解压是 C 级别的,很快)。

写出:to_csv

to_csv 的用法和 read_csv 对称:

df.to_csv("输出.csv")                     # 基本写法
df.to_csv("输出.csv", index=False)        # 不写行索引(最常见)

index=False 是你最该记住的参数。 默认情况下,to_csv 会把行索引也写进去,生成一个多余的 index 列。绝大多数场景你都不想要它。

再看一组参数:

df.to_csv("输出.csv",
          index=False,            # 不写索引
          columns=["姓名", "分数"],  # 只写这两列
          sep=";",                # 分号分隔
          na_rep="缺失",           # 缺失值写成"缺失"
          encoding="utf-8",       # 编码
          float_format="%.2f")    # 浮点数保留两位
  • columns:只导出指定列
  • na_rep:NaN 在文件里的表示,默认空串
  • float_format:控制浮点数的格式
  • mode="a":追加模式,把数据接到文件末尾(默认是 w 覆盖)

写完再读回来验证,是养成习惯的好方法:

df2 = pd.read_csv("输出.csv")
print(df2.head())

小结

  • read_csv 读文件,to_csv 写文件,两者参数一一对应
  • 分隔符用 sep:逗号、制表符、分号都能处理
  • 表头用 header 控制,自定义列名用 names
  • 索引列用 index_colindex_col=False 对付畸形文件
  • 缺失标记用 na_values 追加、keep_default_na=False 重置
  • usecolsdtypeskiprowsnrowsencoding 是高频搭配
  • 中文乱码先试 encoding="gbk";URL 和压缩文件直接读
  • 写文件记得 index=False,多半你不需要索引列

下一节读 Excel 文件,参数和 CSV 大同小异,但多了一个”sheet”的概念。