You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

sklearn OneHotEncoder工作原理及泰坦尼克数据集编码疑问

关于sklearn OneHotEncoder在泰坦尼克数据集上编码行为的疑问

我最近在泰坦尼克数据集的pandas DataFrame子集上使用sklearn的OneHotEncoder,根据官方文档,默认auto模式会自动从训练数据推导类别,不需要手动指定。于是我写了这段代码:

print(x_train.head())
enc = OneHotEncoder(handle_unknown="ignore")
print("_____________")
print(x_train.shape)
x_train = enc.fit_transform(x_train)
print(x_train.shape)
print(x_train.toarray())

得到的输出是:

Pclass  Sex   Age  SibSp  Parch     Fare Cabin Embarked
845      3  male  42.000000      0      0   7.5500  None        S
162      3  male  26.000000      0      0   7.7750  None        S
630      1  male  80.000000      0      0  30.0000   A23        S
176      3  male  29.699118      3      1  25.4667  None        S
115      3  male  21.000000      0      0   7.9250  None        S
_____________
(712, 8)
(712, 460)
[[0. 0. 1. ... 0. 0. 1.]
 [0. 0. 1. ... 0. 0. 1.]
 [1. 0. 0. ... 0. 0. 1.]
 ...
 [0. 0. 1. ... 0. 0. 1.]
 [1. 0. 0. ... 0. 0. 1.]
 [0. 0. 1. ... 0. 0. 1.]]

我能看到特征数从8变成了460,符合独热编码的预期,但我有几个疑问:

  1. 编码器是对所有特征都进行了独热编码吗?
  2. 如果是的话,像Age这种虽然有有限取值但本质是连续变量的特征,被编码难道不是问题吗?
  3. 另外,像Pclass这种类型是int但实际是分类变量的特征,编码器会怎么处理?

问题拆解与解答

1. 编码器是否对所有特征都做了独热编码?

没错,OneHotEncoder默认会对输入的所有特征进行编码——它不会自动识别特征的语义类型,只看输入的数据结构。你输入的是包含8列的DataFrame,它就会把每一列都当作“类别特征”处理,这就是特征数暴涨到460的核心原因:比如Cabin列有大量唯一值,每个值都会被拆成一个新的二进制特征,加上其他列的类别总数,最终就到了460。

2. 连续变量被独热编码的问题

这确实是个严重的问题!像Age、Fare这种连续变量,独热编码会把每个不同数值都当成独立类别,不仅会产生大量冗余特征,还会破坏变量的连续性(比如30岁和31岁本应比30岁和60岁更相似,但独热编码后它们是完全孤立的特征),会直接影响模型的学习效果和训练效率。

3. 类型为int的分类变量(如Pclass)的处理

OneHotEncoder完全不关心特征的pandas数据类型(int、object等),只要是输入的特征列,它都会按唯一值生成类别。比如Pclass的取值是1、2、3,编码器会把它拆成3个二进制特征,分别对应“是否是1等舱”“是否是2等舱”“是否是3等舱”——这其实符合分类变量的编码需求,但前提是你确实把它当作分类变量处理;如果想保留它的有序性(比如1等舱>2等舱>3等舱),那更适合用OrdinalEncoder。


正确的做法:指定需要编码的特征

要解决这个问题,你需要明确区分分类特征和连续特征,针对性处理,sklearn推荐两种方式:

方法一:用ColumnTransformer分特征处理

这是最规范的做法,可以给不同类型特征绑定不同预处理逻辑:

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler

# 定义分类特征和连续特征列名
categorical_features = ['Pclass', 'Sex', 'Embarked', 'Cabin']
numeric_features = ['Age', 'SibSp', 'Parch', 'Fare']

# 构建预处理管道
preprocessor = ColumnTransformer(
    transformers=[
        ('cat', OneHotEncoder(handle_unknown="ignore"), categorical_features),
        ('num', StandardScaler(), numeric_features)
    ])

# 拟合并转换训练数据
x_train_processed = preprocessor.fit_transform(x_train)

这样分类特征会被独热编码,连续特征会被标准化(你也可以换成其他归一化方法)。

方法二:单独提取分类特征编码后合并

如果你只想对分类特征编码,可以先拆分特征,编码后再合并:

# 提取分类特征
cat_x_train = x_train[['Pclass', 'Sex', 'Embarked', 'Cabin']]
# 提取连续特征
num_x_train = x_train[['Age', 'SibSp', 'Parch', 'Fare']]

# 编码分类特征
enc = OneHotEncoder(handle_unknown="ignore")
cat_x_train_encoded = enc.fit_transform(cat_x_train)

# 合并编码后的分类特征与连续特征
import scipy.sparse
x_train_processed = scipy.sparse.hstack([cat_x_train_encoded, num_x_train])

额外小技巧:查看编码器生成的类别

如果你想确认编码器到底生成了哪些类别,可以用enc.categories_属性查看:

enc = OneHotEncoder(handle_unknown="ignore")
enc.fit(cat_x_train)
# 打印每个分类特征对应的类别
for col, categories in zip(categorical_features, enc.categories_):
    print(f"特征 {col} 的类别: {categories}")

内容的提问来源于stack exchange,提问作者jgklsdjfgkldsfaSDF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:25:20