线性回归( Linear Regression )是利用称为线性回归方程的最小平方函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析。这种函数是一个或多个称为回归系数的模型参数的线性组合。只有一个自变量的情况称为简单回归,大于一个自变量情况的叫做多元回归。
代数表示
结合平方误差和公式
假设根据特征的预测结果与实际结果有误差 ϵ(i) ,那么预测结果 θτx(i) 与真实结果 y(i) 满足:
y(i)=θτ∗x(i)+ϵ(i)
一般来讲,误差满足平均值为0的高斯分布,也就是正态分布。那么x和y的条件概率也就是:
p(y(i)|x(i);θ)=12π−−√σexp((y(i)−θτx(i))22σ2)
这样就估计了一条样本的结果概率,然而我们期待的是模型能够在全部样本上预测最准,也就是概率积最大。注意这里的概率积是概率密度函数积,连续函数的概率密度函数与离散值的概率函数不同。这个概率积成为最大似然估计。我们希望在最大似然估计得到最大值时确定θ。那么需要对最大似然估计公式求导,求导结果既是:
12Σmi=1(θτx(i)−y(i))2
这就解释了为何误差函数要使用平方和。当然推导过程中也做了一些假定,但这个假定符合客观规律。
代数表示
注: θ 为 n+1 维的列向量, X 为 (n+1)∗m 维的向量, Y 为 m+1 维的列向量。
通过训练找到使得 J(θ) 值最小的 θ .我们可以用梯度下降( gradient descent )法来求。
梯度下降法,就是利用负梯度方向来决定每次迭代的新的搜索方向,使得每次迭代能使待优化的目标函数逐步减小。
每次对代价函数求偏导,得到前进的方向,然后设定一个学习的速率 α ,使得代价函数的值往小的方向收敛。
代数公式:
function J = computeCostMulti(X, y, theta)
m = length(y); % number of training examples
J = 0;
predictions = X*theta; %假设函数的值
sqrterror = (predictions-y).^2; %平方误差
J=1/(2*m)*sum(sqrterror);
end
function [theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters)
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);
for iter = 1:num_iters
theta = theta - alpha/m*(X'*(X*theta-y));
J_history(iter) = computeCostMulti(X, y, theta);
end
end
房价预测
#include <bits/stdc++.h>
using namespace std;
typedef vector<double > vd;
struct data{
vd x;
double y;
data(){
x.clear();
y=0;
}
data(const vd &_x,const double &_y){
x=_x;
y=_y;
}
};
double H(vd x,vd thea)//hypothesis function
{
int len = thea.size();
double sum = 0;
for(int i=0;i<len;i++)
sum=sum+x[i]*thea[i];
return sum;
}
double getvalue(data dt[],vd thea,int n){//最小二乘得到方差
double sum = 0;
for(int i=0;i<n;i++){
double tmpsum = H(dt[i].x,thea);
sum+=(tmpsum-dt[i].y)*(tmpsum-dt[i].y);
}
return sum/2.0;
}
void gradient(data dt[],vd &thea,int n,double alpha)//梯度下降更新thea
{
int len = thea.size();
vd tmp;
for(int i=0;i<len;i++){
double tmpsum = 0;
for(int j=0;j<n;j++){
tmpsum = tmpsum + alpha*(H(dt[j].x,thea)-dt[j].y)*dt[j].x[i];
}
tmp.push_back(thea[i]-tmpsum);
}
thea = tmp;
}
void solve(data dt[],vd &thea,int n)//处理迭代
{
double alpha = 0.005;
double delta = 1e-6;
double pre = getvalue(dt,thea,n);
double now = 0;
while(abs(pre-now)>delta){
pre = now;
now = getvalue(dt,thea,n);
gradient(dt,thea,n,alpha);
}
}
int main()
{
int f,t,m,n;
while(~scanf("%d%d",&f,&n)){
data test[110];
for(int i=0;i<n;i++){
vd tmp;
double x;
tmp.push_back(1.0);
for(int i=0;i<f;i++){
scanf("%lf",&x);
tmp.push_back(x);
}
scanf("%lf",&x);
test[i]=data(tmp,x);
}
scanf("%d",&m);
data ans[110];
for(int i=0;i<m;i++){
vd tmp;
double x;
tmp.push_back(1.0);
for(int i=0;i<f;i++){
scanf("%lf",&x);
tmp.push_back(x);
}
ans[i]=data(tmp,0);
}
vd thea;
for(int i=0;i<=f;i++)
thea.push_back(0);
solve(test,thea,n);
for(int i=0;i<m;i++){
ans[i].y=H(ans[i].x,thea);
printf("%.2lf\n",ans[i].y);
}
}
return 0;
}