多元线性回归-梯度下降法 c++

线性回归(Linear Regression)

假设线性回归方程如下:

h ( x ) = h θ ( x ) = θ 0 + θ 1 x + + θ 2 x h(x)=h_\theta(x)=\theta_0+\theta_1x++\theta_2x h(x)=hθ(x)=θ0+θ1x++θ2x

损失函数(Loss Function)

损失函数,表达式如下:
J ( θ ) = 1 2 ∑ i = 0 m ( h θ ( x i ) − y i ) 2 J(\theta) = \frac{1}{2}\sum_{i=0}^{m}(h_\theta(x^i)-y^i)^2 J(θ)=21i=0m(hθ(xi)yi)2
目标为求解最优的 θ \theta θ,使损失函数 J ( θ ) J(\theta) J(θ)取最小值。

梯度下降(gradient descent)

批梯度下降(batch gradient descent)

处理一个样本的表达式:
θ j : = θ j + α ( y i − ( h θ ( x i ) ) x j i \theta_j:=\theta_j+\alpha(y^i-(h_\theta(x^i))x_j^i θj:=θj+α(yi(hθ(xi))xji
转化为处理多个样本:
Repeat until convergence{
θ j : = θ j + α ∑ i = 1 m ( y i − ( h θ ( x i ) ) x j i \theta_j:=\theta_j+\alpha\sum_{i=1}^{m}(y^i-(h_\theta(x^i))x_j^i θj:=θj+αi=1m(yi(hθ(xi))xji
}
α -步长(learning rate),控制θ每次向J(θ)变小的方向迭代时的变化幅度

在表达式中每一步都是计算的全部训练集的数据,所以称之为批梯度下降(batch gradient descent)。
注意,梯度下降可能得到局部最优,但在优化问题里已经证明线性回归只有一个最优点,因为损失函数J(θ)是一个二次的凸函数,不会产生局部最优的情况。(假设学习步长α不是特别大)

随机梯度下降(Stochastic Gradient Descent, SGD)

随机梯度下降在计算下降最快的方向时时随机选一个数据进行计算,而不是扫描全部训练数据集,这样就加快了迭代速度。随机梯度下降并不是沿着J(θ)下降最快的方向收敛,而是震荡的方式趋向极小点。

Loop {
for i=i to m {
θ j : = θ j + α ( y i − ( h θ ( x i ) ) x j i \theta_j:=\theta_j+\alpha(y^i-(h_\theta(x^i))x_j^i θj:=θj+α(yi(hθ(xi))xji
}
}

代码片段如下:

linear_regression.h 代码片.

// 利用批梯度下降算法求解线性回归 
#include <iostream>
#include <stdio.h>
#include <math.h>

using namespace std;

double predict(double* w, double* data, int feature_num);
// 损失函数
double Theta(double **training_set, int featue_num, int training_num, double* w);
// 批梯度下降
void gradient_descent(double** training_set, int feature_num, int training_num, double* w, double a, int iterator_time);
// 特征归一化
void feature_normalize(double **feature_set, int feature_num, int training_num);
// 测试模型预测误差
void forecast(double *forecast_set, double* w, int featue_num);

linear_regression.cpp 代码片.

#include "pch.h"
#include "gradient_descent.h"

double predict(double* w, double* data, int feature_num) {
	double sum = 0;
	for (int i = 0; i < feature_num; i++) {
		sum += w[i] * data[i];
	}
	return sum;
}

double Theta(double **training_set, int featue_num, int training_num, double* w) {
	double sum = 0;
	for (int i = 0; i < training_num; i++) {
		sum += (training_set[i][featue_num] - predict(w, training_set[i], featue_num))*(training_set[i][featue_num] - predict(w, training_set[i], featue_num));
	}
	return sum / (2 * training_num);
}

void gradient_descent(double** training_set, int feature_num, int training_num, double* w, double a, int iterator_time) {
	while (iterator_time--) {
		double* del_theta = new double[feature_num];
		for (int i = 0; i < feature_num; i++) {
			del_theta[i] = 0;
			for (int j = 0; j < training_num; j++) {
				del_theta[i] += (predict(w, training_set[j], feature_num) - training_set[j][feature_num])*training_set[j][i];
			}
		}
		//w[i]的更新必须等所有的del_theta测算出来了才可以!不然更新的会影响没更新的
		//上述问题在代码内表示即是下面的for循环不能和上面的合并!
		for (int i = 0; i < feature_num; i++)
			w[i] -= a * del_theta[i] / (double)training_num;
		//printf("%.3lf\n", Theta(training_set, feature_num, training_num, w));
		delete[] del_theta;
	}
	printf("计算结果:\n");
	for (int i = 0; i < feature_num - 1; i++) {
		printf("%.3lf ", w[i]);
	}
	printf("%.3lf\n", w[feature_num - 1]);
	return;
}

void forecast(double *forecast_set, double* w, int feature_num) {
	double y=w[0];
	for (int i = 1; i < feature_num - 1; i++) {
		printf("%.3lf ", w[i]);
		printf("\t%.3lf\n ", forecast_set[i]);
		y = y + w[i] * forecast_set[i];
	}
	printf("------------------------------------------\n");
	printf("预测值: %.3lf\n", y);
	printf("实际值: %.3lf\n", forecast_set[feature_num]);
	printf("误差: %.3lf%%\n", fabs(y - forecast_set[feature_num])*100/y);
}


void feature_normalize(double **feature_set, int feature_num, int training_num) {
	//特征归一化
	// 对于某个特征 x(i)=(x(i)-average(X))/standard_devistion(X)
	// 1、求出特征X在n个样本中的平均值average(X)
	// 2、求出特征X在n个样本中的标准差 standard_devistion(X)
	// 3、对特征X的n个样本中的每个值x(i),使用上述公式进行归一化
	double *average = new double[feature_num];
	double  *stanrd_divition = new double[feature_num];
	for (int i = 1; i < feature_num; i++) {
		double sum = 0;
		for (int j = 0; j < training_num; j++) {
			sum += feature_set[j][i];
		}
		average[i] = sum / training_num;
	}
	for (int i = 1; i < feature_num; i++) {
		double sum = 0;
		for (int j = 0; j < training_num; j++) {
			sum += (feature_set[j][i] - average[i])*(feature_set[j][i] - average[i]);
		}
		stanrd_divition[i] = sqrt((sum / (training_num - 1)));
	}
	for (int i = 1; i < feature_num; i++)
		for (int j = 0; j < training_num; j++) {
			feature_set[j][i] = (feature_set[j][i] - average[i]) / (double)stanrd_divition[i];
		}
	delete[] stanrd_divition;
	delete[] average;
}
  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 梯度下降法是一种优化算法,常用于求解多元回归问题。在多元回归中,我们希望找到一组系数,使得回归模型的预测值与真实值之间的误差最小化。 梯度下降法的基本思想是通过反复迭代更新系数,使得每次更新后的系数能够减少误差。具体而言,梯度下降法通过计算误差函数对各个系数的偏导数(梯度),并以负梯度的方向进行更新。 在多元回归中,我们可以定义误差函数为平方误差的平均值,即均方误差(MSE)。梯度下降法的迭代步骤如下: 1. 初始化系数。可以随机初始化系数或者使用某种启发式方法。 2. 计算梯度。利用已知样本的特征和真实值计算误差函数对各个系数的偏导数。 3. 更新系数。按照负梯度的方向,更新每个系数,使得误差函数减少。 4. 检查停止条件。可以设置一个阈值,当系数更新的幅度小于该阈值时,认为已经收敛,停止迭代。 5. 重复步骤2-4,直到满足停止条件。 梯度下降法具有一定的收敛性和全局最优性,但同时也存在一些问题,如局部极值点、学习率选择等。因此,在使用梯度下降法求解多元回归问题时,需要根据具体情况选择合适的学习率和停止条件,以及进行多次试验和调优,以获得更好的回归模型。 ### 回答2: 梯度下降法可以用于求解多元回归问题。多元回归问题是指有多个自变量与一个因变量之间的关系,需要通过找到最优的参数来拟合这个关系。 在梯度下降法中,首先需要选择一个初始的参数向量,然后通过不断更新参数向量来逼近最优解。具体步骤如下: 1. 初始化参数向量:选择一组初始的参数向量,可以随机选择或者根据经验来定。 2. 计算预测值:根据当前的参数向量,计算模型的预测值。 3. 计算误差:将预测值与实际值之间的差异计算出来,即计算误差。 4. 计算梯度:计算误差对于每个参数的偏导数,得到梯度向量。 5. 更新参数:根据学习率和梯度向量,更新参数向量。 6. 重复2-5步骤:重复计算预测值、误差、梯度和参数更新的步骤,直到达到指定的停止条件(如迭代次数或误差的收敛)。 梯度下降法的优点是能够通过不断迭代来逐渐优化参数向量,找到最优解。同时,它也可以应用于非线性的多元回归问题。但是,梯度下降法也有一些限制,例如可能会陷入局部最优解,需要选择合适的学习率来控制参数更新的速度,以及可能需要花费较长的时间来找到最优解。 总而言之,梯度下降法是一种求解多元回归问题的常用方法,通过不断地迭代和参数更新,可以逐渐优化参数向量,找到最优解。 ### 回答3: 梯度下降法是一种常用的优化算法,用于求解多元回归问题。在多元回归中,我们试图找到一组参数,使得给定的输入变量与输出变量之间的预测误差最小化。 梯度下降法的基本思想是通过反复迭代来调整参数,以使预测误差逐渐减小。在每一次迭代中,根据误差函数关于参数的导数信息来更新参数的值,以使误差函数下降的方向对应的参数调整方向。 具体而言,对于多元回归问题,我们设定一个误差函数,常用的是均方误差函数。我们通过计算误差函数关于参数的偏导数,得到梯度信息。然后,根据梯度信息来更新参数的值,使用学习率来控制每一次迭代中参数更新的幅度。 在每一次迭代中,我们计算当前参数设置下的误差,并根据梯度信息和学习率来调整参数。我们重复这个过程,直到达到预定的停止条件,比如误差下降到一个较小的阈值,或是达到一定的迭代次数。 值得注意的是,梯度下降法的求解过程可能会受到局部最优解的影响,即最终可能只找到了一个局部最优解,而非全局最优解。因此,在实际应用中,我们通常需要进行多次运行,并选择最优的结果。 综上所述,梯度下降法是一种常用的求解多元回归问题的优化算法,通过迭代调整参数来减小预测误差。它的优点是简单易懂、易于实现,但需要选择适当的学习率和停止条件,以及注意局部最优解的问题。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值