1 机器学习概述
1.1 机器学习简介
机器学习(MachineLearning),作为计算机科学的子领域,是人工智能领域的重要分支和实现方式。
机器学习并不是让机器像人一样学习,而是去寻找大量数据之间的隐藏规律,在同类型事件再次发生时,运用总结的规律在短时间内对实际问题进行决定或预测。
1.2 回归算法分类
1.3 线性模型
1.3.1 (单/多元)线性回归
线性回归是最简单、最常用的回归算法之一,假设目标变量 ( y ) 与输入特征 ( X ) 之间存在线性关系。
y=wX+b
其中,w 是权重向量,( b ) 是偏置项。
线性回归通过最小化均方误差(MSE)来找到最佳拟合线。
通过梯度下降算法,求解最小MSE对应的最佳参数 W和 b组合。
import numpy as np #基于数组对象的科学计算库
from sklearn.linear_model import LinearRegression #从sklearn导入线性回归模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples=100, n_features=2, noise=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = LinearRegression()
model.fit(X_train, y_train)
# 预测与评估
y_pred = model.predict(X_test) #模型预测Y值
print(f"Coefficients: {model.coef_}") #模型权重W
print(f"Intercept: {model.intercept_}") #模型参数b
print(f"Mean Squared Error: {np.mean((y_pred - y_test)**2)}") #输出模型MSE值
numpy:科学计算库,提供了矩阵,线性代数,傅立叶变换等等的解决方案, 最常用的是它的N维数组对象。
sklearn:是一个功能强大且易于使用的机器学习库,它提供了丰富的算法和工具集,使得机器学习变得更加简单和高效。
1.3.2 Lasso
一般线性回归模型的目标是最小化残差平方和(MSE),即通过拟合一个线性方程来预测目标变量。然而,在实际问题中,可能存在大量的自变量,其中一些可能对目标变量的预测能力较弱或冗余。此时,Lasso回归通过引入L1正则化 (即Lasso惩罚项),可以将系数向量中小的权重变为0,从而实现特征选择和模型稀疏性。
其中, 是正则化项,它通过增加非零系数的数量来惩罚模型的复杂性。
假设我们有两个特征 和 ,
,lasso回归的惩罚项
的几何形状是一个菱形。而 OLS 的等值线是椭圆形。当我们在优化过程中缩小误差平方和的同时约束
(即菱形内的区域),最终会导致优化解在菱形的顶点处。这些顶点对应于一些系数(如
或
)为零,从而实现特征选择。
总之,通过Lasso回归,我们不仅能得到一个适合数据的模型,还能自动筛选出对结果有重要影响的特征,使得模型更加简洁和解释性更强。
import numpy as np #基于数组对象的科学计算库
from sklearn.linear_model import Lasso #从sklearn导入Lasso模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
from sklearn.model_selection import GridSearchCV #超参数网格搜索
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples=100, n_features=5, noise=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = Lasso()
#定义超参数网格,-4~4之间平均取50个点
alphas = np.logspace(-4, 4, 50)
#网格搜索
grid_search=GridSearchCV(estimator = model,param_grid = {'alpha':alphas},cv=5,scoring='neg_mean_squared_error')
grid_search.fit(X_train,y_train)
#最佳模型与超参数
best_lasso = grid_search.best_estimator_ #最佳模型
best_alpha=grid_search.best_params_['alpha'] #最佳超参数
print(f'Best alpha:{best_alpha}')
# #训练最终模型
# lasso_opt=Lasso(alpha = best_alpha)
# lasso_opt.fit(X_train,y_train)
#预测
y_pred_train=best_lasso.predict(X_train)
y_pred_test=best_lasso.predict(X_test)
print(f"Coefficients: {best_lasso.coef_}") #模型权重W
print(f"Intercept: {best_lasso.intercept_}") #模型参数b
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
超参数'alpha': 它控制了L1正则化项中惩罚项的大小。当alpha为0时,Lasso退化为普通的线性回归模型,不带任何正则化;如果alpha非常大,则所有特征的权重都会趋近于0;如果alpha适当,则不重要的特征的权重都会趋近于0,从而实现特征选择。
GridSearchCV: 它通过搜索定义的超参数值,筛选模型对应的最佳超参数值。然后使用最佳超参数训练最终模型,使模型表现良好。但对于多个超参数的模型,计算成本可能很高。
优点:
-
特征选择:Lasso回归会将一些不重要的特征的系数缩减为零,从而实现特征选择。这使得模型更加简洁和易于解释。
-
减少过拟合:通过引入正则化项,Lasso回归可以有效地减少过拟合,提高模型的泛化能力。
-
简单高效:Lasso回归相对简单,计算效率高,适用于处理高维数据。
缺点:
-
多重共线性问题:当特征之间存在多重共线性时,Lasso回归可能无法正确选择特征,导致模型性能下降。
-
计算复杂度:在大规模数据集上,Lasso回归的计算复杂度可能较高,尤其是当使用网格搜索优化超参数时。
-
模型解释性:虽然Lasso回归能进行特征选择,但对结果的解释性仍可能受到数据特性的影响,有时难以完全理解模型的行为。
1.3.3 Ridge
Ridge 回归是一种用于处理多重共线性(即自变量之间高度相关)的线性回归技术。它通过在模型中引入一个额外的惩罚项(L2正则化)来避免过拟合,从而提高模型的泛化能力。
多重共线性问题:在实际应用中,自变量之间有时候会高度相关,这叫做多重共线性。这种情况会导致线性回归模型的预测效果不好,因为模型对训练数据过于敏感(即过拟合),在新数据上表现不佳。
引入惩罚项:Ridge 回归通过在损失函数中加入一个惩罚项(也叫正则化项)来解决这个问题。这个惩罚项是所有回归系数的平方和乘以一个常数(惩罚参数)。它的作用是限制回归系数的大小,使得模型不会过度拟合训练数据。
可以说,Ridge 回归是一种增强版的线性回归,通过在损失函数中加入一个惩罚项来限制回归系数的大小,从而减少过拟合并提高模型在新数据上的预测能力。对于咱们大多数同学来说,可以把 Ridge 回归看作是在原有的线性回归基础上“加了一点约束”,使得模型更加稳健。
其中, 是L2正则化参数,控制惩罚项的权重。较大的
会更严格地限制
的大小,防止过拟合。
import numpy as np #基于数组对象的科学计算库
from sklearn.linear_model import Ridge #从sklearn导入Lasso模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
from sklearn.model_selection import GridSearchCV #超参数网格搜索
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples=100, n_features=5, noise=0.2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = Ridge()
#定义超参数网格,-4~4之间平均取50个点
alphas = np.logspace(-4, 4, 50)
#网格搜索
grid_search=GridSearchCV(estimator = model,param_grid = {'alpha':alphas},cv=5,scoring='neg_mean_squared_error')
grid_search.fit(X_train,y_train)
#最佳模型与超参数
best_lasso = grid_search.best_estimator_ #最佳模型
best_alpha=grid_search.best_params_['alpha'] #最佳超参数
print(f'Best alpha:{best_alpha}')
# #训练最终模型
# lasso_opt=Lasso(alpha = best_alpha)
# lasso_opt.fit(X_train,y_train)
#预测
y_pred_train=best_lasso.predict(X_train)
y_pred_test=best_lasso.predict(X_test)
print(f"Coefficients: {best_lasso.coef_}") #模型权重W
print(f"Intercept: {best_lasso.intercept_}") #模型参数b
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
优点
-
解决多重共线性问题:Ridge 回归通过引入 正则化项,可以有效地解决自变量之间存在多重共线性的问题,从而提高模型的稳定性和预测性能。
-
防止过拟合:正则化项限制了回归系数的大小,防止模型过拟合训练数据,提升对新数据的泛化能力。
-
计算效率高:相比于某些复杂的非线性回归模型,Ridge 回归的计算效率较高,适用于大规模数据集。
-
参数调整灵活:通过调整正则化参数 ,可以在偏差和方差之间找到最佳平衡,从而优化模型性能。
缺点:
-
不适用于特征选择:Ridge 回归不会将不相关的特征系数缩减到零,因此不适用于需要进行特征选择的场景。
-
无法处理非线性关系:Ridge 回归是线性模型,如果数据中存在复杂的非线性关系,Ridge 回归的表现可能不如非线性模型。
-
解释性较差:由于引入了正则化项,Ridge 回归模型的解释性可能较差,不易于解释每个特征对目标值的具体影响。
1.3.4 ElasticNet
ElasticNet 回归结合了 Lasso 和 Ridge 的特点,通过引入 L1 和 L2 正则化项:
import numpy as np #基于数组对象的科学计算库
from sklearn.linear_model import ElasticNet #从sklearn导入Lasso模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
from sklearn.model_selection import GridSearchCV #超参数网格搜索
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples=100, n_features=5, noise=0.2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = ElasticNet()
#定义超参数网格,-4~4之间平均取50个点的二维网格
alphas = np.logspace(-4,4,50)
param_grid = {'alpha': alphas, 'l1_ratio':np.linspace(0,1,10)}
#网格搜索
grid_search=GridSearchCV(estimator = model,param_grid = {'alpha':alphas},cv=5,scoring='neg_mean_squared_error')
grid_search.fit(X_train,y_train)
#最佳模型与超参数
best_lasso = grid_search.best_estimator_ #最佳模型
best_alpha=grid_search.best_params_['alpha'] #最佳超参数
print(f'Best alpha:{best_alpha}')
# #训练最终模型
# lasso_opt=Lasso(alpha = best_alpha)
# lasso_opt.fit(X_train,y_train)
#预测
y_pred_train=best_lasso.predict(X_train)
y_pred_test=best_lasso.predict(X_test)
print(f"Coefficients: {best_lasso.coef_}") #模型权重W
print(f"Intercept: {best_lasso.intercept_}") #模型参数b
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
优点:
-
结合了 Ridge 和 Lasso 的优点:既可以解决多重共线性问题,又可以进行特征选择。
-
灵活性高:通过调整
和
的值,可以在 Ridge 和 Lasso 之间进行权衡。
缺点:
-
参数选择复杂:需要同时调优两个正则化参数,可能增加模型调参的复杂性。
-
计算开销较大:由于引入了两个正则化项,计算复杂度相对更高。
1.4 KNN
K近邻回归(K-Nearest Neighbors Regression,简称KNN回归)是一种简单直观的机器学习算法。KNN回归通过寻找样本空间中与目标点最接近的K个邻居,利用这些邻居的平均值或加权平均值来预测目标点的值。KNN回归属于非参数模型,因为它不对数据的分布做出假设,也不需要训练过程。
对于待预测的样本点,计算其与训练集中每一个样本点之间的欧氏距离:
其中, 和
分别是两个样本点的特征向量,
是特征的维数。
根据计算得到的距离,选择距离待预测样本点最近的K个邻居。
根据选中的K个邻居的输出值,计算待预测样本点的加权平均输出值。
其中, 是待预测样本点与第
个邻居的距离。
from sklearn.neighbors import KNeighborsRegressor #从sklearn导入KNeighborsRegressor模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples = 150, n_features = 3, noise = 0.1, random_state = 42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = KNeighborsRegressor(n_neighbors = 4)
model.fit(X_train, y_train)
# n_neighbors: 默认为5,表示用于 kneighbors 查询的默认邻居数。
# weights: 权重函数用于预测,可选值为 'uniform'(均匀权重)或 'distance'(距离权重),或者自定义的一个函数。默认为 'uniform'。
# algorithm: 计算最近邻的算法,可选 'auto'、'ball_tree'、'kd_tree'、'brute'。'auto' 会基于传递给 fit 方法的值尝试决定最合适的算法。
# p: 闵可夫斯基度量的幂参数。当 p=1 时,等同于使用曼哈顿距离; p=2 时为欧几里得距离。
#预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
n_neighbors: 默认为5,表示用于 kneighbors 查询的默认邻居数。
weights: 权重函数用于预测,可选值为 'uniform'(均匀权重)或 'distance'(距离权重),或者自定义的一个函数。默认为 'uniform'。
algorithm: 计算最近邻的算法,可选 'auto'、'ball_tree'、'kd_tree'、'brute'。'auto' 会基于传递给 fit 方法的值尝试决定最合适的算法。
p: 闵可夫斯基度量的幂参数。当 p=1 时,等同于使用曼哈顿距离; p=2 时为欧几里得距离。
优点:
-
简单直观:算法思想简单,容易理解和实现。
-
无模型假设:KNN回归不对数据的分布做任何假设,适用于各种数据分布。
-
高灵活性:由于无需训练过程,KNN回归可以处理在线学习问题,也可以随时加入新的数据。
缺点:
-
计算复杂度高:对于大规模数据集,计算每个样本点的距离代价较高,影响预测效率。
-
维度灾难:随着特征维数的增加,样本之间的距离变得越来越难以区分,导致预测效果下降。
-
对异常值敏感:KNN回归直接依赖于邻居的输出值,如果邻居中存在异常值,可能会严重影响预测结果。
1.5 SVR
支持向量回归(SVR)是一种扩展到回归任务的支持向量机(SVM)。它的目标是找到一个能够最大限度地拟合训练数据的回归超平面,同时保持模型的复杂度尽可能小。SVR 通过在误差范围内(即“ε-不敏感”区域)不对数据点施加惩罚,从而控制模型的泛化能力。
from sklearn.svm import SVR #从sklearn导入SVR模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples = 150, n_features = 2, noise = 0.2, random_state = 42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = SVR(kernel = 'rbf',C = 100,epsilon = 0.1,gamma = 0.1) #超参数太多GridSearchCV计算量太大,可以手动调超参数,
model.fit(X_train, y_train)
# kernel:算法中所使用的核函数类型,其中有(‘linear’,‘poly’, ‘rbf’,‘sigmoid’,‘precomputer’,默认使用‘rbf’).
# degree:多项式核函数的次数,默认为3,所以当核函数为‘poly’时用到,其它核函数忽略.
# gamma:核函数的系数,在核函数为‘rbf’,‘poly’,‘sigmoid’时使用,其他核函数忽略。gamma的值必须大于0,随着gamma的增大,对于测试集分类效果越差,对于训练集分类效果好,并且使模型的复杂度提高,泛化能力(对未知数的预测能力)较差,从而出现过拟合的情况。
# coef0:核函数中的常数值(y = kx + b中的b值),只在核函数为‘poly’跟‘sigmoid’时使用。
# tol:残差收敛条件,默认是0.0001,即容忍1000分类里出现一个错误,误差达到指定值时停止训练。
# C: 错误项的惩罚因子:原则上C可以根据需要选择所有大于0的数。C越大表示整个优化过程中对于总误差的关注程度越高,对于减小误差的要求越高,甚至不惜使间隔减小。
# 当C趋于无穷大时,这个问题也就是不允许出现分类误差的样本存在,那这就是一个hard - marginSVM问题;
# 当C趋于0时,我们不再关注分类是否正确,只要求间隔越大越好,那么我们将无法得到有意义的解且算法不会收敛。
#预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
kernel:算法中所使用的核函数类型,其中有(‘linear’,‘poly’, ‘rbf’,‘sigmoid’,‘precomputer’,默认使用‘rbf’)。
degree: 多项式核函数的次数,默认为3,所以当核函数为‘poly’时用到,其它核函数忽略.
C: 错误项的惩罚因子(大于0),C越大表示整个优化过程中对于总误差的关注程度越高,对于减小误差的要求越高,甚至不惜使间隔减小。
优点:
-
强大的泛化能力:通过 ε-不敏感区域,SVR 能有效控制模型的复杂度,防止过拟合。
-
非线性扩展:借助核技巧,SVR 能处理非线性数据。
-
鲁棒性:对异常值具有一定的鲁棒性。
缺点:
-
计算复杂度高:由于二次规划的计算复杂度,SVR 在大数据集上训练时间较长。
-
参数调优复杂:需要仔细调节 C 和 ε 参数,以找到最优解。
1.6 树模型
1.6.1 决策树回归
决策树回归是使用树状模型进行回归任务的算法。它通过不断将数据集划分成更小的子集,并在叶子节点上做出预测。决策树的划分基于对特征的某种度量,如均方误差(MSE),以最小化叶子节点的误差为目标。
其中, 是叶子节点中的平均值。
from sklearn.tree import DecisionTreeRegressor #从sklearn导入DecisionTreeRegressor模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples = 150, n_features = 3, noise = 0.2, random_state = 42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = DecisionTreeRegressor(max_depth=3,random_state=42) #超参数太多GridSearchCV计算量太大,可以手动调超参数,
model.fit(X_train, y_train)
# "squared_error":平均平方误差,即方差减少,使用每个终端节点的平均值最小化L2损失;
# "friedman_mse":使用平均平方误差与Friedman改进得分寻找潜在的分裂;
# "absolute_error":平均绝对误差,使用每个终端节点的中位数最小化L1损失;
# "poisson":使用减少泊松偏差寻找分裂。
# splitter 参数决定了选择每个节点分割的策略,可选的策略有:"best":选择最佳分割;"random":选择最佳随机分割。
# max_depth 参数限制了树的最大深度。如果未设置,节点将继续展开直到所有叶子都是纯净的,或者每个叶子包含的样本少于 min_samples_split 指定的数量。
# min_samples_split 参数规定了分割内部节点所需的最小样本数。可以是整数或者浮点数,如果是浮点数,则表示最小样本数占总样本数的比例。
# min_samples_leaf 参数指定了一个叶子节点所需的最小样本数。这个参数可以平滑模型,特别是在回归中。
# max_features 参数决定了寻找最佳分割时考虑的特征数量。可以是整数、浮点数、"sqrt" 或 "log2"。
# random_state 参数控制估计器的随机性。即使 splitter 设置为 "best",特征在每次分割时也会随机排列。
# min_impurity_decrease 参数表示如果分割导致不纯度的减少大于或等于该值,则会进行分割。
# ccp_alpha 参数用于最小成本复杂性剪枝。选择成本复杂性最大且小于 ccp_alpha 的子树。
#预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
max_depth: 参数限制了树的最大深度。如果未设置,节点将继续展开直到所有叶子都是纯净的,或者每个叶子包含的样本少于 min_samples_split 指定的数量。
min_samples_split: 参数规定了分割内部节点所需的最小样本数。可以是整数或者浮点数,如果是浮点数,则表示最小样本数占总样本数的比例。
min_samples_leaf: 参数指定了一个叶子节点所需的最小样本数。这个参数可以平滑模型,特别是在回归中。
max_features: 参数决定了寻找最佳分割时考虑的特征数量。可以是整数、浮点数、"sqrt" 或 "log2"。
random_state: 参数控制估计器的随机性。即使 splitter 设置为 "best",特征在每次分割时也会随机排列。
min_impurity_decrease: 参数表示如果分割导致不纯度的减少大于或等于该值,则会进行分割。
1.6.2 随机森林回归
随机森林回归是通过集成多棵决策树来进行回归任务的算法。每棵树都是从数据的不同子集和特征子集上训练而成的,最终的预测结果通过这些树的平均值(Bagging)来给出。这种集成方法有效地降低了单棵决策树的过拟合风险,并提高了模型的稳定性和泛化能力。
随机森林由多棵决策树组成,假设我们有 棵树,每棵树对输入特征
给出一个预测
,则随机森林的预测结果为这些树的平均值:
from sklearn.ensemble import RandomForestRegressor #从sklearn导入RandomForestRegressor模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples = 150, n_features = 3, noise = 0.2, random_state = 42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = RandomForestRegressor(n_estimators=100,random_state=42) #定义了100棵树
model.fit(X_train, y_train)
# criterion: “mse”来选择最合适的节点。
# splitter: ”best” or “random”(default=”best”)随机选择属性还是选择不纯度最大的属性,建议用默认。
# max_features: 选择最适属性时划分的特征不能超过此值。
# 当为整数时,即最大特征数;
# 当为小数时,训练集特征数*小数;
# if “auto”, then max_features=sqrt(n_features).
# If “sqrt”, thenmax_features=sqrt(n_features).
# If “log2”, thenmax_features=log2(n_features).
# If None, then max_features=n_features.
# max_depth: (default=None)设置树的最大深度,默认为None,这样建树时,会使每一个叶节点只有一个类别,或是达到min_samples_split。
# min_samples_split: 根据属性划分节点时,每个划分最少的样本数。
# min_samples_leaf: 叶子节点最少的样本数。
# max_leaf_nodes: (default=None)叶子树的最大样本数。
# min_weight_fraction_leaf: (default=0) 叶子节点所需要的最小权值
# verbose: (default=0) 是否显示任务进程
#预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
criterion: “mse”来选择最合适的节点。
splitter: “best” or “random”(default=”best”)随机选择属性还是选择不纯度最大的属性,建议用默认。
max_features: 选择最适属性时划分的特征不能超过此值。
当为整数时,即最大特征数;
当为小数时,训练集特征数*小数;
# if “auto”, then max_features=sqrt(n_features).
# If “sqrt”, thenmax_features=sqrt(n_features).
# If “log2”, thenmax_features=log2(n_features).
# If None, then max_features=n_features.
max_depth: (default=None)设置树的最大深度,默认为None,这样建树时,会使每一个叶节点只有一个类别,或是达到min_samples_split。
min_samples_split: 根据属性划分节点时,每个划分最少的样本数。
min_samples_leaf: 叶子节点最少的样本数。
max_leaf_nodes: (default=None)叶子树的最大样本数。
min_weight_fraction_leaf: (default=0) 叶子节点所需要的最小权值
verbose: (default=0) 是否显示任务进程。
优点:
-
高准确度:通过集成学习方法,随机森林通常比单个决策树具有更高的预测准确度。
-
防止过拟合:通过对多个子集和特征进行训练,降低了模型的过拟合风险。
-
可处理高维数据:适用于高维特征的数据集。
缺点:
-
计算开销大:训练多个决策树需要较高的计算成本,尤其在数据集较大时。
-
可解释性差:由于是集成模型,难以解释单个预测的逻辑。
1.6.3 GBDT
GBDT 是基于梯度提升(Gradient Boosting)思想的一种集成学习方法。其核心思想是通过多个决策树模型的叠加,不断优化模型误差。每一棵树拟合的是前一棵树的残差(即预测误差),通过迭代减少误差,最终形成强大的预测模型。
对于回归问题,GBDT 的目标是最小化损失函数 ,其中
表示模型的预测值。模型通过以下过程迭代更新:
1.初始模型:
2.迭代训练第 棵树时,首先计算前一轮的残差
:
3. 通过拟合残差构建新的决策树,并更新模型:
其中, 是学习率,
是拟合残差的新树。
from sklearn.ensemble import GradientBoostingRegressor #从sklearn导入GradientBoostingRegressor模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples = 150, n_features = 3, noise = 0.2, random_state = 42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = GradientBoostingRegressor(learning_rate=0.1,n_estimators=100,random_state=42) #定义了100棵树
model.fit(X_train, y_train)
# Boosting 框架参数
# n_estimators:这是要构建的树的数量。太少可能会导致欠拟合,太多可能会导致过拟合。通常需要与 learning_rate 一起调整来找到最佳的组合。
# learning_rate:这是每棵树对最终预测的贡献。较小的学习率意味着需要更多的树来进行训练。通常从较小的值开始调整,例如 0.1 或更小。
# subsample:这是用于拟合每棵树的样本的比例。值小于 1 可以减少方差,防止过拟合,但也会增加偏差。推荐的值在 0.5 到 0.8 之间。
# loss:损失函数的选择对模型的性能有很大影响。对于回归问题,常用的损失函数包括均方差("ls"),绝对损失("lad"),Huber损失("huber")和分位数损失("quantile")。
# alpha:这是 Huber 损失和分位数损失的参数,它定义了分位数。当数据中有许多异常值时,可能需要调整此参数。
# 决策树参数
# max_features:在寻找最佳分割时要考虑的特征数量。这可以帮助提高模型的性能,并减少计算时间。
# max_depth:树的最大深度。较深的树可以捕获更复杂的模式,但也可能导致过拟合。
# min_samples_split 和 min_samples_leaf:这些参数控制树的生长。它们帮助定义了节点可以继续分割的条件,以及叶子节点所需的最小样本数。
# min_weight_fraction_leaf:这是叶子节点所有样本权重和的最小值,如果小于这个值,则节点将不会进一步分割。
# max_leaf_nodes:最大叶子节点数,通过限制叶子节点的数量,可以防止模型过于复杂。
# min_impurity_split:节点划分的最小不纯度。这个阈值越高,树就越容易停止生长。
#预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
Boosting 框架参数
n_estimators:这是要构建的树的数量。太少可能会导致欠拟合,太多可能会导致过拟合。通常需要与 learning_rate 一起调整来找到最佳的组合。
learning_rate:这是每棵树对最终预测的贡献。较小的学习率意味着需要更多的树来进行训练。通常从较小的值开始调整,例如 0.1 或更小。
subsample:这是用于拟合每棵树的样本的比例。值小于 1 可以减少方差,防止过拟合,但也会增加偏差。推荐的值在 0.5 到 0.8 之间。
loss:损失函数的选择对模型的性能有很大影响。对于回归问题,常用的损失函数包括均方差("ls"),绝对损失("lad"),Huber损失("huber")和分位数损失("quantile")。
alpha:这是 Huber 损失和分位数损失的参数,它定义了分位数。当数据中有许多异常值时,可能需要调整此参数。
决策树参数
max_features:在寻找最佳分割时要考虑的特征数量。这可以帮助提高模型的性能,并减少计算时间。
max_depth:树的最大深度。较深的树可以捕获更复杂的模式,但也可能导致过拟合。
min_samples_split 和 min_samples_leaf:这些参数控制树的生长。它们帮助定义了节点可以继续分割的条件,以及叶子节点所需的最小样本数。
min_weight_fraction_leaf:这是叶子节点所有样本权重和的最小值,如果小于这个值,则节点将不会进一步分割。
max_leaf_nodes:最大叶子节点数,通过限制叶子节点的数量,可以防止模型过于复杂。
min_impurity_split:节点划分的最小不纯度。这个阈值越高,树就越容易停止生长。
优点:
-
强大的预测能力:梯度提升回归在处理复杂的非线性回归任务时表现尤为出色。
-
计算效率高:(支持并行和分布式);支持自动处理缺失值;灵活性高,适合多种任务。
-
可处理高维数据:适用于高维特征的数据集。
缺点:
-
模型复杂:参数较多,调参复杂;占用内存较大,特别是在处理超大规模数据集时。
1.6.4 XGBoost
XGBoost 是 GBDT 的优化版本,核心思想仍然是梯度提升(Boosting),但它在计算效率、模型精度等方面进行了多种优化。它通过使用正则化控制模型复杂度,防止过拟合,并且支持分布式计算和多线程并行,提升了计算速度。
XGBoost 的目标是通过加法模型最小化目标函数:
其中, 是损失函数,
是正则化项,用于控制模型的复杂度。XGBoost 的优化过程使用了泰勒展开的二阶导数加速计算梯度和误差更新:
其中, 和
分别是损失函数的一阶和二阶导数,能更快地拟合新树。
from xgboost import XGBRegressor #从sklearn导入XGBRegressor模型
from sklearn.model_selection import train_test_split #从sklearn导入训练/测试数据集划分模块
from sklearn.datasets import make_regression #从sklearn导入生成回归样本数据模块
from sklearn.metrics import mean_squared_error,r2_score #模型评估MSE,R2
# 生成数据
# n_samples样本个数;n_features特征个数; noise数据噪声;random_state=42随机种子
# test_size=0.2 测试集数据占20%
X, y = make_regression(n_samples = 150, n_features = 3, noise = 0.2, random_state = 42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = XGBRegressor(eta=0.2,n_estimators=100) #定义了100棵树
model.fit(X_train, y_train)
# booster:默认值为 ‘gbtree’,基于树模型。 ‘gblinear’ 基于线性模型。
# silent:默认为0;当这个参数值为1时,静默模式开启,不会输出任何信息。
# nthread:默认值为最大可能的线程数。
# eta: 权重递减参数,典型值为0.01-0.2。
# min_child_weight:决定最小叶子节点样本权重和。
# max_depth:这个值为树的最大深度。
# max_leaf_nodes:树上最大的节点或叶子的数量。
# gamma:Gamma指定了节点分裂所需的最小损失函数下降值。 这个参数的值越大,算法越保守。
# max_delta_step:每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。
# alpha:权重的L1正则化项。 可以应用在很高维度的情况下,使得算法的速度更快。默认为1。
# lambda:权重的L2正则化项。默认为1。
#预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
#评估
mse_train=mean_squared_error(y_train,y_pred_train)
mse_test=mean_squared_error(y_test,y_pred_test)
r2_train=r2_score(y_train,y_pred_train)
r2_test=r2_score(y_test,y_pred_test)
print(f'MSE (Train): {mse_train}')
print(f'MSE (Test): {mse_test}')
print(f'R^2 (Train): {r2_train}')
print(f'R^2 (Test): {r2_test}')
booster: 默认值为 ‘gbtree’,基于树模型。 ‘gblinear’ 基于线性模型。
silent: 默认为0;当这个参数值为1时,静默模式开启,不会输出任何信息。
nthread:默认值为最大可能的线程数。
eta: 权重递减参数,典型值为0.01-0.2。
min_child_weight:决定最小叶子节点样本权重和。
max_depth:这个值为树的最大深度。
max_leaf_nodes:树上最大的节点或叶子的数量。
gamma:gamma指定了节点分裂所需的最小损失函数下降值。 这个参数的值越大,算法越保守。
max_delta_step:每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。
alpha:权重的L1正则化项。 可以应用在很高维度的情况下,使得算法的速度更快。默认为1。
lambda:权重的L2正则化项。默认为1。
优点:
-
精度更高: GBDT 只用到一阶泰勒展开,而 XGBoost 对损失函数进行了二阶泰勒展开。XGBoost 引入二阶导一方面是为了增加精度,另一方面也是为了能够自定义损失函数,二阶泰勒展开可以近似大量损失函数。
-
正则化: XGBoost 在目标函数中加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、叶子节点权重的 范式。正则项降低了模型的方差,使学习出来的模型更加简单,有助于防止过拟合,这也是XGBoost优于传统GBDT的一个特性。
-
可处理高维数据:适用于高维特征的数据集。
缺点:
-
虽然利用预排序和近似算法可以降低寻找最佳分裂点的计算量,但在节点分裂过程中仍需要遍历数据集。
-
预排序过程的空间复杂度过高,不仅需要存储特征值,还需要存储特征对应样本的梯度统计值的索引,相当于消耗了两倍的内存。
1.7 机器学习的一般流程
2 机器学习的python常用库
Numpy: 是一个Python库,提供了多维数组对象(ndarray)以及用于处理这些数组的函数。它是数据科学和机器学习领域最常用的库之一。Numpy提供了高效的数组操作和数学函数,使得在Python中进行数值计算更加简单和高效。 Numpy使用教程
Pandas: 为 Python 提供了高性能、易使用的数据结构与数据分析工具。 Pandas使用教程
Matplotlib: 是 Python 中最受欢迎的数据可视化工具之一,支持跨平台运行,它是 Python 常用的 2D 绘图库,同时它也提供了一部分 3D 绘图接口。 matplotlib使用教程
Scikit-Learn: 是基于 Python 语言的机器学习工具。有六大任务模块:分别是分类、回归、聚类、降维、模型选择和预处理。 scikit-learn使用教程
今天就写到这里吧!下次基于这些回归模型,进行论文实战代码复现。