前言
写这篇博客,主要是自己来练练手。网络上教程已经是数不胜数,也都讲得非常清楚了。但自己不动手,知识和能力还是别人的。下面分别用传统方法(sklearn)和神经网络(pytorch)来解决线性回归问题。
内容
什么是线性回归
线性回归(Linear Regression)是统计学和机器学习中最基础且广泛使用的预测模型,用于建立**自变量(输入特征)与因变量(输出目标)**之间的线性关系模型。其核心思想是通过一条直线(或超平面)拟合数据点,以实现对连续型数值的预测。
核心概念与公式

适用场景
- 预测连续值:如房价预测、销售额预测、温度趋势分析等。
- 因果关系初探:分析自变量对因变量的影响方向和强度(需谨慎,需排除混杂因素)。
- 基线模型:作为复杂模型(如神经网络)的对比基准。
关键假设
线性回归的有效性依赖于以下假设:
- 线性关系:自变量与因变量呈线性关系。
- 独立性:样本之间相互独立(无自相关)。
- 同方差性:误差项的方差恒定。
- 正态性:误差项服从正态分布(对参数估计的统计推断有影响)。
- 无多重共线性:自变量之间高度相关会降低模型稳定性。
优缺点
优点 | 缺点 |
---|---|
简单易懂,计算高效 | 仅能建模线性关系,无法处理非线性问题 |
结果可解释性强(系数直接反映影响) | 对异常值和噪声敏感 |
统计推断明确(如p值、置信区间) | 需严格满足模型假设 |
示例
场景:预测房屋价格(单位:万元)
- 自变量:面积(㎡)、房间数、地理位置评分
- 模型:房价=10+0.5×面积+3×房间数+2×地理位置
- 解读:面积每增加1㎡,房价预计上涨0.5万元;每多一间房,房价上涨3万元。
扩展:正则化线性回归
为应对过拟合或特征共线性,可引入正则化技术:
- 岭回归(Ridge):在损失函数中加入L2正则化项(控制系数大小)。
- Lasso回归:加入L1正则化项(可实现特征选择,稀疏化系数)。
线性回归是机器学习的基石,理解它有助于后续学习更复杂的模型(如逻辑回归、神经网络)。实际应用中需结合数据特性验证假设或调整模型。
传统方法(sklearn) 解法
Scikit-learn是一个基于Python语言的机器学习库,它提供了广泛的机器学习算法,包括但不限于支持向量机、随机森林、梯度提升机、k-近邻、逻辑回归、线性回归、岭回归、套索回归、弹性网回归、朴素贝叶斯、决策树、集成方法、聚类算法如k-均值、层次聚类、DBSCAN、谱聚类以及降维技术如主成分分析、线性判别分析、t-SNE等,通过简单易用的API和详细的文档,它为研究人员和开发者提供了一个强大的工具箱,用于数据挖掘和数据分析任务。
以下是一个使用Python和Scikit-learn库实现的简单线性回归示例代码:
python
from sklearn.linear_model import LinearRegression
import numpy as np
# 示例数据
# 自变量(特征)
X = np.array([[1], [2], [3], [4], [5]])
# 因变量(目标值)
y = np.array([1, 2, 2.5, 4, 5])
# 创建线性回归模型实例
model = LinearRegression()
# 训练模型
model.fit(X, y)
# 预测
# 例如,预测X为6时的y值
X_new = np.array([[6]])
y_pred = model.predict(X_new)
# 打印模型参数(斜率和截距)
slope = model.coef_[0]
intercept = model.intercept_
print("斜率:", slope)
print("截距:", intercept)
print("预测值:", y_pred[0])
在这个例子中,我们使用了一个特征X和一个目标值y。模型训练后,我们预测了当X为6时的y值。模型的斜率是1.0,截距是-0.1。因此,当X为6时,预测的y值约为5.9。
在Scikit-learn库中,线性回归是通过LinearRegression类实现的。这个类使用了最小二乘法来估计线性模型的参数。下面是LinearRegression类的基本实现原理和代码示例:
数据准备:确保输入数据是数值型,并且特征矩阵是二维数组,目标变量是一维数组。
模型创建:创建一个LinearRegression类的实例。
模型拟合:使用.fit()方法来训练模型,它会计算最佳拟合直线。
预测:使用.predict()方法来进行预测。
下面是Scikit-learn中LinearRegression类的简化版伪代码,展示了它的基本结构:
python
from sklearn.base import BaseEstimator, RegressorMixin
from sklearn.utils.validation import check_X_y, check_array, check_is_fitted
from sklearn.utils.extmath import safe_sparse_dot
import numpy as np
class LinearRegression(BaseEstimator, RegressorMixin):
def __init__(self, fit_intercept=True, normalize=False, copy_X=True, n_jobs=None):
# 初始化模型参数
self.fit_intercept = fit_intercept
self.normalize = normalize
self.copy_X = copy_X
self.n_jobs = n_jobs
def fit(self, X, y):
# 检查输入数据
X, y = check_X_y(X, y, accept_sparse=['csr', 'csc', 'coo'],
y_numeric=True, multi_output=True)
# 标准化数据(如果需要)
if self.normalize:
X = self._normalize(X)
# 添加截距项(如果需要)
if self.fit_intercept:
X = np.hstack((np.ones((X.shape[0], 1)), X))
# 使用最小二乘法计算权重
self.coef_, self.residues_, self.rank_, self.singular_ = np.linalg.lstsq(X, y, rcond=-1)
self.coef_ = self.coef_.T
# 如果添加了截距项,则调整权重和截距
if self.fit_intercept:
self.intercept_ = self.coef_[0]
self.coef_ = self.coef_[1:]
else:
self.intercept_ = 0.
# 返回拟合的模型
return self
def predict(self, X):
# 检查模型是否已经拟合
check_is_fitted(self)
# 检查输入数据
X = check_array(X, accept_sparse=['csr', 'csc', 'coo'])
# 标准化数据(如果需要)
if self.normalize:
X = self._normalize(X)
# 添加截距项(如果需要)
if self.fit_intercept:
X = np.hstack((np.ones((X.shape[0], 1)), X))
# 进行预测
return safe_sparse_dot(X, self.coef_.T) + self.intercept_
def _normalize(self, X):
# 标准化特征
# ...
return X
# 使用示例
# 创建模型实例
model = LinearRegression()
# 训练模型
model.fit(X_train, y_train)
# 进行预测
predictions = model.predict(X_test)
这个伪代码展示了LinearRegression类的基本结构,实际代码会更加复杂,包含更多的输入验证、错误处理和优化。在Scikit-learn的源代码中,LinearRegression类的实现会涉及到更多细节,比如多输出回归、稀疏矩阵的支持、并行计算等。如果需要查看详细的实现,可以直接查看Scikit-learn库的源代码。
神经网络(pytorch)
在PyTorch中解决线性回归问题,我们首先需要构建一个简单的神经网络模型,该模型将只包含一个线性层,因为我们正在尝试学习一个线性关系。以下是如何使用PyTorch来实现线性回归的步骤:
导入必要的库
创建模拟数据集
定义一个简单的神经网络模型
选择损失函数和优化器
训练模型
评估模型
以下是具体的代码实现:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 1. 创建模拟数据集
# 真实的线性关系: y = 2x + 1
x_data = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_data = torch.tensor([[3.0], [5.0], [7.0], [9.0]])
# 2. 定义一个简单的神经网络模型
class LinearRegressionModel(nn.Module):
def __init__(self):
super(LinearRegressionModel, self).__init__()
self.linear = nn.Linear(in_features=1, out_features=1) # 一个输入特征和一个输出特征
def forward(self, x):
return self.linear(x)
model = LinearRegressionModel()
# 3. 选择损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 4. 训练模型
for epoch in range(100):
# 前向传播
y_pred = model(x_data)
# 计算损失
loss = criterion(y_pred, y_data)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch+1) % 10 == 0:
print(f'Epoch [{epoch+1}/100], Loss: {loss.item():.4f}')
# 5. 评估模型
with torch.no_grad(): # 在这个上下文中,我们不需要计算梯度
predicted = model(x_data).data.numpy()
expected = y_data.data.numpy()
print(f'Predicted: {predicted.flatten()}, Expected: {expected.flatten()}')
在这个例子中,我们首先创建了一个包含四个数据点的简单线性关系的数据集。然后,我们定义了一个只有一个线性层的神经网络模型。我们使用了均方误差损失函数(MSELoss)和随机梯度下降优化器(SGD)来训练模型。最后,我们训练了模型100个epoch,并在每个10个epoch后打印出损失值,最后评估模型的预测结果。
请注意,这个例子使用了模拟数据,实际应用中你需要使用真实的数据集。此外,对于线性回归问题,通常情况下并不需要使用神经网络,因为线性回归模型已经足够简单且有效。但是,这个例子展示了如何在PyTorch中设置和训练一个神经网络模型。
总结
sklearn 是使用了最小二乘法来进行求解,而 pytorch则是做了一个只有一个神经元的神经网络。sklean中还有很多传统机器学习算法,在一些情况下还是很有用的。而pytorch则逐渐发展出来用于实现各种结构的神经网络。就像生物进化一样,发展出了不同分支,但都能适应一定的环境。