1. 程式人生 > >python 機器學習 sklearn 廣義線性模型

python 機器學習 sklearn 廣義線性模型

廣義的線性模型是最最常用和我個人認為最重要的

  • 最小二乘

class sklearn.linear_model.LinearRegression(fit_intercept=Truenormalize=Falsecopy_X=Truen_jobs=1)

fit_intercept=True表示是否計算截距,就是最後的那個 Y=w1X1+w2X2+b的b,normalize表示是都需要標準化

from sklearn import linear_model
reg = linear_model.LinearRegression()
reg.fit ([[0, 0], [1, 1], [2, 2]], [0, 1, 2])
reg.coef_
  • 嶺迴歸

這是對上面的一個優化,\underset{w}{min\,} {|| X w - y||_2}^2 變成了\underset{w}{min\,} {{|| X w - y||_2}^2 + \alpha {||w||_2}^2}, \alpha \geq 0 是控制係數收縮量的複雜性引數: \alpha 的值越大,收縮量越大,這樣係數對共線性的魯棒性也更強

class sklearn.linear_model.Ridge(alpha=1.0fit_intercept=Truenormalize=Falsecopy_X=Truemax_iter=Nonetol=0.001solver='auto'random_state=None)

alpha就是公式上的alpha,正則話引數,後面幾個和最小二乘一樣

solver的選擇如下列表:{"auto","svd","cholesky","sparse_cg","lsqr","sag"}

'auto'根據資料型別自動選擇求解器;'svd'使用X的奇異值分解來計算嶺係數;'cholesky'使用標準的scipy.linalg.solve函式來獲得封閉形式的解決方案;'sparse_cg'使用scipy.sparse.linalg.cg中的共軛梯度求解器;'lsqr'使用專用的正則化最小二乘例程scipy.sparse.linalg.lsqr;'sag'使用隨機平均梯度下降

from sklearn.linear_model import Ridge
import numpy as np
n_samples, n_features = 10, 5
np.random.seed(0)
y = np.random.randn(n_samples)
X = np.random.randn(n_samples, n_features)
clf = Ridge(alpha=1.0)
clf.fit(X, y) 

對於有些矩陣,矩陣中某個元素的一個很小的變動,會引起最後計算結果誤差很大,這種矩陣稱為“病態矩陣”。有些時候不正確的計算方法也會使一個正常的矩陣在運算中表現出病態。對於高斯消去法來說,如果主元(即對角線上的元素)上的元素很小,在計算時就會表現出病態的特徵。

迴歸分析中常用的最小二乘法是一種無偏估計。對於一個適定問題,X通常是列滿秩的採用最小二乘法,定義損失函式為殘差的平方,最小化損失函式上述優化問題可以採用梯度下降法進行求解,也可以採用如下公式進行直接求解當X不是列滿秩時,或者某些列之間的線性相關性比較大時,  的行列式接近於0,即  接近於奇異,上述問題變為一個不適定問題,此時,計算時誤差會很大,傳統的最小二乘法缺乏穩定性與可靠性。為了解決上述問題,我們需要將不適定問題轉化為適定問題:我們為上述損失函式加上一個正則化項,變為其中,我們定義 ,於是:上式中, 是單位矩陣。隨著的增大, 各元素的絕對值均趨於不斷變小,它們相對於正確值的偏差也越來越大。趨於無窮大時,趨於0。其中, 隨  的改變而變化的軌跡,就稱為嶺跡。實際計算中可選非常多的值,做出一個嶺跡圖,看看這個圖在取哪個值的時候變穩定了,那就確定值了。

嶺迴歸是對最小二乘迴歸的一種補充,它損失了無偏性,來換取高的數值穩定性,從而得到較高的計算精度。

PS:奇異矩陣就是行列式=0;也代表著行列式的向量有線性相關;線性相關也就意味著最起碼有兩個向量式Y=AX+B的關係,也就是說有一行向量根本不起作用,也就是說在一個方陣中有M個變數,卻只有M-1個方程式,那麼根本解不了方程,既然解不了方程,你這個最小二乘的結果.....是不是有點....不對了,所以才出現了嶺迴歸。(個人理解)

所以在看到屬性式如下:工資,房產,......., [ label ] 這樣的資料,就不要用最小二乘擬合了,試試嶺迴歸,因為工資和房產有線性關係,感覺結果不如後者(個人感覺....沒有測試過);還有一種情況,就是一個屬性的值一直都很小很接近,比如0.000012,0.000011,0.000013;這樣的資料,我感覺這樣一來一條屬性就費了,那在一個方陣中有一個屬性不起作用,也就是一列都是0,方程也解不了啊,建議不要用最小二乘擬合。

線性迴歸 工作原理

讀入資料,將資料特徵x、特徵標籤y儲存在矩陣x、y中
驗證 x^Tx 矩陣是否可逆
使用最小二乘法求得 迴歸係數 w 的最佳估計

線性迴歸 開發流程

收集資料: 採用任意方法收集資料
準備資料: 迴歸需要數值型資料,標稱型資料將被轉換成二值型資料
分析資料: 繪出資料的視覺化二維圖將有助於對資料做出理解和分析,在採用縮減法求得新迴歸係數之後,可以將新擬合線繪在圖上作為對比
訓練演算法: 找到迴歸係數
測試演算法: 使用 R^2 或者預測值和資料的擬合度,來分析模型的效果
使用演算法: 使用迴歸,可以在給定輸入的時候預測出一個數值,這是對分類方法的提升,因為這樣可以預測連續型資料而不僅僅是離散的類別標籤

線性迴歸 演算法特點

優點:結果易於理解,計算上不復雜。
缺點:對非線性的資料擬合不好。
適用於資料型別:數值型和標稱型資料。

def loadDataSet(fileName):      #general function to parse tab -delimited floats
    numFeat = len(open(fileName).readline().split('\t')) - 1 #get number of fields 
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr =[]
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

#最小二乘擬合

def standRegres(xArr,yArr):
    xMat = mat(xArr); yMat = mat(yArr).T
    xTx = xMat.T*xMat
    if linalg.det(xTx) == 0.0:
        print "This matrix is singular, cannot do inverse"
        return
    ws = xTx.I * (xMat.T*yMat)
    return ws

#嶺迴歸

def ridgeRegres(xMat,yMat,lam=0.2):
    xTx = xMat.T*xMat
    denom = xTx + eye(shape(xMat)[1])*lam
    if linalg.det(denom) == 0.0:
        print "This matrix is singular, cannot do inverse"
        return
    ws = denom.I * (xMat.T*yMat)
    return ws
    
def ridgeTest(xArr,yArr):   # 因為alpha不同,效果不同所以可以看看不同的alpha對解過有什麼不一樣
    xMat = mat(xArr); yMat=mat(yArr).T
    yMean = mean(yMat,0)
    yMat = yMat - yMean     #to eliminate X0 take mean off of Y
    #regularize X's
    xMeans = mean(xMat,0)   #calc mean then subtract it off
    xVar = var(xMat,0)      #calc variance of Xi then divide by it
    xMat = (xMat - xMeans)/xVar
    numTestPts = 30
    wMat = zeros((numTestPts,shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegres(xMat,yMat,exp(i-10))
        wMat[i,:]=ws.T
    return wMat

  • Lasso迴歸(上面的嶺迴歸是二範數--最優化理論第一章講的就是範數)

class sklearn.linear_model.Lasso(alpha=1.0fit_intercept=Truenormalize=Falseprecompute=Falsecopy_X=Truemax_iter=1000tol=0.0001warm_start=Falsepositive=Falserandom_state=Noneselection='cyclic')

引數中有一個max_iter,最大迭代次數,因為Losso不是平方,是絕對值計算,所以不能直接求解,只能迭代求解

from sklearn import linear_model
clf = linear_model.Lasso(alpha=0.1)
clf.fit([[0,0], [1, 1], [2, 2]], [0, 1, 2])
print(clf.coef_)
print(clf.intercept_)

Lasso迴歸是Ridger迴歸發展的,如果有太多的特徵,可以用此方法

因為是線性,所以比非線性解算方便。但是L1範數的懲罰項,帶有絕對值,求導之後存在尖點,所以需要通過迭代演算法來進行求解,不能直接得到解析解。迭代求解方法:

(1)座標軸下降法

(2)最小角迴歸法(Least Angle Regression,LAR)

(3)前向選擇法(Forward Selection method)

(4)前向梯度法(Forward stagewise method)

逐步向前回歸模擬:
def stageWise(xArr,yArr,eps=0.01,numIt=100):
    xMat = mat(xArr); yMat=mat(yArr).T
    yMean = mean(yMat,0)
    yMat = yMat - yMean     #can also regularize ys but will get smaller coef
    xMat = regularize(xMat)
    m,n=shape(xMat)
    #returnMat = zeros((numIt,n)) #testing code remove
    ws = zeros((n,1)); wsTest = ws.copy(); wsMax = ws.copy()
    for i in range(numIt):
        print ws.T
        lowestError = inf; 
        for j in range(n):
            for sign in [-1,1]:
                wsTest = ws.copy()
                wsTest[j] += eps*sign
                yTest = xMat*wsTest
                rssE = rssError(yMat.A,yTest.A)
                if rssE < lowestError:
                    lowestError = rssE
                    wsMax = wsTest
        ws = wsMax.copy()
        returnMat[i,:]=ws.T
    return returnMat