Skip to content

7.4 读取与保存数据

课前导读

本节目标

你将学会:用 pandas 读取和保存本地数据文件,理解 CSV、Parquet、路径、编码、覆盖风险和数据版本。

适合基础:已经知道 DataFrame 是一张可计算的行情表,准备把表格保存下来并重复使用。

预计用时:约 34 分钟。

本节边界:只使用手写示例数据,不调用真实外部数据服务,不新增依赖。


知识正文

1. 把数据文件想成“投资资料柜”

如果 DataFrame 是摊在桌面上的行情表,数据文件就是放进资料柜里的档案。

你今天研究一只 A 股,手动整理了四天行情。

如果不保存,关掉 Python 后这张表就像临时草稿一样消失。

如果保存成文件,下次可以重新打开,继续检查、补充或复盘。

投资研究最怕“凭记忆”。

量化研究更怕“今天的数据和昨天的数据不是同一份,却没有记录”。

所以读取与保存数据,不只是技术动作。

它也是研究纪律。

你要知道文件从哪里来,保存在哪里,是否覆盖旧版本,编码是否正确,字段是否仍然一致。

2. CSV:最适合新手理解的表格文本

CSV 可以理解为“用逗号分隔的表格文本”。

它很朴素,很多表格软件都能打开。

一行是一条记录。

逗号把不同字段分开。

例如下面这几行就像一个迷你行情文件。

text
日期,股票代码,开盘价,收盘价,成交量
2026-01-05,600000,10.00,10.20,1200000
2026-01-06,600000,10.20,10.10,980000
2026-01-07,600000,10.10,10.45,1500000

CSV 的好处是直观。

你可以用记事本看,也可以用表格软件看。

CSV 的不足是它不擅长保存复杂数据类型,也没有强制字段说明。

例如股票代码 600000 如果被误当成数字,有些软件可能会把前导零处理掉。

A 股代码里有 000001 这样的代码,因此股票代码通常要当作文本处理。

常见误区

不要因为 CSV 能用 Excel 打开,就默认 Excel 展示的一定等于原始数据。编码、日期和股票代码格式都可能被自动改动。

3. 用 pandas 保存一份 CSV

下面的代码会用手写数据创建 DataFrame,并保存到本地 data\a_share_prices.csv

python
from pathlib import Path

import pandas as pd

data = {
    "日期": ["2026-01-05", "2026-01-06", "2026-01-07"],
    "股票代码": ["600000", "600000", "600000"],
    "开盘价": [10.00, 10.20, 10.10],
    "收盘价": [10.20, 10.10, 10.45],
    "成交量": [1200000, 980000, 1500000],
}

df = pd.DataFrame(data)

csv_path = Path(r"data\a_share_prices.csv")
csv_path.parent.mkdir(exist_ok=True)

df.to_csv(csv_path, index=False, encoding="utf-8-sig")

Path(r"data\a_share_prices.csv") 表示文件路径。

data 是文件夹名。

a_share_prices.csv 是文件名。

mkdir(exist_ok=True) 表示如果 data 文件夹不存在,就创建它;如果已经存在,也不要报错。

index=False 表示不要把 DataFrame 默认行号也写进 CSV。

encoding="utf-8-sig" 有助于某些表格软件正确识别中文列名。

这段代码不需要外部行情接口,因此适合练习。

4. 用 pandas 读取 CSV

保存之后,可以再把它读回来。

python
loaded = pd.read_csv(
    csv_path,
    dtype={"股票代码": "string"},
    encoding="utf-8-sig",
)

print(loaded)
print(loaded.dtypes)

pd.read_csv() 的意思是“从 CSV 文件读取成 DataFrame”。

dtype={"股票代码": "string"} 是告诉 pandas:股票代码不是普通数字,而是文本。

这对 A 股非常重要。

如果把 000001 当成数字,前面的 0 可能不见。

dtypes 可以查看每一列的数据类型。

你可以把它理解为读取后的“开箱验货单”。

5. 路径:数据到底放在哪里

新手常见报错是“文件找不到”。

这通常不是 pandas 不会读,而是路径写错。

路径可以理解为资料柜里的地址。

例如 data\a_share_prices.csv 表示:在当前项目下的 data 文件夹里,找 a_share_prices.csv 这个文件。

如果你在不同目录运行 Python,同一个相对路径可能指向不同位置。

所以学习阶段建议把脚本、数据文件夹和笔记放在同一个项目目录下。

你还可以打印路径,确认自己保存到哪里。

python
print(csv_path.resolve())

resolve() 会显示更完整的本地路径。

看到真实路径后,你就能去文件夹里检查文件是否存在。

6. 编码:为什么中文列名有时会乱码

编码像是文字的“翻译规则”。

同样的中文列名,如果保存和读取时使用的编码不一致,就可能出现乱码。

在中文环境中,你可能遇到两类常见编码。

编码常见场景处理建议
utf-8-sig自己保存的新文件、希望兼容表格软件新手优先使用
gbk一些旧系统或历史导出的中文文件读取失败时再尝试

如果 utf-8-sig 读取报错,可以尝试。

python
loaded_gbk = pd.read_csv(
    csv_path,
    dtype={"股票代码": "string"},
    encoding="gbk",
)

不要机械地到处改编码。

正确做法是记录文件来源和导出方式,再选择匹配的读取参数。

7. 覆盖风险:保存文件会不会把旧数据冲掉

to_csv() 默认会覆盖同名文件。

这件事很危险。

假设你昨天保存了一份 a_share_prices.csv,今天又用同名路径保存。

如果没有备份,昨天那份文件可能被直接替换。

投资研究中,覆盖旧文件会带来两个问题。

第一,你无法确认研究时用的是哪一版数据。

第二,如果数据供应方后来修正了历史数据,你可能不知道结果为何变化。

更稳妥的命名方式,是把日期或版本写进文件名。

python
versioned_path = Path(r"data\a_share_prices_2026-01-08_v1.csv")

df.to_csv(versioned_path, index=False, encoding="utf-8-sig")

文件名不需要花哨,但要让未来的自己看得懂。

比如“哪一天保存”“第几版”“覆盖范围是什么”。

关键心得

量化研究不是只要算得快,更要能回到当时那份数据,解释当时为什么得到那个结果。

8. Parquet:更像“带结构的压缩档案”

Parquet 可以先理解为更适合程序使用的数据文件格式。

如果 CSV 是朴素文本表,Parquet 更像带字段类型信息的压缩档案。

它通常更省空间,读取大数据时也更高效。

但 Parquet 的学习门槛比 CSV 高一点。

在 pandas 中,保存 Parquet 通常会写成这样。

python
parquet_path = Path(r"data\a_share_prices.parquet")

# 如果本地没有安装 pyarrow 或 fastparquet,这一行可能会报错。
# 本课程当前只认识接口,依赖处理放到后续环境整理中。
df.to_parquet(parquet_path, index=False)

读取时通常写成这样。

python
# 同样需要本地 Parquet 引擎支持。
loaded_parquet = pd.read_parquet(parquet_path)

print(loaded_parquet.head())

本节你不需要为了 Parquet 立刻安装新依赖。

你只要先知道:CSV 适合新手理解和小数据交换,Parquet 更适合未来更大的本地数据管理。

9. 数据版本:同一只股票,为什么会有多份文件

同一只股票可能有不同版本的数据。

例如未复权价格、前复权价格、后复权价格。

例如今天下载的文件和下周下载的文件。

例如只包含日线的数据和同时包含成交额、换手率的数据。

这些差异都会影响研究结果。

如果你不记录版本,后面复盘时会非常痛苦。

最小的数据版本记录可以包括四项。

记录项示例为什么重要
保存时间2026-01-08便于回到当时那份数据
股票范围600000 单只样例避免误以为覆盖全市场
字段范围日期、代码、开盘价、收盘价、成交量便于复查计算依据
处理口径手写未复权示例避免和复权数据混用

这张记录表可以写在你的研究笔记里。

等你以后管理更多数据,再学习更规范的元数据管理。

10. A 股案例:路径、代码和编码一起出错会怎样

假设你保存了一份招商银行样例数据,文件名叫 600036.csv

你后来又保存了一份平安银行样例数据,文件名也叫 000001.csv

如果读取时没有把股票代码设为文本,000001 可能在某些环境里被显示成 1

如果中文字段编码错误,“收盘价”可能变成乱码。

如果路径写错,你可能读到旧文件,误以为代码没有更新。

这些问题都不是交易策略本身的问题。

但它们会让研究结果偏离事实。

量化开发的专业性,就体现在这些基础环节不马虎。

11. 一个安全保存流程

mermaid
graph TD
    A["准备 DataFrame"] --> B["检查字段和行数"]
    B --> C["确认保存路径"]
    C --> D["使用带版本的文件名"]
    D --> E["保存 CSV"]
    E --> F["重新读取文件"]
    F --> G["核对行数、字段和股票代码类型"]
    G --> H["在笔记中记录数据版本"]

这个流程看起来比直接 to_csv() 多了几步。

但它能减少很多低级错误。

在真实研究中,低级数据错误往往比复杂模型错误更常见。


交互实验室

练习 1:保存并读回同一份数据

请运行本节的 to_csv()read_csv() 示例。

完成后检查三件事。

第一,项目目录下是否出现了 data\a_share_prices.csv

第二,读回来的行数是否还是 3 行。

第三,股票代码的数据类型是否是文本。

如果三项都正确,说明你完成了最小数据闭环。

练习 2:制造一次编码观察

encoding="utf-8-sig" 改成不写 encoding,再读一次文件。

如果你的环境仍然正常,不代表编码不重要。

它只说明当前环境刚好能识别。

请在笔记中写下:当文件来自不同软件或旧系统时,我需要检查编码。

练习 3:创建一个版本化文件名

把保存路径改成下面这样。

python
safe_path = Path(r"data\a_share_prices_2026-01-08_v2.csv")

df.to_csv(safe_path, index=False, encoding="utf-8-sig")

保存后对比文件夹里的两个 CSV。

请回答:哪个文件名更容易让未来的自己理解数据来源?

练习 4:写一张数据来源卡

请在笔记里写下五行。

数据名称:单只 A 股手写日线样例。

保存路径:你本地的实际路径。

字段范围:日期、股票代码、开盘价、收盘价、成交量。

处理口径:教学用手写数据,不代表真实行情。

注意事项:股票代码按文本读取,保存时避免覆盖旧版本。


核心复盘

知识清单

  • [ ] CSV 是新手最容易理解的表格文本格式,但要注意编码和股票代码格式。
  • [ ] to_csv() 会保存 DataFrame,默认可能覆盖同名文件。
  • [ ] read_csv() 会把 CSV 读回 DataFrame,A 股代码建议按文本读取。
  • [ ] 路径决定文件保存和读取的位置,路径错会导致“读错文件”。
  • [ ] Parquet 更适合后续管理更大数据,但通常需要额外引擎支持。
  • [ ] 数据版本记录能帮助你复现当时的研究结论。

金句总结

会保存数据,不等于会管理数据;能说明数据从哪里来、是哪一版,才是量化研究的起点。

风险提醒

覆盖旧文件、股票代码格式错误、编码乱码和数据版本混乱,都可能让研究结果失真。任何保存和读取动作都应留下可复查记录。

本文档仅供学习交流用途,不构成任何投资建议。股市有风险,入市需谨慎。