共计 2897 个字符,预计需要花费 8 分钟才能阅读完成。
问题诊断:为什么评估指标全是 NaN?
当随机森林回归模型输出 MSE/R²等指标为 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)
实践建议与延伸阅读
- Kaggle 实战数据集:
- House Prices Advanced Regression Techniques
-
推荐阅读:
- 《The Elements of Statistical Learning》第 15 章
- Scikit-learn 文档:Ensemble Methods
通过系统性的数据诊断、合理的 Pipeline 构建以及针对性的参数调优,可以有效解决随机森林回归中的 NaN 指标问题。建议在实际项目中始终保留完整的模型验证日志,这对排查异常指标至关重要。
正文完
发表至: 未分类
近一天内
