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

如何为RandomForest编码非序数分类变量(不使用LabelEncoder)

针对非序数高基数分类变量的RandomForest优化方案

你遇到的问题本质是高基数非序数分类变量的编码适配问题,同时要兼顾模型效果和部分依赖图(PDP)的生成,以下是针对性的解决思路:

1. 修复目标编码的PDP异常:用正则化/留一法编码

普通目标编码容易过拟合,导致编码值波动剧烈,PDP无法正常生成。试试用留一法目标编码(避免数据泄露)或者带平滑的均值编码:

from category_encoders import LeaveOneOutEncoder
from sklearn.ensemble import RandomForestClassifier

# 初始化编码器,指定要编码的列
encoder = LeaveOneOutEncoder(cols=['CountryOfExploitation', 'gender', 'citizenship'])
# 用留一法编码,训练时不泄露当前样本的目标信息
df_encoded = encoder.fit_transform(df, df['exploitation_type'])

# 训练随机森林
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(df_encoded.drop('exploitation_type', axis=1), df['exploitation_type'])

留一法编码后的数值连续且稳定,不会出现PDP渲染异常的情况,同时解决了LabelEncoder的序数假设问题。

2. 拯救独热编码:类别合并+特征筛选

独热编码后特征爆炸导致模型效果差?先做两步优化:

  • 合并低频次类别:把样本量极少的国家归为“其他”,减少特征维度
    # 统计国家出现次数,合并频次低于50的类别(阈值根据你的数据调整)
    country_counts = df['CountryOfExploitation'].value_counts()
    low_freq_countries = country_counts[country_counts < 50].index
    df['CountryOfExploitation'] = df['CountryOfExploitation'].replace(low_freq_countries, 'Other')
    
  • 筛选重要特征:用随机森林的特征重要性过滤冗余的独热特征
    from sklearn.preprocessing import OneHotEncoder
    from sklearn.compose import ColumnTransformer
    from sklearn.feature_selection import SelectFromModel
    
    # 独热编码分类变量
    ct = ColumnTransformer(
        [('onehot', OneHotEncoder(sparse_output=False, drop='first'), ['CountryOfExploitation', 'gender', 'citizenship'])],
        remainder='passthrough'
    )
    X_encoded = ct.fit_transform(df.drop('exploitation_type', axis=1))
    y = df['exploitation_type']
    
    # 用临时随机森林筛选特征
    rf_temp = RandomForestClassifier(n_estimators=100, random_state=42)
    rf_temp.fit(X_encoded, y)
    selector = SelectFromModel(rf_temp, threshold='median')
    X_selected = selector.fit_transform(X_encoded, y)
    
    # 训练最终模型
    rf_final = RandomForestClassifier(n_estimators=100, random_state=42)
    rf_final.fit(X_selected, y)
    

优化后的独热编码特征维度大幅降低,模型效果会提升,同时生成PDP也不会因为特征太多报错。

3. 正确生成PDP:映射回原始类别

不管用哪种编码,生成PDP时要把编码值映射回原始类别,不然x轴显示的是编码后的数字毫无意义:

from sklearn.inspection import plot_partial_dependence
import matplotlib.pyplot as plt

# 以留一法编码为例,获取原始类别和编码值的映射
country_mapping = encoder.mapping['CountryOfExploitation']['mapping']
# 反转映射,得到编码值到原始国家的对应关系
code_to_country = {v: k for k, v in country_mapping.items()}

# 生成PDP
fig, ax = plt.subplots(figsize=(12, 6))
plot_partial_dependence(rf, df_encoded.drop('exploitation_type', axis=1), features=['CountryOfExploitation'], ax=ax)
# 修改x轴标签为原始国家名称
ax.set_xticks(list(code_to_country.keys()))
ax.set_xticklabels(list(code_to_country.values()), rotation=45)
plt.tight_layout()
plt.show()

4. 偷懒方案:用原生支持分类变量的树模型

不想折腾编码?直接用CatBoost或LightGBM,它们能直接处理非序数分类变量,不用手动编码,生成PDP也更简单:

import catboost as cb

# 构造CatBoost数据集,指定分类特征列
train_pool = cb.Pool(
    data=df.drop('exploitation_type', axis=1),
    label=df['exploitation_type'],
    cat_features=['CountryOfExploitation', 'gender', 'citizenship']
)

# 训练模型
cat_model = cb.CatBoostClassifier(iterations=100, random_state=42, verbose=0)
cat_model.fit(train_pool)

# 直接生成PDP,自动用原始类别显示
cat_model.plot_partial_dependence(features=['CountryOfExploitation'], data=train_pool)
plt.show()

这种方案最省心,模型对高基数分类变量的处理效率也比RandomForest更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 22:40:22