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

如何在Pandas中转换多分类名义型类别列(规避维度爆炸)

解决高基数名义型特征的编码难题

嘿,这个问题太典型了——高基数的名义型特征编码确实头疼:Item_Identifier这类无顺序的名义特征,用LabelEncoder完全不符合逻辑(毕竟类别间没大小先后),搞哑变量又直接生成1599列,和你的训练集行数一样,直接维度爆炸还可能导致模型无法训练。下面给你几个靠谱的解决方案,按需选择:

1. 频率/计数编码(无监督场景首选)

既然你已经有了value_counts()的结果,大部分类别出现次数在9-10次,我们可以把每个类别映射成它在数据集里的出现频率(或计数)。这种方法既保留了类别分布的信息,又不会新增任何列,简单高效。

代码示例:

import pandas as pd

# 计算每个类别的出现频率(归一化后的值,也可以用原始计数)
freq_map = train_df['Item_Identifier'].value_counts(normalize=True).to_dict()

# 替换原特征列,生成新的数值列
train_df['Item_Identifier_freq'] = train_df['Item_Identifier'].map(freq_map)

优势:零维度膨胀,计算快,不需要依赖目标变量,适合无监督或快速验证场景。

2. 目标编码(有监督场景首选)

如果你的任务是有监督学习(比如回归、分类),目标编码是个好选择——用每个类别对应的目标变量的均值(或中位数)来编码。不过要注意过拟合问题,最好用交叉验证的方式计算编码值,避免模型记住训练集的噪声。

基础版(快速验证)

# 假设你的目标列叫'target'
target_mean_map = train_df.groupby('Item_Identifier')['target'].mean().to_dict()
train_df['Item_Identifier_target'] = train_df['Item_Identifier'].map(target_mean_map)

稳健交叉验证版(避免过拟合)

import numpy as np
from sklearn.model_selection import KFold

kf = KFold(n_splits=5, shuffle=True, random_state=42)
train_df['Item_Identifier_target_cv'] = np.nan

# 用5折交叉验证,每次用训练折的均值编码验证折
for train_idx, val_idx in kf.split(train_df):
    train_part = train_df.iloc[train_idx]
    val_part = train_df.iloc[val_idx]
    fold_mean_map = train_part.groupby('Item_Identifier')['target'].mean()
    train_df.loc[val_idx, 'Item_Identifier_target_cv'] = val_part['Item_Identifier'].map(fold_mean_map)

# 用全局均值填充可能的缺失值(比如只在某一折出现的稀有类别)
global_target_mean = train_df['target'].mean()
train_df['Item_Identifier_target_cv'] = train_df['Item_Identifier_target_cv'].fillna(global_target_mean)

优势:直接把类别和目标变量的关联信息融入编码,模型能更好捕捉有用信号,效果通常优于频率编码。

3. 嵌入编码(深度学习场景首选)

如果你的模型是深度学习架构(比如MLP、CNN),可以用嵌入层来学习类别对应的低维向量表示。先给每个类别分配唯一ID,再让模型自动学习合适的嵌入向量。

代码示例(用Keras):

from sklearn.preprocessing import LabelEncoder
from tensorflow.keras.layers import Embedding

# 先用LabelEncoder给每个类别分配唯一整数ID
le = LabelEncoder()
train_df['Item_Identifier_id'] = le.fit_transform(train_df['Item_Identifier'])

# 在模型中定义Embedding层,比如设置嵌入维度为8
embedding_dim = 8
embedding_layer = Embedding(
    input_dim=len(le.classes_),  # 类别总数
    output_dim=embedding_dim,    # 嵌入向量维度
    input_length=1               # 输入长度(单个特征)
)

优势:模型自动学习类别间的语义关联,不需要手动设计编码规则,灵活性高,适合复杂的深度学习任务。

4. 合并低频类别(可选,视数据情况)

如果你的数据里有极少数出现次数特别低的类别,可以把它们合并成一个统一的“Other”类别,再用哑变量或其他编码方式。不过从你的value_counts()来看,大部分类别出现次数都在9-10次,这个方法收益可能不大,但如果有个别类别出现次数远低于这个值,还是值得试试。

代码示例:

# 设定阈值,比如把出现次数小于9的类别合并为'Other'
threshold = 9
category_counts = train_df['Item_Identifier'].value_counts()
low_freq_categories = category_counts[category_counts < threshold].index.tolist()

train_df['Item_Identifier_grouped'] = train_df['Item_Identifier'].replace(low_freq_categories, 'Other')

# 之后可以对分组后的列做哑变量编码
dummy_cols = pd.get_dummies(train_df['Item_Identifier_grouped'], prefix='Item')
train_df = pd.concat([train_df, dummy_cols], axis=1)

总结

  • 无监督/快速验证:选频率编码
  • 有监督学习:优先目标编码(交叉验证版)
  • 深度学习:用嵌入编码
  • 绝对不要用哑变量,不然维度爆炸+矩阵奇异,模型根本跑不起来

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 15:07:57