数据类型转换是数据清洗的关键步骤。pandas 提供多种方式:强制转换(astype)、解析函数(pd.to_*)、自动推断(convert_dtypes)。


1. astype()

astype() 强制将 Series 或 DataFrame 转换为指定类型,是使用频率最高的类型转换方法。

Series 转换

import pandas as pd
import numpy as np
 
s = pd.Series([1, 2, 3])
 
# 转浮点
s.astype('float64')
# 0    1.0
# 1    2.0
# 2    3.0
 
# 转字符串
s.astype('str')
# 0    '1'
# 1    '2'
# 2    '3'
 
# 转可空整数
s.astype('Int64')
 
# 转分类类型
s.astype('category')

DataFrame 转换

df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': ['1.1', '2.2', '3.3'],
    'C': [True, False, True]
})
 
# 统一转换所有列
df.astype('object')
 
# 按列指定类型
df.astype({'A': 'int64', 'B': 'float64', 'C': 'bool'})
 
# 转换为可空类型
df.astype({'A': 'Int64', 'B': 'Float64', 'C': 'boolean'})
 
# 转 string 扩展类型
df.astype({'B': 'string'})

参数详解

参数说明
dtype目标类型(字符串、NumPy dtype、pandas dtype)或字典(按列指定)
copy是否复制数据(默认 True)
errors'raise'(默认,转换失败抛错)或 'ignore'(忽略错误返回原对象)
# 转换失败时忽略错误
s.astype('int64', errors='ignore')

常见陷阱

  • 字符串转数值时,若含无法解析的字符(如 'abc'),会抛出 ValueError
  • None / NaN 在 astype('int64') 时会失败,需先填补或使用可空类型
  • astype('str') 转为 object 类型,字符串方法使用 .str;若需 string 扩展类型,使用 astype('string')

2. pd.to_numeric()

pd.to_numeric() 将参数转换为数值类型,可处理字符串、列表、Series 等。

参数详解

参数说明
arg待转换的对象(标量、列表、Series、数组)
errors'raise'(默认)、'coerce'(无效值转为 NaN)、'ignore'(无效时返回原对象)
downcast降级到更小的类型:'integer'、'signed'、'unsigned'、'float'

示例

s = pd.Series(['1', '2.5', '3', 'abc', None])
 
# 默认行为:遇到无法解析的字符串会报错
pd.to_numeric(s)
# ValueError: Unable to parse string "abc"
 
# coerce:无法解析转为 NaN
pd.to_numeric(s, errors='coerce')
# 0    1.0
# 1    2.5
# 2    3.0
# 3    NaN
# 4    NaN
# dtype: float64
 
# ignore:无法转换时保留原样
pd.to_numeric(s, errors='ignore')
 
# 降级类型
pd.to_numeric(['100', '200'], errors='coerce')
# 0    100
# 1    200
# dtype: int64
 
# 强制降级为整数
pd.to_numeric(['1', '2'], downcast='integer')
# dtype: int8

应用到 DataFrame

df = pd.DataFrame({'A': ['1', '2'], 'B': ['3.4', '5.6']})
 
# 将指定列转换为数值
df['A'] = pd.to_numeric(df['A'])
df['B'] = pd.to_numeric(df['B'])
 
# 多列批量处理
for col in ['A', 'B']:
    df[col] = pd.to_numeric(df[col], errors='coerce')

优势

to_numeric 比 astype 更能容忍错误(配合 errors='coerce'),且在解析数字字符串时更智能。


3. pd.to_datetime()

pd.to_datetime() 将字符串、整数、列表等转换为 datetime64 类型。

参数详解

参数说明
arg待转换对象(标量、列表、Series、DataFrame、字典等)
errors'raise'(默认)、'coerce'(无效转 NaT)、'ignore'(返回原对象)
format指定解析格式(如 '%Y-%m-%d'),可加速解析
unit时间戳单位(如 's'、'ms'、'ns'),用于数字转日期
dayfirst优先解释为“日/月/年”(默认 False)
yearfirst优先解释为“年/月/日”
utc是否将结果统一为 UTC
exactformat 是否要求严格匹配(默认 True)
cache是否使用缓存(默认 True)

示例

# 字符串列表
pd.to_datetime(['2024-01-01', '2024-02-01'])
# DatetimeIndex(['2024-01-01', '2024-02-01'], dtype='datetime64[ns]')
 
# 混合格式 + 错误处理
pd.to_datetime(['2024-01-01', 'invalid'], errors='coerce')
# DatetimeIndex(['2024-01-01', 'NaT'], dtype='datetime64[ns]')
 
# 指定格式
pd.to_datetime(['2024/01/01', '2024/02/01'], format='%Y/%m/%d')
 
# 时间戳整数(单位秒)
pd.to_datetime([1609459200, 1609545600], unit='s')
 
# 时间戳毫秒
pd.to_datetime([1609459200000], unit='ms')
 
# 拆分的年月日列合并
df = pd.DataFrame({'year': [2024, 2025], 'month': [1, 6], 'day': [15, 30]})
pd.to_datetime(df)
 
# 日期列转换
df['日期'] = pd.to_datetime(df['日期'], format='%Y-%m-%d')

常见格式参考

格式码含义示例
%Y4 位年份2024
%y2 位年份24
%m2 位月份01
%d2 位日期15
%H24 小时制小时13
%M分钟45
%S秒30
%f微秒123456
%Z时区UTC+08:00
# 解析带时分秒的字符串
pd.to_datetime('2024-03-15 13:45:30', format='%Y-%m-%d %H:%M:%S')

注意

  • 混合格式字符串建议使用 errors='coerce' 并检查 NaT
  • 解析大文件日期列时,用 format 参数可显著提升性能
  • 时区转换请使用 tz_localize() / tz_convert(),to_datetime 本身不处理时区

4. pd.to_timedelta()

pd.to_timedelta() 将字符串、数字等转换为 timedelta64 类型。

参数详解

参数说明
arg待转换对象(字符串、数字、列表、Series)
unit数字的默认为单位(如 's'、'ms'、'm'、'h'、'D')
errors'raise'(默认)、'coerce'(无效转 NaT)、'ignore'

示例

# 字符串形式
pd.to_timedelta('1 days')
# Timedelta('1 days 00:00:00')
 
pd.to_timedelta('2 hours 30 minutes')
# Timedelta('0 days 02:30:00')
 
# 列表
pd.to_timedelta(['1 day', '2 days', '3 days'])
 
# 数字 + 单位
pd.to_timedelta([1, 2, 3], unit='h')
# TimedeltaIndex(['0 days 01:00:00', '0 days 02:00:00', '0 days 03:00:00'])
 
# 错误处理
pd.to_timedelta(['1 day', 'bad'], errors='coerce')
# TimedeltaIndex(['1 days', 'NaT'], dtype='timedelta64[ns]')

与数值列运算

df = pd.DataFrame({'秒数': [3600, 7200, 10800]})
df['时长'] = pd.to_timedelta(df['秒数'], unit='s')
#        秒数          时长
# 0   3600   0 days 01:00:00
# 1   7200   0 days 02:00:00
# 2  10800   0 days 03:00:00

5. convert_dtypes()

convert_dtypes() 自动将每列转换为“最佳”的可空数据类型,是 pandas 推荐的新方法。

参数详解

参数说明
infer_objects是否推断 object 类型(默认 True)
convert_string是否转为 string 扩展类型(默认 True)
convert_integer是否转为可空整数(默认 True)
convert_boolean是否转为可空布尔(默认 True)
convert_floating是否转为可空浮点(默认 True)
dtype_backend'numpy_nullable'(默认)或 'pyarrow'

示例

df = pd.DataFrame({
    'A': [1, 2, None],          # 含缺失的整数
    'B': [1.5, 2.5, None],      # 含缺失的浮点
    'C': ['a', 'b', None],      # 含缺失的字符串
    'D': [True, False, None]    # 含缺失的布尔
})
 
print(df.dtypes)
# A    float64
# B    float64
# C     object
# D     object
# dtype: object
 
df2 = df.convert_dtypes()
print(df2.dtypes)
# A     Int64
# B   Float64
# C    string
# D   boolean
# dtype: object

应用到读取数据

# read_csv 时配合 dtype_backend
df = pd.read_csv('data.csv', dtype_backend='pyarrow')
 
# 读取后统一转换
df = pd.read_csv('data.csv').convert_dtypes()

优势

  • 自动将含缺失的数值列转换为可空扩展类型,解决 NaN 破坏整数的问题
  • 自动将 object 字符串转为 string 扩展类型,更高效
  • 与 pandas 2.x 的 PyArrow 后端无缝集成

注意

convert_dtypes() 是启发式推断,可能对部分列产生意外结果。转换后务必检查 df.dtypes 是否符合预期。


6. 类型转换实践

综合示例

df = pd.read_csv('乱数据.csv')
 
# 1. 统一缺失值标记
df = df.replace(['NULL', 'N/A', '?'], pd.NA)
 
# 2. 自动推断类型
df = df.convert_dtypes()
 
# 3. 手动修正特殊列
df['日期'] = pd.to_datetime(df['日期'], errors='coerce')
df['价格'] = pd.to_numeric(df['价格'], errors='coerce')
df['数量'] = pd.to_numeric(df['数量'], errors='coerce', downcast='integer')
df['时长'] = pd.to_timedelta(df['时长'], errors='coerce')
 
# 4. 检查结果
print(df.dtypes)
print(df.isna().sum())

转换时常见的坑

场景问题解法
字符串含逗号'1,000' 无法转数字先 str.replace(',', '')
日期格式多样'2024/1/1' 与 '01-02-2024'errors='coerce' 后检查 NaT
整数列含 NaNastype('int64') 报错使用 Int64 或先填充
布尔字符串'Y' / 'N'replace({'Y': True, 'N': False})
百分比字符串'10%'str.rstrip('%') 后转浮点除以 100