Python实战:用Scikit-learn轻松搞定随机森林分类(附完整代码)
Python实战:用Scikit-learn轻松搞定随机森林分类(附完整代码)
随机森林作为机器学习中最实用的算法之一,凭借其出色的表现和易用性,成为数据科学项目中的常客。今天我们就来手把手教你如何用Python的Scikit-learn库快速构建一个随机森林分类器,从数据准备到模型评估,全程代码可复制运行。
1. 环境准备与数据加载
在开始之前,确保你已经安装了必要的Python库。打开你的终端或命令提示符,运行以下命令:
pip install numpy pandas scikit-learn matplotlib seaborn
我们将使用经典的鸢尾花(Iris)数据集作为示例,这个数据集内置于Scikit-learn中,非常适合用来演示分类问题。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 加载数据
iris = load_iris()
X = iris.data # 特征
y = iris.target # 标签
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
为什么选择随机森林?
- 对特征缩放不敏感,省去了数据标准化的步骤
- 能够自动处理特征间的交互作用
- 内置特征重要性评估
- 对异常值和噪声数据有较好的鲁棒性
2. 构建基础随机森林模型
让我们从最简单的随机森林分类器开始。Scikit-learn的RandomForestClassifier类让这个过程变得异常简单。
from sklearn.ensemble import RandomForestClassifier
# 创建随机森林分类器实例
rf = RandomForestClassifier(n_estimators=100, random_state=42)
# 训练模型
rf.fit(X_train, y_train)
# 在测试集上评估
accuracy = rf.score(X_test, y_test)
print(f"模型准确率: {accuracy:.2f}")
小技巧:设置random_state参数可以确保结果可复现,这在调试和分享代码时特别有用。
2.1 理解关键参数
随机森林有几个重要参数会影响模型性能:
| 参数 | 默认值 | 说明 |
|---|---|---|
| n_estimators | 100 | 森林中树的数量,通常越大越好,但计算成本会增加 |
| max_depth | None | 树的最大深度,控制模型复杂度 |
| min_samples_split | 2 | 分裂内部节点所需的最小样本数 |
| min_samples_leaf | 1 | 叶节点所需的最小样本数 |
| max_features | 'auto' | 寻找最佳分割时考虑的特征数量 |
提示:对于分类问题,
max_features的默认值是特征数的平方根,这通常是一个不错的起点。
3. 模型评估与可视化
准确率只是评估模型的一个方面,我们还需要更全面的评估指标。
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
# 预测测试集
y_pred = rf.predict(X_test)
# 打印分类报告
print(classification_report(y_test, y_pred))
# 绘制混淆矩阵
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.show()
3.1 特征重要性分析
随机森林的一个强大功能是能够评估特征的重要性。
# 获取特征重要性
importances = rf.feature_importances_
features = iris.feature_names
# 创建DataFrame便于查看
import pandas as pd
feature_importance = pd.DataFrame({'特征': features, '重要性': importances})
feature_importance = feature_importance.sort_values('重要性', ascending=False)
print(feature_importance)
# 可视化
plt.figure(figsize=(10, 6))
sns.barplot(x='重要性', y='特征', data=feature_importance)
plt.title('特征重要性排序')
plt.show()
4. 超参数调优
虽然随机森林的默认参数通常表现不错,但适当的调优可以进一步提升性能。我们使用网格搜索(GridSearchCV)来寻找最佳参数组合。
from sklearn.model_selection import GridSearchCV
# 定义参数网格
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
# 创建网格搜索实例
grid_search = GridSearchCV(estimator=RandomForestClassifier(random_state=42),
param_grid=param_grid,
cv=5,
n_jobs=-1,
verbose=2)
# 执行网格搜索
grid_search.fit(X_train, y_train)
# 输出最佳参数
print(f"最佳参数组合: {grid_search.best_params_}")
print(f"最佳交叉验证分数: {grid_search.best_score_:.2f}")
# 使用最佳模型评估测试集
best_rf = grid_search.best_estimator_
test_accuracy = best_rf.score(X_test, y_test)
print(f"调优后测试集准确率: {test_accuracy:.2f}")
注意事项:
- 网格搜索计算成本较高,参数范围不宜设置过大
- 对于大型数据集,可以考虑使用随机搜索(RandomizedSearchCV)
- 实际项目中,可以先在小样本上测试参数效果
5. 处理类别不平衡问题
在实际项目中,我们经常会遇到类别不平衡的数据集。随机森林提供了几种处理方式:
# 创建不平衡的示例数据
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000, n_classes=2, weights=[0.9, 0.1], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 方法1:使用class_weight参数
rf_balanced = RandomForestClassifier(class_weight='balanced', random_state=42)
rf_balanced.fit(X_train, y_train)
# 方法2:手动设置样本权重
sample_weight = np.where(y_train == 1, 5, 1) # 少数类样本权重设为5
rf_weighted = RandomForestClassifier(random_state=42)
rf_weighted.fit(X_train, y_train, sample_weight=sample_weight)
# 比较两种方法
print("平衡类别权重准确率:", rf_balanced.score(X_test, y_test))
print("手动设置权重准确率:", rf_weighted.score(X_test, y_test))
提示:对于多类不平衡问题,可以传递一个字典给
class_weight参数,为每个类别指定权重。
6. 实际应用技巧与常见问题
6.1 处理缺失值
随机森林本身能够处理缺失值,但Scikit-learn的实现不支持。我们可以先进行缺失值填充:
from sklearn.impute import SimpleImputer
# 假设X_train有缺失值
imputer = SimpleImputer(strategy='mean') # 也可以用'median'或'most_frequent'
X_train_imputed = imputer.fit_transform(X_train)
X_test_imputed = imputer.transform(X_test)
# 然后训练模型
rf.fit(X_train_imputed, y_train)
6.2 处理高基数分类特征
对于具有大量类别的分类特征,可以考虑以下方法:
- 目标编码(Target Encoding)
- 使用
pd.get_dummies进行独热编码(适用于类别较少的情况) - 使用
OrdinalEncoder进行序数编码
from sklearn.preprocessing import OrdinalEncoder
# 假设有一个分类特征列
encoder = OrdinalEncoder()
X_train['category_feature'] = encoder.fit_transform(X_train[['category_feature']])
X_test['category_feature'] = encoder.transform(X_test[['category_feature']])
6.3 模型持久化
训练好的模型可以保存到磁盘,以便后续使用:
import joblib
# 保存模型
joblib.dump(rf, 'random_forest_model.joblib')
# 加载模型
loaded_rf = joblib.load('random_forest_model.joblib')
7. 随机森林的局限性
虽然随机森林很强大,但也有其局限性:
- 计算资源:树的数量多时,训练和预测速度较慢
- 内存消耗:需要存储所有树的结构
- 解释性:虽然比单个决策树更难解释,但仍比神经网络等"黑盒"模型好
- 外推能力:对于超出训练数据范围的预测可能表现不佳
在实际项目中,我通常会先尝试随机森林作为基线模型,然后再根据具体需求考虑是否使用更复杂的算法。
更多推荐



所有评论(0)