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.運行結果:
數據很大程度上影響了擬合的效果,不過就我的這些數據至少已經能展示出一般的規律了 :)
比如:距離市中心的距離與房價成反比; 房屋使用時間與房價成反比等等。
設想若數據量足夠大,足夠真實,那麼應當可以得到一個很具有現實意義的預測函數。
與這個問題同理,還有許多問題都可以被梯度下降算法預測,只是未知量的個數問題。