從兩元線性迴歸到多元:數據預處理的重要性

在瞭解了一下梯度下降的原理之後,如下有一個程序實現了兩元的線性迴歸。按理說,那麼要寫多元線性迴歸,就是幾維都可以處理的,應該只需要改一部分代碼,多一個循環取值就可以了。但卻出現了損失值越來越大的情況。折騰了很久,後來發現,加一步數據預處理-數據規範化,問題就解決了。(0 。0)
先上一開始的代碼,可以求出有兩個自變量x0,x1時的線性方程的兩個未知參數theta0,theta1。

print "-------增量梯度下降(兩個未知數)---------"
# 自變量x(x0, x1)
# 假設函數爲:h(x) = theta0 * x[0] + theta1 * x[1]
# y爲理想theta值下的真實函數值
x = [(1, 1.15), (1, 1.9), (1, 3.06), (1, 4.66), (1, 6.84), (1, 7.95)]
y = [1.37, 2.4, 3.02, 3.06, 4.22, 5.42]
# 兩個終止條件:最大迭代次數,收斂精度
loop_max = 10000
epsilon = 0.0001

alpha = 0.005  # 步長
diff = 0  # 每一次測試時當前值與理想值的差距
error0 = 0  # 上一次目標函數之和
error1 = 0  # 當前次目標函數和
m = len(x)  # 訓練數據條數
count = 0  #
finish = 0  #

theta = [0, 0]  # 存放未知參數

while count < loop_max:
    count += 1
    # 遍歷訓練數據集,不斷更新theta
    for i in range(m):
        # 訓練集代入,計算假設函數值h(x)與真實值y的差距
        diff = theta[0] * x[i][0] + theta[1] * x[i][1] - y[i]
        # 求參數theta,增量梯度下降算法,每次只使用一組數據
        theta[0] = theta[0] - alpha * diff * x[i][0]
        theta[1] = theta[1] - alpha * diff * x[i][1]
        #cost_function是損失函數,可以打印出來做檢查,是否最後有所收斂。
        # for i in range(len(x)):
        #     cost_function = abs(theta[0]*x[i][0]+theta[0]*x[i][0]-y[i])
        # print 'cost_function=', cost_function
    # 當上面的循環結束時已遍歷了一遍訓練集,求出theta
    # 接下來判斷是否已經收斂
    if abs(theta[0] - error0) < epsilon and abs(theta[1] - error1) < epsilon:
        print 'theta:[%f, %f]' % (theta[0], theta[1]), 'error1: ', error1
        finish = 1
    else:
        error0, error1 = theta
    if finish:
        break
print 'FINISH count: %s' % count

如果有如下這麼一份數據,

1.86 23.71 23.95 0.23 28.4 858
2.12 24.52 23.92 0.25 27.2 963
2.17 25.32 24.42 0.26 26.8 1112
2.17 25.81 23.73 0.25 25.7 1366
2.2 26.41 24.7 0.3 27.1 1644
2.4 26.94 21.94 0.33 24.5 1893
2.58 27.46 19.77 0.34 21.8 2311
2.8 27.99 18.98 0.32 19.7 2998
。。。。

每一條數據有五元,(最後一行是實際結果),多維如何處理呢?只改其中部分代碼可以嗎?事實上,當我只是把其中諸如:
diff = theta[0] * x[i][0] + theta[1] * x[i][1] - y[i]

等多次進行修改,加多一層迭代的時候,輸出cost_function,卻得到了這樣的輸出結果:(部分)

187872.85
193631.42416
244661.535817
686493.44376



1.04409046398e+11
8.47052583941e+11
7.12289709856e+12


5.47441638474e+100
4.60034979459e+101
3.83394355995e+102

後面居然越滾越大!!OMG!!!
好了,中間痛苦的追尋過程就省略了,(一把心酸淚
T^T。。。。。。)這裏直接上最後加了一步數據規範化的代碼:

# -*-coding:utf-8 -*-
# 多元線性迴歸
matrix_A = []  # 多元數值[[x1,x2,x3..],[x1,x2,x3..],...[x1,..xn]]
Matrix_y = []  # 準確值[y1,y2,y3,..yn]
f = open('test.txt')
datalines = f.readlines()
for data in datalines:
    data = data.split()
    l = len(data)
    x = []
    for i in data[:l-1]:
        x.append(float(i))
    matrix_A.append(x)
    Matrix_y.append(float(data[l-1]))

def lineregression(matrix_X, matrix_Y, error,leraing_rate,iters=1000):

    now_iters = 1  # 計算量
    number = len(matrix_A)  # 總測試條數
    dim = len(matrix_A[0])  # 維度,爲每條測試的長度
    max_A = [0]* dim
    min_A =[0]* dim
    max_y =max(Matrix_y)
    min_y =min(Matrix_y)
    theta=[1]* dim  # 存放所求參數,初始化爲1
    bef_cf = -1  # 上一次的損失函數值
    now_cf = error  # 這一次的損失函數值
    for i in range(number):  # 先進行數據規範化
        for j in range(dim):
            if matrix_A[i][j] > max_A[j]: max_A[j] = matrix_A[i][j]
            if matrix_A[i][j] < min_A[j]: min_A[j] = matrix_A[i][j]
    for i in range(number):
        Matrix_y[i] = (Matrix_y[i]-min_y)/(max_y-min_y)
        for j in range(dim):
            matrix_A[i][j] = (matrix_A[i][j]-min_A[j])/(max_A[j]-min_A[j])


    while now_iters < iters and abs(now_cf-bef_cf) > error:
# 限制條件爲最大迭代次數iters,上一次與當前損失函數之差是否已經足夠小
        for i in range(number):
            h = [0] * number

            for j in range(dim):
                h[i] += theta[j] * matrix_A[i][j]  #
            for j in range(dim):  # 迭代更新參數
                theta[j] = theta[j] + leraing_rate * (Matrix_y[i]-h[i]) * matrix_A[i][j]
            cost_function = 0
            for i in range(number):
                cost_function += abs(h[i] - Matrix_y[i])
            print cost_function
            bef_cf = now_cf
            now_cf = cost_function
        now_iters = now_iters +1
    print 'theta=', theta
    return theta

lineregression(matrix_A,Matrix_y,0.01,0.005,100000)

這是結果:

10.1966685898
10.2259006252
10.2205934747
10.0847738914


6.60560406654
6.56520700864
6.44987263528


6.12707444834
6.12784301073
6.13783688284
theta= [0.0016302034449064047, 0.7329372810913097, 0.024466433622201224, 0.18546386097686593, -0.566741757743412]

損失函數值在收斂,且最後得出了結果。
那麼爲什麼會出現這種情況呢?
個人理解是這樣的哈,多元的時候,數據可能會比較多比較大,那麼個別過大或過小的數據對整體的影響就會很大,從而出現後面越滾越大的情況。而規範化幫我們把所有數字映射到一個區間,上述我的代碼是在0~1區間。這樣的話,數據差別就很小了,雪球纔不會越滾越大。
自我感覺這樣的解釋並不是很有力,但是代碼實現了,心中總算是有點安慰。如果大家有自己的看法,歡迎交流!!畢竟,我,還,是,好,小,的,一,只,菜,鳥:)
From now on, when we dealing with big data, machine learning and so on, we are suggested to pay more attention to
數據預處理:)
(包括去噪音,平滑,分箱,規範化等等,有興趣的可以自行百度谷歌瞭解)

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