均值归一化(mean normalization)
除了在特征缩放中将特征除以最大值以外,有时候我们也会进行一个称为均值归一化(mean normalization)的工作。
具体做法就是:如果你有一个特征xixi你就用xi−μixi−μi来替换。这样做的目的是为了让你的特征值具有为0的平均值。很明显 我们不需要把这一步应用到x0中,因为x0x0中,因为x0总是等于1的,所以它不可能有为0的的平均值。
但是对其他的特征来说,比如房子的大小取值介于0 ~ 2000,并且假如房子面积的平均值是等于1000的,那么你可以用这个公式
x1=size−10002000x1=size−10002000
类似地,如果你的房子有五间卧室,并且平均一套房子有两间卧室,那么你可以使用这个公式来归一化你的第二个特征x2:
x2=卧室数−25x2=卧室数−25
在这两种情况下你可以算出新的特征x1和x2x1和x2,它们的范围可以在-0.5 ~ +0.5之间,当然这肯定不对,x2的值实际上肯定会大于0.5。更一般的规律是用:
xn−μnSnxn−μnSn, , μn为平均值μn为平均值, , Sn为最大值−最小值Sn为最大值−最小值
来替换原来的特征xnxn。其中定义μn的意思是在训练集中特征xnxn的平均值。而SnSn是该特征值的范围(最大值减去最小值)。
最后直的一提的是:特征缩放其实并不需要太精确,其目的只是为了让梯度下降能够运行得更快一点,让梯度下降收敛所需的循环次数更少一些而已。
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-10
double x[100][100]={{1,1,4},{1,2,5},{1,5,1},{1,4,2}};
double y[100]={19,26,19,20};
double theta[100]={0,0};
int m=4;
int n=2;
double learn_rate=0.1;
double error=100.0;
void p(){
for(int i=1;i<=n;i++){ //lie
double averagex=0.0;
double Maxx2=x[0][i],Minx2=x[0][i];
for(int j=0;j<m;j++){
averagex+=x[j][i];
Maxx2=max(Maxx2,x[j][i]);
Minx2=min(Minx2,x[j][i]);
}
averagex/=m;
//cout<<Maxx2<<" "<<Minx2<<" "<<averagex<<endl;
for(int j=0;j<m;j++){
x[j][i]=(x[j][i]-averagex)/(Maxx2-Minx2);
}
}
}
double get_hx(int index){
double ans=0.0;
for(int i=0;i<=n;i++) ans+=x[index][i]*theta[i];
return ans;
}
int main(){
double error1=0.0,error2=0.0;
// cout<<endl<<endl;
// cout<<"x0"<<" "<<"x1"<<" "<<"x2"<<" "<<"y"<<endl;
//
// for(int i=0;i<m;i++){
// for(int j=0;j<=n;j++){
// cout<<x[i][j]<<" ";
// }
// cout<<y[i];
// cout<<endl;
// }
// cout<<endl<<endl;
p();
// cout<<"x0"<<" "<<"x1"<<" "<<"x2"<<" "<<"y"<<endl;
// for(int i=0;i<m;i++){
// for(int j=0;j<=n;j++){
// printf("%.2f ",x[i][j]);
// }
// cout<<y[i];
// cout<<endl;
// }
// cout<<endl<<endl;
//
//
// return 0;
while(true){
for(int i=0;i<m;i++){
double h_x=get_hx(i);
for(int j=0;j<=n;j++){
theta[j]+=(y[i]-h_x)*learn_rate*x[i][j]/m;
}
}
for(int i=0;i<=n;i++) cout<<theta[i]<<" ";
cout<<endl;
//找出最小的值,即与上一次的结果相差小于eps
error1=0.0;
for(int i=0;i<m;i++){
error1+=((y[i]-get_hx(i))/m)*(y[i]-get_hx(i))/2;
}
if(abs(error1-error2)<eps) break;
else error2=error1;
}
return 0;
}