最直接方法是用 dtype 参数指定列类型:dtype={"user_id": str} 或 dtype={0: str};处理含空值的数字列时,必须同时设置 keep_default_na=False 和 na_values=None。

用 dtype 参数指定列类型最直接
read_csv 默认会尝试推断每列数据类型,遇到全数字就转成 int 或 float。要强制某列为 string,必须显式传入 dtype 参数,值为字典:键是列名(或列索引),值是 str 或 object(二者在此场景下等效)。
- 列名存在且稳定时,优先用列名:
dtype={"user_id": str, "code": str} - 列名可能缺失或含空格,可用列索引:
dtype={0: str, 2: str} - 若整张表都需保持原始字符串,直接用
dtype=str(但会关闭类型推断,所有列都变 object) - 注意:如果该列后续有
na_values或keep_default_na=False等设置,空值仍可能被识别为NaN,此时列类型仍是object,但元素混合了str和float(NaN是 float)——这不是你想要的,得配合keep_default_na=False+na_values=None控制
处理含缺失值的数字列转 string 的坑
这是最常踩的坑:一列看起来是“123”、“456”、“”,read_csv 默认把空转成 NaN,而 NaN 是浮点类型,导致即使你写了 dtype={"col": str},最终该列仍是 object 类型,但内部混着 str 和 float(NaN),调用 .str.upper() 会报 AttributeError。
- 正确做法是关掉默认 NaN 解析:
keep_default_na=False - 同时清空自定义空值列表:
na_values=None(否则na_values=[""]这类默认值仍生效) - 完整示例:
pd.read_csv("data.csv", dtype={"id": str}, keep_default_na=False, na_values=None)
列名还没读出来时怎么指定 dtype?
有时 CSV 没有 header,或者 header 行本身含异常字符,你想跳过它再读,但又需要对特定位置的列设类型——这时不能靠列名,只能靠列序号。
- 用
header=None让 pandas 不把第一行当列名,列自动命名为 0, 1, 2… - 再用
dtype={1: str, 3: str}指定第 2 列、第 4 列为 string - 如果还用了
skiprows=1跳过脏 header,注意skiprows在header解析前执行,列序号仍从实际读取的第一行开始计数
为什么不用 converters?
converters 看似灵活(例如 converters={"id": str}),但它是在 dtype 推断之后才执行的,属于“后处理”。这意味着:如果原列被识别为 int,而其中有非法值(如 "123abc"),read_csv 会先报错或转成 NaN,根本走不到 converters;而 dtype 是底层解析阶段控制,能避免类型冲突提前中断。
所以除非你需要做复杂转换(比如去空格+截取),否则别用 converters 强制 string——它不解决根本问题,还掩盖类型推断失败。
真正难的是混合空值和数字字符串的列,那几行配置组合(dtype + keep_default_na=False + na_values=None)缺一不可,少一个都可能让列里悄悄混进 NaN。










