首页 / Pandas 入门教程 / 数据格式与类型清洗

Pandas 入门教程

数据格式与类型清洗

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

PandasPandas 入门教程to_numericto_datetimeStringDtype数据清洗

本节目标:把”看着像数字其实是字符串”的列转成正确类型,清理字符串里的空格,并把 object 列迁移到 3.0 的新字符串类型。

先看看类型对不对

从文件读进来的数据,类型经常和想象不一样:数字带着千分位逗号、日期格式五花八门、字符串前后带空格。第一步先体检:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "价格": ["1,200", "2,500", "3,000"],
    "日期": ["2024-01-01", "2024/01/02", "20240103"],
    "城市": [" 北京 ", "上海", "广州 "],
})
print(df.dtypes)

价格是文本(还带逗号),日期是三种格式的字符串,城市带空格。这样的数据没法求和、没法排序、没法按时间分析——清洗的第一步就是把类型修对。

to_numeric:容错转数值

pd.to_numeric 把字符串转成数值。关键参数 errors 有三种取值:

  1. errors=“raise”(默认):遇到转不了的直接抛错
  2. errors=“coerce”:转不了的变成 NaN
  3. errors=“ignore”:转不了就原样返回
s = pd.Series(["1", "2", "NA", "4"])
print(pd.to_numeric(s, errors="coerce"))

“1,200” 这种带千分位逗号的,先去掉逗号再转:

prices = df["价格"].str.replace(",", "", regex=False)
print(pd.to_numeric(prices))

数字字符串还有个隐形坑:前后空格。" 12 " 直接 to_numeric 会转失败,先 strip 再转是标准动作:

s7 = pd.Series(["12", " 34 ", "56 "])
print(pd.to_numeric(s7.str.strip()))
Tip

errors=“coerce” 把脏值变成 NaN 后
,配合 §24 的 isna().sum() 统计脏数据数量——这个数字本身就是一份数据质量报告。

to_datetime:容错转日期

pd.to_datetime 能识别大部分常见日期格式。多种格式混在一列(“2024-01-01”、“2024/01/02”、“20240103”)时,用 format=“mixed” 让它逐条识别:

print(pd.to_datetime(df["日期"], format="mixed"))

转不了的日期用 errors=“coerce” 变成 NaT(日期的缺失值):

s2 = pd.Series(["2024-01-01", "2024-13-45", "2024-02-01"])
print(pd.to_datetime(s2, errors="coerce"))

日期统一后,就能做后续的时间序列分析(§44 起);把日期列设为索引也顺理成章:df.set_index("日期")

字符串去空格

前后空格是字符串列的”隐形杀手”:肉眼看不出来,但 “北京” 和 “北京 ” 会被当成两个不同的值。用 str.strip() 清理:

df["城市"] = df["城市"].str.strip()
print(df["城市"].unique())
Note

str.strip() 去掉首尾空白,str.lstrip() / str.rstrip() 只去一边。str 访问器的完整家族在 §48 讲。

astype:干净数据直接转

列很干净时,astype 一行搞定;有脏值时会报错,这时改用 to_numeric / to_datetime 的 errors=“coerce” 更稳:

s3 = pd.Series(["1", "2", "3"])
print(s3.astype(int))          # 干净,直接转
s4 = pd.Series(["1", "2", "x"])
# print(s4.astype(int))        # 会报错,改用 to_numeric
print(pd.to_numeric(s4, errors="coerce"))

object 列清理流程

object 列是”垃圾桶”,什么都能装:正常字符串、空字符串、None、各种占位符混在一起。清理步骤:

  1. 看这一列到底有哪些值:df["列"].unique() 或 value_counts()
  2. 找出脏值:""、“n/a”、”—”、“unknown”、带空格的值
  3. 统一处理:替换成 NaN 或统一成标准写法
  4. 转成正确的类型
raw = pd.Series(["北京", "", " 上海 ", "n/a", None, "广州"])
print(raw.value_counts(dropna=False))
cleaned = raw.replace({"": np.nan, "n/a": np.nan}).str.strip()
print(cleaned)
print(cleaned.isna().sum())

3.0 的新字符串类型:str

pandas 3.0 起,字符串列默认使用新的 string 类型(StringDtype),dtype 显示为 str,不再是 object(§07 讲过类型体系)。创建和转换很简单:

s5 = pd.Series(["a", "b", None])
print(s5.dtype)          # str
s6 = s5.astype("str")    # 显式转换
print(s6.isna())

str 和 object 的完整对比在 §49 详讲,这里只留迁移要点:3.0 默认字符串列就是 str 类型;astype(“str”) 保留缺失值,不会变成字符串 “nan”(老版本的大坑,已修复)。

Warning

str 类型列赋值非字符串会报错。老代码如果依赖 object 列”什么都能塞”(一列里字符串数字混着),需要先清理成统一类型;确实要保留混合内容的,显式转回 object:df["列"] = df["列"].astype("object")

老项目里已经写成 dtype=“object” 的代码,3.0 下仍能跑,只是享受不到新类型的性能;新代码直接不写 dtype 或写 dtype=“str” 即可。

类型检查与批量转换

几个常用的类型判断函数(§07 也提过):

  • is_numeric_dtype:是不是数值
  • is_datetime64_any_dtype:是不是日期时间
  • is_string_dtype:是不是字符串(str 或 object 都算)

批量把整个表转成更合理的类型,用 convert_dtypes:

df2 = pd.DataFrame({"a": [1, None], "b": ["x", "y"]})
print(df2.convert_dtypes().dtypes)    # a → Int64,b → string

新字符串类型底层优先用 PyArrow 存储,性能更好、内存更省(§04 提过)。清洗完统一复查 df.dtypesdf.isna().sum()——类型对了,后面求和、分组、画图才不会莫名报错。

小结

类型清洗的套路:先 dtypes 体检,再按需转换。容错转换用 to_numeric / to_datetime 的 errors=“coerce”,干净数据用 astype;字符串列清理空格后,迁移到 3.0 默认的 str 类型(完整对比见 §49)。清洗完统一复查 dtypes 和 isna().sum()。