今天是
上次文章
的一个延续,就是把昨天关于回归类算法剩余的内容进行补充。
前前后后回归类问题Q&A总共是16个方面。
另外,昨天评论区有同学觉得在内容上,缺乏代码,这个会在下周的时间进行继续补充,到时候大家可以收藏学习~
咱们今天第 2 期:回归类总结,总共是16个问题,也就是大概16个核心点的分享。
# 特征工程的重要性
读者问:
最近刚刚开始学习算法,有一个小问题。在构建回归模型时,进行特征选择和特征工程为什么这么重要?初学者,不是特别的明白
答:
你好。其实,特征选择和特征工程在构建任何算法模型的时候,都非常非常重要。
首先,让我们明确一下这两个概念。
特征选择
是指从所有可用的特征中选择最相关和最有用的特征,以用于模型的训练和预测。而
特征工程
则涉及对原始数据进行预处理和转换,以便更好地适应模型的需求,包括特征缩放、特征变换、特征衍生等等操作。
那么,为什么这两个步骤如此重要呢?我这边从4个方面概括下~
1. 提高模型性能
:通过选择最相关的特征和对特征进行适当的工程处理,可以提高模型的性能。过多的不相关特征会增加模型的复杂性,降低模型的泛化能力,导致过拟合。而合适的特征工程可以帮助模型更好地理解数据的结构和关系,提高模型的准确性。
2. 降低计算成本
:在实际的数据集中,可能存在大量的特征,而并非所有特征都对预测目标具有重要影响。通过特征选择,可以减少模型训练的计算成本和时间消耗,提高模型的效率。
3. 减少过拟合风险
:过拟合是模型在训练数据上表现很好,但在新数据上表现不佳的现象。特征选择和特征工程可以帮助降低过拟合的风险,使模型更加泛化到未见过的数据上。
4. 提高模型的解释性
:经过特征选择和特征工程处理的模型,其特征更加清晰明了,更容易理解和解释。这对于实际应用中的决策和解释至关重要。
常用的特征选择方法包括基于
统计检验、正则化方法、基于树模型的方法
等;而特征工程则涉及到
缺失值处理、标准化、归一化、编码、特征组合、降维
等技术。
下面举一个简单的案例,在代码中进行特征选择和特征工程,结合上面所说以及代码中的注释进行理解~
import numpy as npimport pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LinearRegressionfrom sklearn.feature_selection import SelectKBest, f_regressionfrom sklearn.preprocessing import StandardScaler# 随机生成示例数据 np.random.seed(0 ) X = np.random.rand(100 , 5 ) # 5个特征 y = X[:, 0 ] + 2 *X[:, 1 ] - 3 *X[:, 2 ] + np.random.randn(100 ) # 线性关系,加入噪声 # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2 , random_state=42 )# 特征工程:标准化特征 scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)# 特征选择:选择k个最好的特征 selector = SelectKBest(score_func=f_regression, k=3 ) X_train_selected = selector.fit_transform(X_train_scaled, y_train) X_test_selected = selector.transform(X_test_scaled)# 训练回归模型 model = LinearRegression() model.fit(X_train_selected, y_train)# 在测试集上评估模型性能 score = model.score(X_test_selected, y_test) print("模型在测试集上的R^2得分:" , score)
上面代码中 ,我们首先生成了一些示例数据,然后对数据进行了标准化处理。接着,我们使用方差分析选择了3个最佳特征。最后训练了一个线性回归模型并在测试集上评估了其性能。
通过特征选择和特征工程,在实际的算法建模中,可以更好地理解数据,提高模型的性能。
# 缺失值和异常值的处理
读者问:
最近在处理数据的时候,遇到缺失值和异常值就没思路了。在我的回归分析中,应该怎么样处理缺失值和异常值呢?
答:
这是一个太太太常见的问题了。首先说,处理缺失值和异常值在回归分析中非常关键,因为它们可能会对模型的准确性和可靠性造成影响。
咱们从处理缺失值和处理异常值两个方面,详细的说说~
处理缺失值
1. 数据探索与理解
首先,你需要仔细了解数据,确定哪些特征存在缺失值,并理解缺失的原因。
2. 缺失值的处理方式
删除
:如果缺失值占比很小且随机分布,可以考虑删除缺失样本或特征。
填充
:采用统计量(如均值、中位数、众数)进行填充,或者使用插值法(如线性插值、多项式插值)进行填充。
3. 代码示例
import pandas as pdfrom sklearn.impute import SimpleImputer# 假设 df 是你的数据框 # 使用均值填充缺失值 imputer = SimpleImputer(strategy='mean' ) df_filled = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
处理异常值
1. 异常值的识别
可以使用可视化工具(如箱线图、直方图)来识别异常值,或者利用统计学方法(如Z分数、IQR)来检测异常值。
2. 异常值的处理方式
删除
:如果异常值数量较少且不影响整体趋势,可以考虑删除异常样本。
替换
:用特定值(如上下限、中位数、均值)替换异常值,使其不会对模型产生过大影响。
3. 代码示例
# 假设 df 是你的数据框 # 假设我们使用 Z 分数方法来检测异常值并替换为均值 from scipy import stats z_scores = stats.zscore(df) abs_z_scores = np.abs(z_scores) filtered_entries = (abs_z_scores 3).all(axis=1 ) df_no_outliers = df[filtered_entries]
总的来说,咱们遇到这样的情况,有几点需要注意:
处理缺失值和异常值需要谨慎,因为不当的处理可能会影响模型的预测能力。
在处理之前,要仔细观察数据的分布和特点,选择合适的处理方法。
处理过程中,要保持对数据的透明度和可解释性,记录下处理过程以及处理后的数据情况。
加油~
# 回归模型的诊断
读者问:
有一个问题想要跟你学习一下。就是我如何对我的回归模型进行有效的诊断?例如,我应该如何进行残差分析或检查模型是否符合回归假设?
答:
咱们互相学习。当进行回归算法实验时,对回归模型进行有效的诊断是至关重要的,以确保模型的准确性和可靠性。
这里,总结了一些非常常见的回归模型诊断方法:
残差分析
残差(Residuals)
是指观测值与模型预测值之间的差异。通过分析残差可以评估模型的拟合程度和误差结构。
通过绘制残差图(Residual Plot)来检查残差是否随机分布在0附近,若残差呈现明显的模式(如趋势或异方差性),则可能表示模型存在问题。
正态概率图(Normal Probability Plot)可以用来检查残差是否服从正态分布。若残差点在一条直线上均匀分布,则表明残差近似正态分布。
检查回归假设
线性性(Linearity)
:使用散点图(Scatter Plot)和偏相关图(Partial Residual Plot)来检查自变量和因变量之间的线性关系。
同方差性(Homoscedasticity)
:通过残差图或者利用Breusch-Pagan检验、White检验等来检验残差是否具有同方差性。若残差的方差随着自变量的变化而变化,则可能存在异方差性。
独立性(Independence)
:通过检查残差之间的自相关性来评估观测数据是否相互独立,可以利用Durbin-Watson检验来进行检验。
正态性(Normality)
:利用正态概率图或者Shapiro-Wilk检验来检验残差是否服从正态分布。
Cook's距离
Cook's 距离衡量了每个数据点对于模型参数估计的影响程度。大的Cook's距离可能表示某些数据点对模型拟合具有较大的影响,可能是异常值或者高杠杆点。
我这里用代码实现一下,帮助你理解模型诊断相关内容~
import numpy as npimport statsmodels.api as smimport matplotlib.pyplot as plt# 生成示例数据 np.random.seed(0 ) X = np.random.rand(100 , 1 ) y = 2 * X.squeeze() + np.random.normal(scale=0.5 , size=100 )# 添加截距项 X = sm.add_constant(X)# 拟合线性回归模型 model = sm.OLS(y, X).fit()# 残差分析 residuals = model.resid plt.figure(figsize=(12 , 6 ))# 绘制残差图 plt.subplot(1 , 2 , 1 ) plt.scatter(model.fittedvalues, residuals) plt.xlabel('Fitted values' ) plt.ylabel('Residuals' ) plt.title('Residual Plot' )# 绘制正态概率图 plt.subplot(1 , 2 , 2 ) sm.qqplot(residuals, line='45' ) plt.title('Normal Probability Plot' ) plt.show()# 检查回归假设 name = ['Lagrange multiplier statistic' , 'p-value' , 'f-value' , 'f p-value' ] test = sm.stats.diagnostic.het_breuschpagan(residuals, X) print(dict(zip(name, test)))# Cook's距离 influence = model.get_influence() cooks_distance = influence.cooks_distance[0 ] plt.figure(figsize=(8 , 6 )) plt.stem(np.arange(len(cooks_distance)), cooks_distance, markerfmt="," , linefmt="b-." ) plt.xlabel('Data points' ) plt.ylabel("Cook's Distance" ) plt.title("Cook's Distance" ) plt.show()
这里给出其中一个结果图,你可以自己执行代码,把其他的图进行打印,以便理解。
通过以上代码以及给出的图形,可以进行残差分析、检查回归假设以及计算Cook's距离,从而对线性回归模型进行全面的诊断。
有问题,随时再提哈~
# 学习曲线和验证曲线的解读
读者问:
这几天遇到一个问题,就是我应该如何使用学习曲线和验证曲线来评估我的回归模型?这些曲线能告诉我什么,以及我该如何根据它们来调整模型参数?
答:
在实验中,很多时候,使用学习曲线和验证曲线可以帮助评估回归模型的性能,并指导调整模型参数。
下面我会分别介绍
学习曲线
和
验证曲线
,并说明它们能告诉我们的信息以及如何根据它们来调整模型参数。
学习曲线
学习曲线(Learning Curve)
是一种用于分析模型性能的图表,它展示了训练数据大小与模型性能之间的关系。通常,学习曲线会随着训练数据量的增加而变化。学习曲线的两个关键指标是训练集上的性能和验证集上的性能。
学习曲线能告诉我们的信息:
欠拟合:
如果训练集和验证集上的性能都很差,那么可能是模型过于简单,无法捕捉数据的复杂性。
过拟合:
如果训练集上的性能很好,但验证集上的性能较差,那么可能是模型过于复杂,学习到了训练集的噪声。
合适的模型复杂度:
当训练集和验证集上的性能趋于稳定且收敛时,可以认为找到了合适的模型复杂度。
如何根据学习曲线调整模型参数:
欠拟合时:
可以尝试增加模型复杂度,如增加多项式特征、使用更复杂的模型等。
过拟合时:
可以尝试减少模型复杂度,如减少特征数量、增加正则化、采用更简单的模型等。
验证曲线
验证曲线(Validation Curve)
是一种图表,用于分析模型性能与某一参数(例如正则化参数、模型复杂度等)之间的关系。通过在不同参数取值下评估模型的性能,我们可以找到最优的参数取值。
验证曲线能告诉我们的信息:
最优参数取值:
通过观察验证曲线的变化趋势,我们可以确定哪个参数值对模型性能有最大的提升。
过拟合和欠拟合:
验证曲线也可以用于检测过拟合和欠拟合,如果验证集上的性能在某些参数值下出现较大的波动,可能是因为模型处于过拟合或欠拟合状态。
如何根据验证曲线调整模型参数:
选择最优参数:
根据验证曲线的趋势,选择能够使验证集性能最优的参数取值。
调整模型复杂度:
如果验证曲线显示出模型过拟合或欠拟合,可以相应地调整模型复杂度或正则化参数。
这里,用代码演示了使用学习曲线和验证曲线来评估回归模型,并调整模型参数,可以作为参考~
from sklearn.datasets import make_regressionfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LinearRegressionimport matplotlib.pyplot as pltimport numpy as npfrom sklearn.model_selection import learning_curve, validation_curve# 生成随机回归数据 X, y = make_regression(n_samples=1000 , n_features=20 , 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 )# 定义线性回归模型 estimator = LinearRegression()def plot_learning_curve (estimator, title, X, y, ylim=None, cv=None, n_jobs=None, train_sizes=np.linspace(.1 , 1.0 , 5 ) ) : plt.figure() plt.title(title) if ylim is not None : plt.ylim(*ylim) plt.xlabel("Training examples" ) plt.ylabel("Score" ) train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes) train_scores_mean = np.mean(train_scores, axis=1 ) train_scores_std = np.std(train_scores, axis=1 ) test_scores_mean = np.mean(test_scores, axis=1 ) test_scores_std = np.std(test_scores, axis=1 ) plt.grid() plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, alpha=0.1 , color="r" ) plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, alpha=0.1 , color="g" ) plt.plot(train_sizes, train_scores_mean, 'o-' , color="r" , label="Training score" ) plt.plot(train_sizes, test_scores_mean, 'o-' , color="g" , label="Cross-validation score" ) plt.legend(loc="best" ) return pltdef plot_validation_curve (estimator, title, X, y, param_name, param_range, cv=None, scoring=None) : train_scores, test_scores = validation_curve( estimator, X, y, param_name=param_name, param_range=param_range, cv=cv, scoring=scoring) train_scores_mean = np.mean(train_scores, axis=1 ) train_scores_std = np.std(train_scores, axis=1 ) test_scores_mean = np.mean(test_scores, axis=1 ) test_scores_std = np.std(test_scores, axis=1 ) plt.title(title) plt.xlabel(param_name) plt.ylabel("Score" ) plt.ylim(0.0 , 1.1 ) lw = 2 plt.plot(param_range, train_scores_mean, label="Training score" , color="darkorange" , lw=lw) plt.fill_between(param_range, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, alpha=0.2 , color="darkorange" , lw=lw) plt.plot(param_range, test_scores_mean, label="Cross-validation score" , color="navy" , lw=lw) plt.fill_between(param_range, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, alpha=0.2 , color="navy" , lw=lw) plt.legend(loc="best" ) return plt# 使用示例 plot_learning_curve(estimator, "Learning Curve" , X_train, y_train, cv=5 ) plt.show()
在这段代码中,我们首先定义了一个线性回归模型
LinearRegression()
,然后将其传递给了
plot_learning_curve
函数。这样就可以成功绘制学习曲线了。
# 解释线性回归的工作原理
读者问:
能否详细解释一下线性回归的数学原理,比如它是如何通过损失函数和梯度下降来工作的?看了一圈,还是有点懵
答:
你好。当我们谈到线性回归时,我们实际上在讨论一种用于建立输入变量(特征)与连续输出变量之间关系的模型。
在实验中,我们通常想要了解输入特征如何影响输出,或者用已知的输入输出数据来预测未知的输出。线性回归正是解决这种问题的一种常见方法。
下面从数学原理和代码结合起来进行解释,应该会很好的理解~
数学原理
1. 模型表示
在线性回归中,我们假设输出变量与输入变量之间存在线性关系。这可以用以下公式表示:
其中:
2. 损失函数
我们需要定义一个损失函数来衡量模型的预测与实际观测值之间的差异。
在线性回归中,最常见的损失函数是均方误差,其公式为:
其中:
3. 梯度下降
梯度下降是一种优化算法,用于最小化损失函数。其思想是通过不断沿着损失函数梯度的反方向更新模型参数,直到达到损失函数的最小值。
梯度下降的更新规则如下:
其中:
根据上面提到的理论内容,咱们通过代码来实现一番。使用梯度下降算法进行参数优化的Python代码~
import numpy as npclass LinearRegression : def __init__ (self, learning_rate=0.01 , n_iterations=1000 ) : self.learning_rate = learning_rate self.n_iterations = n_iterations self.weights = None self.bias = None def fit (self, X, y) : n_samples, n_features = X.shape self.weights = np.zeros(n_features) self.bias = 0 for _ in range(self.n_iterations): y_predicted = np.dot(X, self.weights) + self.bias # 计算损失函数的梯度 dw = (1 /n_samples) * np.dot(X.T, (y_predicted - y)) db = (1 /n_samples) * np.sum(y_predicted - y) # 更新模型参数 self.weights -= self.learning_rate * dw self.bias -= self.learning_rate * db def predict
(self, X) : return np.dot(X, self.weights) + self.bias# 使用样例数据进行线性回归 X = np.array([[1 , 1.5 ], [2 , 2.5 ], [3 , 3.5 ], [4 , 4.5 ]]) y = np.array([2 , 3 , 4 , 5 ]) model = LinearRegression() model.fit(X, y)# 打印模型参数 print("Coefficients:" , model.weights) print("Intercept:" , model.bias)# 进行预测 X_test = np.array([[5 , 5.5 ], [6 , 6.5 ]]) predictions = model.predict(X_test) print("Predictions:" , predictions)# Coefficients: [0.37869152 0.65891856] # Intercept: 0.5604540832879905 # Predictions: [6.07796379 7.11557387]
这段代码演示了如何使用梯度下降算法拟合线性回归模型,并进行预测。
在读懂简洁的理论之上,自行推到,最后结合代码,应该是比较容易理解的。
# 非线性回归模型的例子
读者问:
能给我一些非线性回归模型的例子吗?它们与线性回归主要有什么不同?
答:
当谈到非线性回归模型时,我们通常指的是模型中自变量和因变量之间的关系不是线性的,而是通过非线性函数来描述的一类回归模型。
下面我会介绍几种常见的非线性回归模型,并与线性回归进行对比。这样会更加的容易理解。
1. 多项式回归
多项式回归是一种将自变量的高次项加入模型的方法,例如:
这与线性回归的不同之处在于,
自变量
的幂次不仅限于一次。通过增加高次项,模型能够更好地拟合非线性关系。
2. 指数回归
指数回归是一种通过指数函数来建模的方法,例如:
这种模型表达了因变量随自变量呈指数增长或指数衰减的趋势。
3. 对数回归
对数回归是一种通过对自变量或因变量取对数来建模的方法,例如:
或者