梯度下降推广:多元线性回归(学习速率掌控) ----预测房价


1.假设
一个房屋的出售价格y(千元/平方米)由:
(1)房屋距市中心的距离(km) x1
(2)房屋的大小(平方米)x2
(3)房屋所拥有的房间数x3
(4)房屋的已使用时间x4

这四个因素决定,那么根据训练集确定五个变量θ1 θ2 θ3 θ4 θ0,使得任一房屋的价格可由 y= θ0 + θ1*x1 + θ2*x2 + θ3*x3 + θ4*x4 预测。


2.分析:
要预测房屋价格,实际上是要对五个变量分别使用梯度下降,来找到使得误差函数J(θ) 最小的θ1 θ2 θ3 θ4 θ0 的组合。

这篇文章承接自我的上一篇有关梯度下降的文章:[初识:梯度下降算法 (Gradient Descent)]
在这篇博客中我通过对 x1 x2 (在这里应当对应的是 θ0 θ1 )两个变量进行梯度下降从而得到散点的最优直线拟合。在这里只是问题稍微复杂了一些,需要对五个变量进行梯度下降的处理,来得到最优的房价预测方程。


承接上篇博客,这里直接给出五个变量的梯度下降式子:
梯度下降推广:多元线性回归(学习速率掌控) ----预测房价_第1张图片


那么只需要根据这五个式子,就可以利用梯度下降算法得到最优的拟合方程。

然而,我在用代码实现了算法之后,却发现θ1 θ2 θ3 θ4 θ0 无法收敛,每次都运行到我指定的for循环最大次数后才退出。其时间消耗少则五分钟,多更至十多分钟,有时甚至根本无法得到结果(结果显示 not a number)。

但是,经过长时间的探索,终于发现问题竟出在了α的取值上。α 又称学习速率,决定了每一次θ1 θ2 θ3 θ4 θ0 改变幅度的大小,受之前那个拟合散点程序的影响,我这次开始的时候将α 设置的较大(0.1或0.01),或许是因此导致了θ1 θ2 θ3 θ4 θ0 中一部分变量的发散,从而导致循环跳出条件无法满足。
α 值调为0.0001后,五个变量得以迅速收敛,循环次数也由千万级别骤降至四百余次。

可以看到,过小的α有时会导致计算次数增多,增加消耗,有时却能拯救一个无法收敛的程序。可见,对于不同的训练集,α的取值相当灵活。


3.代码实现:

原理与上篇博客中的拟合散点大致相同

(1)给出训练集,学习速率,及有关变量
由于训练集数据过少,而且数据是自己编的,结论应该和实际没什么关系 :(

int Judge ;     //用于判断收敛

//自己脑补了15组数字 :)
double Train_set_x1[15] = {0.1, 0.7, 3, 5, 10, 1, 1, 1, 1, 1.1, 2, 2, 2, 2, 2};
double Train_set_x2[15] = {1, 1, 1, 1.1, 1, 2.1, 2.1, 2, 1.5, 1.52, 3, 4, 5, 7};
double Train_set_x3[15] = {2, 2, 2, 2, 2, 2, 2, 3, 4, 3, 2, 2, 2, 2, 2 };
double Train_set_x4[15] = {1, 1, 1, 1, 1, 2, 1, 0.1, 0.1, 51, 1, 1, 1, 1, 1};
double Train_set_y[15] = {7, 5, 4, 3.9, 3.2, 4.5, 5.2, 5.9, 5.8, 4.1, 5.0, 5.5, 5.7, 5.9, 6.5};
int j;
double m = 15;   //共十五组数据
double alpha = 0.0001;
double sum_0;    //用于进行求和运算
double sum_1;
double sum_2;
double sum_3;
double sum_4;
double theta_0 = 1;      //θ用theta代替
double theta_1 = 1;
double theta_2 = 1;
double theta_3 = 1;
double theta_4 = 1;

(2)进行梯度下降:

for (i = 0; i < 99999999; i++)   
    {
        sum_0 = 0;   //每次循环前初始化为0,用于计算和式
        sum_1 = 0;
        sum_2 = 0;
        sum_3 = 0;
        sum_4 = 0;

        for (j = 0; j <= 14; j++)   // for theta_0   先把和式全部计算出来
        {
            sum_0 += (theta_0 + theta_1*Train_set_x1[j] + theta_2*Train_set_x2[j] + theta_3*Train_set_x3[j] + theta_4 * Train_set_x4[j] - Train_set_y[j]);
        }

        for (k = 0; k <= 14; k++)   // for theta_1
        {
            sum_1 += (theta_0 + theta_1*Train_set_x1[k] + theta_2*Train_set_x2[k] + theta_3*Train_set_x3[k] + theta_4*Train_set_x4[k] - Train_set_y[k])*Train_set_x1[k];
        }

        for (t = 0; t <= 14; t++)   // for theta_2
        {
            sum_2 += (theta_0 + theta_1*Train_set_x1[t] + theta_2*Train_set_x2[t] + theta_3*Train_set_x3[t] + theta_4*Train_set_x4[t] - Train_set_y[t])*Train_set_x2[t];
        }

        for (n = 0; n <= 14; n++)   // for theta_3
        {
            sum_3 += (theta_0 + theta_1*Train_set_x1[n] + theta_2*Train_set_x2[n] + theta_3*Train_set_x3[n] + theta_4*Train_set_x4[n] - Train_set_y[n])*Train_set_x3[n];
        }

        for (g = 0; g <= 14; g++)   // for theta_4
        {
            sum_4 += (theta_0 + theta_1*Train_set_x1[g] + theta_2*Train_set_x2[g] + theta_3*Train_set_x3[g] + theta_4*Train_set_x4[g] - Train_set_y[g])*Train_set_x4[g];
        }

        temp_0 = theta_0 - alpha*(1 / m)*sum_0;   //梯度下降算法核心
        temp_1 = theta_1 - alpha*(1 / m)*sum_1;
        temp_2 = theta_2 - alpha*(1 / m)*sum_2;
        temp_3 = theta_3 - alpha*(1 / m)*sum_3;
        temp_4 = theta_4 - alpha*(1 / m)*sum_4;
        Judge = 0;
                                       //判断五个变量是否都已经收敛
        if (theta_0 == temp_0)  Judge++;
        if (theta_1 == temp_1)  Judge++;
        if (theta_2 == temp_2)  Judge++;
        if (theta_3 == temp_3)  Judge++;
        if (theta_4 == temp_4)  Judge++;
        if (Judge == 5) break;

        theta_0 = temp_0;       //更新五个变量的值
        theta_1 = temp_1;
        theta_2 = temp_2;
        theta_3 = temp_3;
        theta_4 = temp_4;

    }

4.运行结果:
梯度下降推广:多元线性回归(学习速率掌控) ----预测房价_第2张图片

数据很大程度上影响了拟合的效果,不过就我的这些数据至少已经能展示出一般的规律了 :)
比如:距离市中心的距离与房价成反比; 房屋使用时间与房价成反比等等。

设想若数据量足够大,足够真实,那么应当可以得到一个很具有现实意义的预测函数。


与这个问题同理,还有许多问题都可以被梯度下降算法预测,只是未知量的个数问题。

你可能感兴趣的:(C++算法,Machine,Learning)