Pandas 依托 NumPy,但扩展了一套自己的数据类型体系。很多莫名的 NaN、类型报错、内存占用高、分组异常、join对齐问题,根源都是数据类型。本文系统梳理原生numpy类型、Pandas扩展类型、分类类型、时间类型、字符串类型、类型转换、类型推断、类型检查、常见坑,延续整套教程风格。
前置导入
import pandas as pd
import numpy as np
一、核心概念
dtype:Series / DataFrame 每一列的数据类型- 旧版 Pandas 底层大量复用 NumPy 类型;Pandas 1.0+ 推出扩展数据类型(ExtensionDtype),专门解决 NumPy 原生类型不支持空值的痛点
- 查看类型
df = pd.DataFrame({
"商品": ["键盘","鼠标"],
"数量": [2, 3],
"金额": [178.0, 45.0]
})
df.dtypes
df["数量"].dtype
# 详细内存与类型诊断
df.info(memory_usage="deep")
区分:
- NumPy 原生类型:
int64、float64、bool_、object- Pandas 扩展类型:
Int64、Float64、boolean、string、category、datetime64、timedelta64
二、NumPy 原生类型(传统)
1. int 整数
int8 / int16 / int32 / int64
- 特点:不能存空值 NaN,一旦出现缺失,会自动向上转为 float
s = pd.Series([1, 2, None], dtype="int64")
print(s.dtype) # float64,自动上浮
2. float 浮点
float16 / float32 / float64
- 可以表示
np.nan - 缺点:浮点数存在精度误差,金额、ID尽量避免float存储
3. bool 布尔
bool_
- 只有 True / False;不支持空值,遇到None会变成object类型
4. object 对象类型(最容易踩坑)
dtype: object
- 本质:一列存放Python对象(字符串、列表、字典、混合类型)
- 弊端:
- 内存占用大
str.xxx向量化方法性能差- 分组、筛选速度慢
- 常见场景:旧版本读取文本默认object;单元格内包含列表、字典
尽量优先使用
string类型替代object存字符串。
5. datetime64 / timedelta64 时间类型
# datetime64[ns] 纳秒时间戳
s = pd.to_datetime(["2026-01-01", "2026-01-02"])
# timedelta64[ns] 时间间隔
s_delta = pd.to_timedelta(["1 day","2h"])
- 支持
dt访问器:year, month, day, weekday - 时间运算、resample、rolling时序统计必备
三、Pandas 扩展类型 ExtensionDtype(推荐新项目使用)
核心优势:原生支持 NA(pd.NA),不会因为空值强制上浮类型
| 类型 | 写法 | 说明 |
|---|---|---|
| 可空整数 | pd.Int64Dtype() / "Int64" | 大写I,支持pd.NA |
| 可空浮点 | pd.Float64Dtype() / "Float64" | 大写F,支持pd.NA |
| 可空布尔 | pd.BooleanDtype() / "boolean" | 支持pd.NA,三态:True/False/NA |
| 字符串类型 | pd.StringDtype() / "string" | 专门存文本,替代object |
示例:
# 可空整数,有空值也不会变成float
s_int = pd.Series([1, 2, None], dtype="Int64")
# 可空布尔
s_bool = pd.Series([True, False, None], dtype="boolean")
# 标准字符串类型
s_str = pd.Series(["键盘","鼠标", None], dtype="string")
注意大小写:
int64(numpy,不可空) vsInt64(pandas扩展,可空)
四、Categorical 分类类型 category(高频优化类型)
适合重复值多、基数少的字段:渠道、商品、状态、省份、类别
s_cat = pd.Series(["线上","线下","线上"], dtype="category")
特点:
- 底层存储:唯一类别编码 + 映射表,内存大幅降低
- groupby、筛选、排序速度显著提升
- 支持自定义有序分类(图表、排序按指定顺序)
# 有序分类
s_cat = pd.Series(["低","中","高"], dtype=pd.CategoricalDtype(
categories=["低","中","高"], ordered=True
))
常用属性:
s_cat.cat.categories # 所有类别
s_cat.cat.codes # 底层编码
s_cat.cat.ordered # 是否有序
坑:category类型不能直接使用str访问器,需要先转string。
五、数据类型转换 astype / to_numeric
5.1 astype 强制转换
df["数量"] = df["数量"].astype("Int64")
df["商品"] = df["商品"].astype("string")
df["渠道"] = df["渠道"].astype("category")
astype 遇到无法转换的值直接报错。
5.2 pd.to_numeric 安全数值转换(清洗脏数据首选)
# errors="coerce" 无法转换的自动变成 NA
df["金额"] = pd.to_numeric(df["金额"], errors="coerce", downcast="float")
df["数量"] = pd.to_numeric(df["数量"], errors="coerce", downcast="integer")
downcast 自动向下压缩精度,节省内存。
5.3 pd.to_datetime 时间转换
df["date"] = pd.to_datetime(df["date"], errors="coerce")
六、读取文件时直接指定 dtype(性能最佳时机)
不要读完再转换,读取阶段就约束类型,减少内存占用
df = pd.read_csv(
"sales.csv",
dtype={
"商品": "string",
"渠道": "category",
"数量": "Int64"
},
parse_dates=["下单日期"]
)
七、类型判断方法
s = df["金额"]
# 判断是否是数字
pd.api.types.is_numeric_dtype(s)
# 判断是否是字符串
pd.api.types.is_string_dtype(s)
# 判断是否是分类
pd.api.types.is_categorical_dtype(s)
# 判断是否是时间
pd.api.types.is_datetime64_any_dtype(s)
# 判断是否是可空布尔
pd.api.types.is_boolean_dtype(s)
八、类型自动推断 convert_dtypes(一键升级扩展类型)
Pandas 提供一键转换,自动把object转为string、int转为Int64等
df = df.convert_dtypes()
适合快速升级旧DataFrame,批量启用扩展可空类型。
九、类型对比总结表
| 需求 | 推荐类型 | 不推荐 |
|---|---|---|
| 带缺失的整数 | Int64 | int64 |
| 带缺失的布尔 | boolean | bool_ |
| 文本字符串 | string | object |
| 重复多的类别字段 | category | string / object |
| 时间 | datetime64[ns] | 字符串 |
| 金额浮点 | Float64 | float64(注意精度) |
十、高频坑清单
- int64 出现空值自动变成float64:整数丢失、精度异常,改用 Int64
- object类型存大量字符串:速度慢、内存大,改用 string
- category类型做str.extract、str.contains报错:先
.astype("string") - 浮点数存订单号、ID:精度丢失,ID应该用 string
- 时间存字符串:无法dt访问、resample、窗口,必须转datetime64
- 混用
np.nan和pd.NA:扩展类型优先用 pd.NA - astype 强转脏数据直接崩溃:脏数据清洗用 pd.to_numeric + errors=”coerce”
- 分类categories顺序不对,排序、图表顺序错乱:用 CategoricalDtype 指定有序列表
十一、综合实战模板
def cast_sales_dtype(df):
df = df.copy()
# 文本
df["商品"] = df["商品"].astype("string")
# 分类
df["渠道"] = df["渠道"].astype("category")
# 可空整数
df["数量"] = pd.to_numeric(df["数量"], errors="coerce").astype("Int64")
# 可空浮点
df["金额"] = pd.to_numeric(df["金额"], errors="coerce").astype("Float64")
# 时间
df["下单日期"] = pd.to_datetime(df["下单日期"], errors="coerce")
return df
十二、速查表
| API | 作用 |
|---|---|
| df.dtypes | 查看每列类型 |
| astype() | 强制类型转换 |
| pd.to_numeric | 清洗脏数据转为数值 |
| pd.to_datetime | 转为时间 |
| convert_dtypes() | 一键升级扩展类型 |
| pd.CategoricalDtype | 自定义有序分类 |
| pd.api.types.is_xxx_dtype | 类型判断 |
0 条笔记