astype("Int64")可安全处理NaN,因它是pandas自1.0起引入的可空整数类型;而astype(int)底层依赖C int,不支持NaN,遇np.nan/pd.NA必抛ValueError。

直接用 astype("Int64") 替代 astype(int),但必须确保上游已清空非数值干扰、且 pandas 版本 ≥ 1.0(推荐 ≥ 2.0);否则会报错或静默转成 float64。
为什么 astype(int) 在含 NaN 时必然失败
底层 C int 不支持空值,astype(int) 遇到 np.nan、pd.NA 或 None 会立刻抛 ValueError: Cannot convert non-finite values (NA, NaN, INF) to integer。这不是数据质量问题,是类型系统硬限制。
- 常见诱因:读 Excel/CSV 后某列为
object,内容混有空格、"N/A"、"null"字符串,你直接df["col"].astype(int) - 错误认知:“我先
dropna()就能硬转”——但dropna()不影响原列 dtype,且丢失行可能破坏业务逻辑 - 真正安全路径:先归一化字符串 → 转 float64(
pd.to_numeric(..., errors="coerce"))→ 再升格为可空整型
用 pd.to_numeric + astype("Int64") 的实操链
这是最可控的两步法,适用于绝大多数脏数据场景:
- 第一步:清理字符串并转为带 NaN 的 float64
df["age"] = df["age"].astype("string").str.strip().replace({"": pd.NA, "null": pd.NA, "none": pd.NA, "nan": pd.NA})df["age"] = pd.to_numeric(df["age"], errors="coerce") - 第二步:升格为可空整型
df["age"] = df["age"].astype("Int64")(注意引号和大写 I) - 验证:
df["age"].dtype应返回Int64,缺失值显示为<NA>,而非nan - 导出 CSV 时,
<NA>默认写为空字段,行为与原始 NaN 一致
convert_dtypes() 能否替代手动链?
可以,但有条件:它只对已经是 float64 且所有非缺失值能无损转整数的列生效(如 [1.0, 2.0, np.nan, 4.0] → 成功转 Int64;但 [1.5, 2.0, np.nan] → 保持 float64)。
立即学习“Python免费学习笔记(深入)”;
- 优点:一行解决多列,不需预处理字符串
df = df.convert_dtypes(convert_integer=True, convert_boolean=True) - 缺点:对
object列中混杂字符串完全跳过,不报错也不警告;无法处理"1.0"这类字符串数字 - 适用场景:你确认数据源已清洗干净,只是旧版 pandas 自动把整数列存成了 float64+NaN
后续对接 scikit-learn 或 JSON 序列化时的坑
Int64 类型在下游工具链里不是“即插即用”的:
- scikit-learn 所有 estimator 都拒绝
Int64,必须提前填缺或转回float64:X = df[["age"]].fillna(0).astype("float64")或X = df[["age"]].astype("float64")(自动将<NA>转为np.nan) - JSON 序列化时,
<NA>会触发TypeError,需自定义 encoder:json.dumps(obj, default=lambda x: x.item() if hasattr(x, "item") else None) - 内存与性能:
Int64比float64内存高 2–3 倍,算术运算慢约 30–50%,因为每步都要做 NA 分支判断
真正难的不是转换动作本身,而是判断哪一步该停——比如是否值得为保留整数语义而承担额外内存和兼容性成本;很多时候,明确用 float64 并文档化“该列逻辑上为整数”反而更稳健。


















