机器学习(1)线性回归
机器学习线性回归学习笔记以及代码实现
线性回归
首先明确回归任务和分类任务的区别
- 回归——最终的结果是一个连续的实数
- 分类——最终的结果是一个离散的值,如二分类:是与不是(1/0)
例如去银行贷款:
能不能贷款,是一个分类任务,输出的是能或者不能
能带款多少钱,是一个回归任务,输出的是一个实数值
基本定义
特征:输入的数据
标签:输出的数据
线性回归就是将特征进行线性组合,对标签进行预测,即:
y^=θ0+θ1x1+θ2x2+⋯+θnxn \hat y = \theta_0+\theta_1x_1 + \theta_2x_2 + \dots + \theta_nx_n y^=θ0+θ1x1+θ2x2+⋯+θnxn
其中,θ0\theta_0θ0是偏置项
通俗解释就是,找到最合适的一条线(或者想象成一个高维空间)来最好地拟合我们的数据点

将上述线性回归方程整合,转化为矩阵的形式,得到:
hθ(x)=∑i=0nθixi=θTx h_{\theta}(x) = \sum _{i=0}^{n}\theta_ix_i = \theta^Tx hθ(x)=i=0∑nθixi=θTx
将 θ0\theta_0θ0 构造成 θ0x0\theta_0 x_0θ0x0,且 x0x_0x0 恒为1
即,特征矩阵(x)可以转化为:
x0x1…xn1x11…x1n1x21…x2n⋮⋮⋮⋮ \begin{matrix} x_0 & x_1 & \dots & x_n \\ 1 & x_{11}& \dots & x_{1n} \\ 1 & x_{21}& \dots & x_{2n} \\ \vdots &\vdots &\vdots &\vdots \end{matrix} x011⋮x1x11x21⋮………⋮xnx1nx2n⋮
误差项的定义
通过线性回归方程的计算,可以得到一个预测值
为了衡量预测值的准确性,因此要定义误差,即真实值与预测值之间的差异
因此对于每个样本:
err(i)=y(i)−θTx(i) err^{(i)} = y^{(i)} - \theta^Tx^{(i)} err(i)=y(i)−θTx(i)
从而,可以得到机器学习的定义:
给定数据data,给定一个目标函数(损失函数),使得我们的模型去学习如何分配一些参数,从而达到目标(损失函数最小)
一般而言,在机器学习中,误差err(i)err^{(i)}err(i)是独立并且具有相同的分布,都服从于均值为000方差为 θ\thetaθ 的高斯分布
将该性质推广到样本,即:
-
样本之间必须是相互独立的,这是前提
-
样本要求同分布
-
高斯分布,即正态分布,大多数样本的数据符合正常情况,极少数的数据较为极端
似然函数
似然函数取得最大值表示相应的参数能够使得统计模型最为合理。

从而得到似然函数与对数似然

注:
我们关注的是似然函数的最大值(极大值)所对应的最大值点(极大值),即对应的 θ\thetaθ ,而不是似然函数的最大(极大)值
将似然函数展开化简,得:

因此,我们的目标转化为:让似然函数越大越好(减号后项越小越好)
即,使得下式J(θ)J(\theta)J(θ)最小
J(θ)=12∑i=1m(y(i)−θTx(i))2 J(\theta) = \frac{1}{2}\sum_{i=1}^{m}(y^{(i)} - \theta^Tx^{(i)})^2 J(θ)=21i=1∑m(y(i)−θTx(i))2
最小二乘法求解参数
公式推导:
将J(θ)J(\theta)J(θ)展开,为了求得极小值,因此对 θ\thetaθ 求偏导,且令偏导为0,最终可以得到
θ=(XTX)−1XTy \theta = (X^TX)^{-1}X^Ty θ=(XTX)−1XTy
关键问题
XTXX^TXXTX在很多条件下是不可逆得,因此不适用最小二乘法
梯度下降
通过计算损失函数losslossloss的梯度,沿着其反方向,找到losslossloss降低最快的方向,进行参数更新
相当于下山问题:每次沿着坡度最大的方向进行下山,可以在最短时间内到达山谷最低点
基本步骤:
- 找到合适的方向,即每次沿着梯度的反方向更新
- 选择合适的步长(学习率),不宜过大也不宜过小
- 按照方向与步伐去更新我们的参数(对每个参数分别进行更新)
批量梯度下降
每次对更新参数时考虑所有样本,容易得到最优解,但速度较慢
∂J(θ)∂θj=−1m∑i=1m(yi−hθ(xi))xji \frac{\partial J(\theta)}{\partial \theta_j} = -\frac{1}{m}\sum_{i=1}^{m}(y^i - h_{\theta}(x^i))x_j^i ∂θj∂J(θ)=−m1i=1∑m(yi−hθ(xi))xji
θj=θj+α1m∑i=1m(yi−hθ(xi))xji \theta _j = \theta_j + \alpha\frac{1}{m}\sum_{i=1}^{m}(y^i - h_{\theta}(x^i))x_j^i θj=θj+αm1i=1∑m(yi−hθ(xi))xji
随机梯度下降
每次随机找一个样本,进行更新参数,迭代速度较快,单不一定每次都朝着收敛的方向
θj=θj+α(yi−hθ(xi))xji \theta _j = \theta_j + \alpha(y^i - h_{\theta}(x^i))x_j^i θj=θj+α(yi−hθ(xi))xji
小批量梯度下降
随机梯度下降与批量梯度下降的综合,每次更新拿一小部分数据(batchbatchbatch)来算,比较实用
θj=θj+α1batch∑k=ii+batch(y(k)−hθ(x(k)))xj(k) \theta _j = \theta_j + \alpha\frac{1}{batch}\sum_{k=i}^{i+batch}(y^{(k)} - h_{\theta}(x^{(k)}))x_j^{(k)} θj=θj+αbatch1k=i∑i+batch(y(k)−hθ(x(k)))xj(k)
超参数的选择:
- batchbatchbatch一般选择64、128、256…
- 学习率 α\alphaα 一般选择 0.01、0.001
代码实现
整体流程
- 数据预处理——归一化、标准化
- 利用梯度下降算法迭代训练模型,求解参数值
- 定义losslossloss
- 预测模型
线性回归代码LinearRegression.py
import numpy as np
from utils.features import prepare_for_training
class LinearRegression:
'''
线性回归模型
'''
def __init__(self, data, labels, polynomial_degress=0,sinusoid_degree=0, normalize_data=True):
'''
:param data: 数据
:param labels: 标签
:param polynomial_degress: 是否要对数据进行一些额外变换
:param sinusoid_degree: 数据的非线性变换
:param normalize_data: 是否进行初始化 默认为是
'''
## 数据预处理
(data_processed, features_mean, features_deviation) = prepare_for_training(data,
polynomial_degress,
sinusoid_degree)
self.data = data_processed
self.labels = labels
self.features_mean = features_mean
self.features_deviation = features_deviation
self.polynomial_degress = polynomial_degress
self.sinusoid_degree = sinusoid_degree
self.normalize_data = normalize_data
## 构造参数
num_features = self.data.shape[1]
self.theta = np.zeros((num_features, 1)) # 列向量
def train(self, alpha, num_iterations = 500):
'''
模型训练——num_iterations次梯度下降
:param alpha: 学习率
:param num_iterations: 迭代次数
:return:
'''
cost_history = self.gradient_descent(alpha, num_iterations)
return self.theta, cost_history
def gradient_descent(self, alpha, num_iterations):
'''
梯度下降
:param alpha: 学习率
:param num_iterations: 迭代次数
:return: 每一步的损失
'''
cost_history = [] #记录每一步的损失
for _ in range(num_iterations):
self.gradient_step(alpha)
cost_history.append(self.cost_function(self.data, self.labels))
return cost_history
def gradient_step(self, alpha):
'''
每一步梯度下降的计算
:param alpha: 学习率
:return:
'''
num_examples = self.data.shape[0]
prediction = LinearRegression.hypothesis(self.data, self.theta)
delta = prediction - self.labels
# 注意要把 delta 转置后在与self.data做dot
new_theta = self.theta - alpha*(1 / num_examples)*(np.dot(delta.T, self.data)).T
self.theta = new_theta #更新参数
@staticmethod # 定义成静态 不会传递self数据
def hypothesis(data, theta):
'''
预测函数
:param theta: 参数
:return: 预测值
'''
prediction = np.dot(data, theta)
return prediction
def cost_function(self, data, labels):
num_examples = data.shape[0]
delta = LinearRegression.hypothesis(data, self.theta) - labels
cost = (1/2)*np.dot(delta.T, delta) # 矩阵的平方
print(cost.shape)
return cost[0][0] # ???
def get_cost(self, data, labels):
'''
获得误差 用于测试阶段
要先对data进行预处理
'''
data_processed= prepare_for_training(data,
self.polynomial_degress,
self.sinusoid_degree)[0] #只需要获得data值 因此加上[0]
return self.cost_function(data_processed, labels)
def predict(self, data):
'''
预测 用于测试阶段 用训练好的模型得到回归结果
要先对data进行预处理
'''
data_processed = prepare_for_training(data,
self.polynomial_degress,
self.sinusoid_degree)[0] # 只需要获得data值 因此加上[0]
return self.hypothesis(data_processed, self.theta)
测试部分 test.py
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from LinearRegression import LinearRegression
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
########## 数据读取与处理 ##########
data = pd.read_csv('./data/world-happiness-report-2017.csv')
## 划分训练测试集
train_data = data.sample(frac=0.8) # 指定训练集占80%
test_data = data.drop(train_data.index)
input_param_name = 'Economy..GDP.per.Capita.'
output_param_name = 'Happiness.Score'
# 注意
x_train = train_data[[input_param_name]].values
y_train = train_data[[output_param_name]].values
x_test = test_data[[input_param_name]].values
y_test = test_data[[output_param_name]].values
## 数据展示
plt.scatter(x_train, y_train, label='Train_data')
plt.scatter(x_test, y_test, label='Test_data')
plt.xlabel(input_param_name)
plt.ylabel(output_param_name)
plt.legend()
plt.show()
########## 模型训练 ##########
## 参数初始化
num_iterations = 500
learning_rate = 0.01
linear_model = LinearRegression(x_train, y_train)
[theta, cost_history] = linear_model.train(learning_rate, num_iterations)
print('开始时的损失:', cost_history[0])
print('训练后的损失', cost_history[-1])
plt.plot(range(num_iterations), cost_history)
plt.xlabel('迭代次数')
plt.ylabel('损失loss')
plt.show()
########## 模型测试 ##########
y_prediction = linear_model.predict(x_test)
## 结果展示
plt.scatter(x_train, y_train, label='Train_data')
plt.scatter(x_test, y_test, label='Test_data')
plt.plot(x_test, y_prediction, 'r', label='Prediction')
plt.xlabel(input_param_name)
plt.ylabel(output_param_name)
plt.legend()
plt.show()
预测结果


更多推荐





所有评论(0)