随机森林回归实战:解决NaN指标问题与模型调优指南

1次阅读
没有评论

共计 2897 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

问题诊断:为什么评估指标全是 NaN?

当随机森林回归模型输出 MSE/R²等指标为 NaN 时,通常说明模型未能从数据中学到有效规律。以下是五大常见原因及诊断代码示例:

随机森林回归实战:解决 NaN 指标问题与模型调优指南

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor

# 模拟问题数据
data = pd.DataFrame({'feature1': [1, 2, 3, np.nan, 5],
    'feature2': [0, 0, 0, 0, 0],  # 零方差特征
    'target': [1.1, 2.4, 3.0, 4.2, 5.7]
})

# 诊断函数
def check_nan_issues(df: pd.DataFrame) -> dict:
    issues = {'missing_values': df.isnull().sum().to_dict(),
        'zero_variance': df.std()[df.std() == 0].index.tolist(),
        'dtypes': df.dtypes.to_dict()}
    return issues

print(check_nan_issues(data))

关键诊断点:

  • 缺失值(Missing Values):未处理的 NaN 会破坏决策树分裂
  • 零方差特征(Zero-Variance Features):如 feature2 所有值相同
  • 数据类型不匹配:分类变量未正确编码
  • 样本量过少:特征数 >> 样本数时容易过拟合
  • 目标变量异常:存在无限大值或全部相同值

解决方案:构建健壮的数据预处理 Pipeline

1. 分类变量编码最佳实践

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler

# 定义预处理步骤
numeric_features = ['feature1']
numeric_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())
])

categorical_features = ['category_col']
categorical_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))
])

preprocessor = ColumnTransformer(
    transformers=[('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)
    ])

2. 处理零方差特征

from sklearn.feature_selection import VarianceThreshold

selector = VarianceThreshold(threshold=0.01)  # 移除方差 <0.01 的特征
X_processed = selector.fit_transform(X)

模型调优:RandomForest vs TreeBagger

参数网格搜索模板

from sklearn.model_selection import GridSearchCV

param_grid = {'n_estimators': [50, 100, 200],
    'max_depth': [None, 10, 20],
    'min_samples_split': [2, 5],
    'min_samples_leaf': [1, 2]
}

model = Pipeline(steps=[('preprocessor', preprocessor),
    ('regressor', RandomForestRegressor())
])

grid_search = GridSearchCV(
    model, param_grid, cv=5,
    scoring='neg_mean_squared_error',
    n_jobs=-1, verbose=2
)
grid_search.fit(X_train, y_train)

关键参数说明:

  • n_estimators:树的数量,更多树 = 更稳定但计算成本更高
  • max_depth:控制过拟合,None 表示不限制
  • min_samples_split:节点分裂最小样本数

生产环境三大陷阱

陷阱 1:类别不平衡导致分裂失败

解决方案:

# 调整类别权重
class_weight = compute_sample_weight('balanced', y)
model.fit(X, y, sample_weight=class_weight)

陷阱 2:内存溢出(Out-of-Memory)

解决方法:

  • 设置 n_jobs=1 减少并行度
  • 使用 max_samples 参数限制每棵树使用的样本比例

陷阱 3:特征重要性误导

验证方法:

import matplotlib.pyplot as plt

feat_importances = pd.Series(model.named_steps['regressor'].feature_importances_,
    index=get_feature_names(preprocessor)
)
feat_importances.nlargest(10).plot(kind='barh')
plt.title('Top 10 Feature Importance')
plt.show()

评估指标重构方案

自定义评估函数避免 NaN:

from sklearn.metrics import make_scorer

def safe_r2_score(y_true, y_pred):
    if len(np.unique(y_true)) == 1:
        return 0.0  # 全部预测为均值时返回 0
    return r2_score(y_true, y_pred)

custom_scorer = make_scorer(safe_r2_score)

实践建议与延伸阅读

  1. Kaggle 实战数据集:
  2. House Prices Advanced Regression Techniques
  3. Tabular Playground Series

  4. 推荐阅读:

  5. 《The Elements of Statistical Learning》第 15 章
  6. Scikit-learn 文档:Ensemble Methods

通过系统性的数据诊断、合理的 Pipeline 构建以及针对性的参数调优,可以有效解决随机森林回归中的 NaN 指标问题。建议在实际项目中始终保留完整的模型验证日志,这对排查异常指标至关重要。

正文完
 0
评论(没有评论)