梯度下降推廣:多元線性迴歸(學習速率掌控) ----預測房價


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 θ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.運行結果:
這裏寫圖片描述

數據很大程度上影響了擬合的效果,不過就我的這些數據至少已經能展示出一般的規律了 :)
比如:距離市中心的距離與房價成反比; 房屋使用時間與房價成反比等等。

設想若數據量足夠大,足夠真實,那麼應當可以得到一個很具有現實意義的預測函數。


與這個問題同理,還有許多問題都可以被梯度下降算法預測,只是未知量的個數問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章