pandas read_csv 读编号后前导零消失:按字符串与空值规则导入
read_csv 将编号推断成数值后前导零丢失,应在读取时按列声明字符串,并明确默认缺失词、空编号与 converter 的行为;已损失格式需从原件恢复。
CSV 中的编号是 000042,读入 pandas 后变成整数 42,再用 astype(str) 也只能得到 "42"。前导零在数值推断时已经丢失,事后转换类型不会把原始文本找回来。
客户编号、邮政编码这类字段通常用于识别而非计算。应在读取时按列指定字符串类型,同时确认 NA、空字符串等内容是否是合法编号。下面使用 pandas 2.x 与 3.0 支持的 "string" 类型,示例不覆盖文件写出前就已经被其他软件改动的情况。
在读取边界指定编号列的 dtype
下面的 CSV 字符串只是说明输入格式的小型示例:
from io import StringIO
import pandas as pd
source = StringIO("customer_id,quantity\n000042,3\n001007,8\n")
df = pd.read_csv(source, dtype={"customer_id": "string"})
编号列预期保留 "000042" 与 "001007",数量列仍可按数值读取。应用中用实际文件路径替代 StringIO,并核对表头是否确实叫 customer_id。
dtype=str 可用于把所有列读成字符串,但会同时改变数量、日期等其他字段的处理方式。只有编号需要保留文本时,按列映射更容易维持原来的数据约定。
给原始 CSV 值加引号并不等于声明 pandas 列类型;读取器仍会根据内容推断类型。如果已经配置了该列的 converters,它会替代这列的 dtype 转换,应检查转换函数是否把文本转成了整数,不能以为同时写了 dtype 就一定保留零。
字符串类型仍需明确 NA 的含义
默认读取会将空字符串、NA、NULL 等常见表示识别为缺失值。指定字符串类型不会自动关闭这项识别,因此合法编号恰好是 NA 时,仍可能读成缺失标记。
假设输入约定是:编号 NA 为合法文本,编号为空才表示缺失。可以关闭默认缺失词,并只给这列声明空字符串:
source = StringIO("customer_id,quantity\n000042,3\nNA,8\n,2\n")
df = pd.read_csv(
source,
dtype={"customer_id": "string"},
keep_default_na=False,
na_values={"customer_id": [""]},
)
这个示例中编号 NA 应保留为两个字符,第三条编号应为缺失值。keep_default_na=False 对整次读取生效,其他列若也有空值或特殊缺失词,需要一并在 na_values 中按业务规则列出。不要为了保留一个编号,悄悄改变其他列的空值含义。
如果所有字段都应原样保留这些缺失词,可使用 keep_default_na=False 且不设置 na_values。na_filter=False 则会关闭缺失标记检测,此时 keep_default_na 和 na_values 都会被忽略;它不适合上面“空编号仍要算缺失”的约定。
已经丢掉的零,需要重新读取原件
只有 42 时,无法判断原始编号是 42、042 还是 000042。优先从保留的原始 CSV 重新读取,避免在已经损失格式的表格上反复转换。
只有业务协议明确规定固定宽度,且现有内容已经核验符合编号规则时,补零才能作为格式修复。补成六位不是还原原始数据;它也不能恢复已被浮点处理舍入的长编号,更不能推断缺失值原来是什么。
如果 DataFrame 内部的编号仍正确,只是在电子表格软件打开导出的 CSV 后显示成 42,应检查那次打开时的列类型推断。此时应按文本导入编号列,不能因此修改保存正确的上游字段。
上线前保留输入原件,用带零编号、合法缺失词编号、真正空编号和较长编号核对读取结果,并检查其他列的数据类型与行数。导出先写到新路径,再由实际下游读取确认;不要覆盖唯一的原始文件,否则后续回退无法补回丢失的编号格式。


