機器學習(二):線性迴歸淺談

定義:

線性迴歸:用一條直線較爲準備的描述數據 之間的關係(注:通過屬性的線性組合來進行預測的線性模型,找到一條直線或者一個 平面,使得預測值與真實值之間的誤差最小,常見於房價的預測)

特點:

計算熵不復雜,但是對非線性的擬合併不好注:(建模速度快,不需要很複雜的計算,在數據量大的情況下依然運行速度很快。可以根據係數給出每個變量的理解和解釋。對異常值很敏感。)

問題:

假定現有一個房價數據集,怎末根據已有的數據集推測未來的房價走向

首先這是一個迴歸問題,而回歸問題分爲兩個過程:學習和預測

採用github現有的數據集,採用之前看過的一個博客的求解方式進行求解

https://github.com/rieuse/Machine_Learning/blob/master/House_Regression/house_price.csv

假定變量如下:

m代表訓練集中樣本的數量

x代表輸入變量

y代表輸出變量

(x,y)代表訓練集中的樣本

代表第i個樣本,如上述房價中的一個數據,輸入x(1)表示:(rooms:2,halls:1,size:50),輸出y(0)表示:price:170

代表第i個樣本的第j個分量,舉房價數據爲參考,表示第一個數據樣本中的halls字段,即=1

房價預測問題,實際上就是通過大量的訓練數據來訓練模型,最終得到預測函數Y=f(X)。然後我們將要預測的房子的rooms、halls、size作爲輸入變量,然後通過學習得到的預測函數f(X)得到輸出變量爲結果。這裏我們假設放假的預測函數爲:分別代表rooms、halls和size三個變量,所以這裏的問題就變成了求解四個參數,找到符合的預測函數。

此時我們已經假定了預測函數爲,那麼我們該如何判定函數解出的參數解是正確的呢?

這裏我們就需要引入代價函數:

1>代價函數:

定義在整個訓練集上的,是所有樣本誤差的平均,也就是損失函數的平均。

代價函數越小,並表示這份數據擬合的越好

注:損失函數:是定義在單個樣本上的,算的是一個樣本的誤差。

通過預測函數得到的預測值f(x)和實際的值y是可能存在一定誤差的,而我們要做的是就是縮小這些誤差。下面我們構建一個代價函數,這個函數是所有建模誤差的平方和,即:

        其中。所以,我們的目標就是找出使得代價函數最小的一系列參數變量,代價函數返回的值越小,說明預測函數越擬合數據,當然也可能出現過擬合的情況。,爲何得到這個代價函數最小的參數變量,我們就需要再次引入梯度下降算法。

2>梯度下降:

可以將代價函數最小化的算法,梯度下降算法。相應地梯度上升算法是用來求函數局部最大值的算法

上式的代價函數展開,即:

求導後得到:

這裏,對求導後,分別爲:

下面,我們對梯度下降算法做個整理:

在上式中α稱爲學習率,也叫步長,它決定了在梯度下降的迭代過程中,每一步沿梯度負方向前進的長度。以上圖的例子,學習率就是這一步所在位置沿着最陡峭的最易下山的位置走的那一步的長度。學習率如果取值太小,會導致收斂變慢,迭代次數變多;取值太大,則會導致波動較大,導致無法收斂。同時,該算法要對所有的θ參數變量進行求導過程。

用更簡潔的矩陣方式來描述梯度下降算法:

首先約定如下幾個矩陣形式:

令:

綜合起來:

所以,採用矩陣形式表示梯度下降後,θ更新步驟如下,通過這個公式,我們就可以通過pandas和numpy更簡潔地實現代碼。

備註:這裏θ是nx1矩陣,x是mxn矩陣,y是mx1矩陣

3>代碼實現:

1:預測函數:

解析:

def model(theta(參數矩陣), X(輸入變量矩陣)):

return X.dot(theta)(輸出變量)

        備註:上述公式x是nx1矩陣,θ是nx1矩陣,即代表一個數據實例的計算結果

        上式是對一個數據實例的計算結果,如果要對所有m個訓練集實例進行矩陣運算,可以採用下述公式:

        備註:上述公式x是mxn矩陣,θ是nx1矩陣,即對所有訓練集的數據實例的計算結果

(2)代價函數

def cost(m, theta, X, y):
    """
    代價函數
    :param m: 訓練集個數
    :param theta: 參數矩陣(mx1)
    :param X: 輸入變量矩陣(mx1)
    :param y: 輸出變量矩陣(mx1)
    :return:
    """
    ele = model(theta, X) - y
    item = ele ** 2
    item_sum = np.sum(item)
    return item_sum / (2 * m)


(3)梯度下降和θ參數更新

在前幾節中,我們推到了上述公式,如下:

def derivative(m, theta, X, y, n):
    """
    對各個theta參數求導
    :param m: 訓練集個數
    :param theta: 參數矩陣(nx1)
    :param X: 輸入變量矩陣(mxn)
    :param y: 輸出變量矩陣(mx1)
    :param n: 𝜃變量個數𝜃0, 𝜃1, 𝜃2, ..., 𝜃n-1
    :return: nx1 矩陣
    """
    grad_theta = []
    for j in range(n):
        # 對所有𝜃j變量求導
        grad = (model(theta, X) - y).T.dot(X[:, j])
        grad_sum = np.sum(grad)
        grad_theta.append(grad_sum / m)
    return np.array(grad_theta).reshape(n, 1)

 

當然如果採用向量形式,代碼會更簡潔,在上面的章節中,我們推導出瞭如下的向量表達形式:

def derivative(m, theta, X, y, n):
    """
    對各個theta參數求導(向量形式)
    :param m: 訓練集個數
    :param theta: 參數矩陣(nx1)
    :param X: 輸入變量矩陣(mxn)
    :param y: 輸出變量矩陣(mx1)
    :param n: 𝜃變量個數𝜃0, 𝜃1, 𝜃2, ..., 𝜃n-1
    :return: nx1 矩陣
    """
    grad_sum = X.T.dot(model(theta, X) - y)
    return grad_sum / m

對比下兩個代碼,明顯向量形式的更簡潔、更容易理解。

def gradient(grade_theta, theta, alpha):
    """
    𝜃更新
    :param grade_theta:求導後的𝜃矩陣(nx1)
    :param theta: 更新後的𝜃矩陣(nx1)
    :param alpha: 學習率
    :return: 返回更新後的𝜃矩陣(nx1)
    """
    return theta - alpha * grade_theta


(4)停止迭代策略(代價函數小於閾值或設定迭代次數)

def stop_strage(cost, cost_update, threshold):
    """
    停止迭代條件
    :param cost:
    :param cost_update:
    :param threshold:
    :return:
    """
    return (cost >= cost_update) and (cost - cost_update < threshold)


(5)線性迴歸

def linear_regression(X, y):
    """
    線性迴歸模型
    :param X: 輸入變量矩陣(mxn)
    :param y: 輸出變量矩陣(mx1)
    :param threshold:
    :return:
    """
    start = time.clock()
    m = X.shape[0] # 樣本個數
    n = X.shape[1]
    theta = np.zeros(n).reshape(n, 1) # 設置權重參數的初始值
    y = y.reshape(m, 1)
    print "theta:", theta.shape, ", X: ", X.shape, "y:", y.shape

    cost_record = [] # 記錄代價函數的值
    alpha = 0.0001 # 學習率
    threshold = 0.01
    cost_val = cost(m, theta, X, y)

    cost_record.append(cost_val)

    iters = 0
    while True:
        grad = derivative(m, theta, X, y, n)
        # 權重參數更新
        theta = gradient(grad, theta, alpha)
        cost_update = cost(m, theta, X, y)
        if stop_strage(cost_val, cost_update, threshold):
            break
        cost_val = cost_update
        cost_record.append(cost_val)
        iters += 1
    end = time.clock()
    print("cost time: %f s" % (end - start))

    return cost_record, theta, iters

(6)使用訓練線性迴歸模型預測房價

df = pd.read_csv('house_price.csv')

print df['rooms'].unique()
print df['halls'].unique()

# 去除髒數據
keep_index = (df['rooms'] != '多') & (df['halls'] != '多')
df = df[keep_index]

# 轉換數據類型
df['rooms'] = df['rooms'].astype('int')
df['halls'] = df['halls'].astype('int')

# 截取rooms、halls、size和price
X = df[['rooms', 'halls', 'size']]
y = df['price']

cost_record, theta, iters = linear_regression(X.values, y.values)
print iters
print theta
print cost_record

# 預測數據
# rooms,halls,size,price
# 1,1,49,326
# 2,1,56.45,315
# 2,1,58.3,466
# 3,1,92.33,1061
# 2,1,76.88,408

print model(theta, np.array([1, 1, 49]))
print model(theta, np.array([2, 1, 56.45]))
print model(theta, np.array([2, 1, 58.3]))
print model(theta, np.array([3, 1, 92.33]))
print model(theta, np.array([2, 1, 76.88]))

再來看下代價函數返回的值的收斂趨勢圖:

# 第一個數據太大,剔除,方便觀察對比
plt.plot(np.arange(len(cost_record)-1), cost_record[1:], 'r')
plt.show()

 注:以上內容參考他人博客太多,個人見解還需後續補充修改

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