文章目录
一、引言
本篇主要介绍机器学习里的一种重要算法 —— 随机森林(Randon Forest),该算法很灵活、使用起来方便,甚至不需要超参数(superparameter)来调优。
二、什么是随机森林?
1.集成学习(ensemble learning)
随机森林是基于集成学习(ensemble learning)的思想,这是机器学习算法中的一种重要思想,可以理解成集思广益。核心思想为:生成一组“个体学习器”(这可以是决策树、神经网络等),然后以某种策略把这些学习器结合起来,达到减少错误,提高精度的效果。这就像向一群专家征求意见,而不是只依靠一个人。每个专家都可能犯错误,但当你把他们的知识结合起来时,最终的决定往往会更好、更准确。
2.随机森林(random forest)
生成一组决策树,将不同决策树的结果结合后输出。随机提现在每次数据集随机有放回的选出,同时随机选出部分特征作为输入;许多决策树结合在一起,所谓“森林”,所以该算法被称为随机森林算法。随机森林算法是以决策树为估计器的Bagging算法。随机森林可以用于分类问题(classification)和回归问题(regression)。
3. 编程实现
1) 分类问题(鸢尾花分类
load_iris 数据集:
数据集包括两个属性data和target,150条记录,其中前四列为花萼长度,花萼宽度,花瓣长度,花瓣宽度等4个用于识别鸢尾花(iris)的属性,第5列为鸢尾花的类别(包括Setosa,Versicolour,Virginica三类)。我们通过判定花萼长度,花萼宽度,花瓣长度和花瓣宽度来划分鸢尾花的类别。
编程实现:
# 导入必要的库
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
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)
# 创建随机森林分类器实例
rf_clf = RandomForestClassifier(n_estimators=100, random_state=42)
# 训练模型
rf_clf.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = rf_clf.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型的准确率为: {accuracy:.2f}")
2) 回归问题(以房价预测问题为例
数据说明:
衡量房价的指标有:price, area, bedrooms, bathrooms, stories, mainroad, guestroom, basement, hotwaterheating, airconditioning, parking, prefarea, furnishingstatus。部分数据如图:
由于有些属性非数值型,需要转换。如yes - 1,no - 0。furnishingstatus有三种状态,furnished - 2,semi-furnished - 1,unfurnished - 0。
编程实现:
导入模块:
import pandas as ps
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error,r2_score
from sklearn.preprocessing import LabelEncoder
主要用到pandas和sklearn。pandas主要用于数据分析。
sklearn主要用于机器学习。在 Sklearn 里有六大任务模块,分别是分类、回归、聚类、降维、模型选择和预处理。
sklearn模块介绍:
1. model_selection,用于模型选择,比如交叉验证(cross validation) 和超参数调优( hyper-parameter tuning)。
2. ensemble: Ensemble-based methods for classification, regression and anomaly detection.
3. metrics里面有各种评价指标函数,如回归指标 explained_variance_score, mean_absolute_error, mean_squared_error, r2_score etc. 分类指标 accuracy_score, precision_score等。
4. preprocessing,数据预处理。
sklearn相关库的官方链接如下:
sklearn.model_selection
sklearn.ensemble
sklearn.metrics
sklearn.preprosessing
数据导入和预处理:
标签转数值:
# 加载数据
file_path = r'youFilePath'
data = pd.read_csv(file_path)
# 数据预处理
# 将二值属性转换为数值(yes - 1, no - 0
label_encoder = LabelEncoder()
binary_columns = ['mainroad', 'guestroom', 'basement', 'hotwaterheating', 'airconditioning','prefarea']
for column in binary_columns:
data[column] = label_encoder.fit_transform(data[column].map({'yes': 1, 'no': 0}))
# 将furnishingstatus属性转换为数值(furnished: 2 semi-furnished: 1 unfurnished - 0
data['furnishingstatus'] = label_encoder.fit_transform(data['furnishingstatus'].map({'furnished': 2, 'semi-furnished': 1, 'unfurnished': 0}))
"""
这里的转换也可以不使用 labelEncoder,可以直接 map ,比如:
data['furnishingstatus'] = data['furnishingstatus'].map({'furnished': 2, 'semi-furnished': 1, 'unfurnished': 0})
两种方法都能把分类标签转换成数值,效果是一样的。
区别:
1. labelEncoder 保留了映射关系,可以反向转换,机器学习常用。没有 label_encoder 就只能做单向映射。
2. labelEncoder 会给每一个标签都赋值,即使标签不存在(不存在的标签 labelEnconder 会给一个新的整数值)。直接 map 的话,没有在映射字典中的值会被赋为 NaN。
"""
训练随机森林模型:
# 特征和目标变量
X = data.drop('price', axis=1) # 删去 price 这一列,axis 指 price 的位置
y = data['price']
# 标准化
""" sklearn有自带标准化器 """
"""
# 初始化标准化器
scaler = StandardScaler()
# 计算均值和标准差,并转换数据
standardized_data = scaler.fit_transform(data)
"""
# 这里我自定义最小-最大标准化函数进行标准化。也可以使用sklearn的内置函数
def min_max_scaling(X, feature_range=(0, 1)):
X_min = X.min()
X_max = X.max()
X_scaled = (X - X_min) / (X_max - X_min) * (feature_range[1] - feature_range[0]) + feature_range[0]
return X_scaled
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 标准化训练集和测试集数据
X_train_scaled = min_max_scaling(X_train)
X_test_scaled = min_max_scaling(X_test)
Y_train_scaled = min_max_scaling(y_train)
Y_test_scaled = min_max_scaling(y_test)
# 创建随机森林模型
model = RandomForestRegressor(n_estimators=100, random_state=42)
# 训练模型
model.fit(X_train_scaled, Y_train_scaled)
模型预测和评估:
# 预测
y_pred = model.predict(X_test_scaled)
# 模型评估
# mse 均方误差
mse = mean_squared_error(Y_test_scaled, y_pred)
print(f'Mean Squared Error: {mse}')
# R^2 可决系数
r2 = r2_score(Y_test_scaled,y_pred)
print(f'R^2: {r2}')
训练结果可视化
# 可视化
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
plt.plot(range(len(y_test_scaled)), y_test_scaled, label='Actual', marker='o', linestyle='-')
plt.plot(range(len(y_pred)), y_pred, label='Predicted', marker='s', linestyle='--')
plt.xlabel('Data Index')
plt.ylabel('Scaled Price')
plt.title('Actual vs Predicted Prices')
plt.legend()
plt.show()
完整代码:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error,r2_score
from sklearn.preprocessing import LabelEncoder,MinMaxScaler
# 加载数据
file_path = r'your_file_path'
data = pd.read_csv(file_path)
# 数据预处理
# 将二值属性转换为数值(yes - 1, no - 0
label_encoder = LabelEncoder()
binary_columns = ['mainroad', 'guestroom', 'basement', 'hotwaterheating', 'airconditioning','prefarea']
for column in binary_columns:
data[column] = label_encoder.fit_transform(data[column].map({'yes': 1, 'no': 0}))
# 将furnishingstatus属性转换为数值(furnished: 2 semi-furnished: 1 unfurnished - 0
data['furnishingstatus'] = label_encoder.fit_transform(data['furnishingstatus'].map({'furnished': 2, 'semi-furnished': 1, 'unfurnished': 0}))
# 特征和目标变量
X = data.drop('price', axis=1) # 删去 price 这一列,axis 指 price 的位置
y = data['price']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
""" 用sklearn自带的标准化器 """
# 标准化
scaler_X, scaler_y = MinMaxScaler(), MinMaxScaler()
X_train_scaled = scaler_X.fit_transform(X_train)
X_test_scaled = scaler_X.transform(X_test)
y_train_scaled = scaler_y.fit_transform(y_train.values.reshape(-1, 1)).ravel()
y_test_scaled = scaler_y.transform(y_test.values.reshape(-1, 1)).ravel()
# 创建随机森林模型
model = RandomForestRegressor(n_estimators=100, random_state=42)
# 训练模型
model.fit(X_train_scaled, y_train_scaled)
# 预测
y_pred = model.predict(X_test_scaled)
# 模型评估
# mse
mse = mean_squared_error(y_test_scaled, y_pred)
print(f'Mean Squared Error: {mse}')
# R^2
r2 = r2_score(y_test_scaled,y_pred)
print(f'R^2: {r2}')
# 输出特征重要性
feature_importances = model.feature_importances_
importance_df = pd.DataFrame({'Feature': X.columns, 'Importance': feature_importances}).sort_values(by='Importance', ascending=False)
print(importance_df.to_string(index=False))
# 可视化
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
plt.plot(range(len(y_test_scaled)), y_test_scaled, label='Actual', marker='o', linestyle='-')
plt.plot(range(len(y_pred)), y_pred, label='Predicted', marker='s', linestyle='--')
plt.xlabel('Data Index')
plt.ylabel('Scaled Price')
plt.title('Actual vs Predicted Prices')
plt.legend()
plt.show()
参考文章:
Random Forest Algorithm in Machine Learning
Ensemble Learning