1. 程式人生 > >線性迴歸(二)

線性迴歸(二)

本文參考:

1)崔家華:https://cuijiahua.com/blog/2017/12/ml_12_regression_2.html

2)zsffuture: https://blog.csdn.net/weixin_42398658/article/details/83511409   

================================================================================================ 

       如果資料的特徵比樣本點還多應該怎麼辦?

       嶺迴歸即L2正則線性迴歸,在一般的線性迴歸最小化均方誤差的基礎上增加了一個引數w的L2範數的罰項,從而最小化罰項殘差平方和。其實質上是一種改良的最小二乘估計法,通過放棄最小二乘法的無偏性,以損失部分資訊、降低精度為代價獲得迴歸係數更為符合實際、更可靠的迴歸方法。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 

普通線性迴歸: 

                                                                                         æºå¨å­¦ä¹ å®ææç¨ï¼åä¸ï¼ï¼çº¿æ§åå½åºç¡ç¯ä¹é¢æµé²é±¼å¹´é¾

  (1)

       如果矩陣不可逆,但是計算機無法達到完全不可逆的地步,只是接近不可逆,此時求出的值很大,很奇怪的一個值,如果我們此時對值做一個約束,讓他小於某個數,那麼他就可以求出穩定的值,從這裡大家能感覺到,這樣做的目的確實把不可逆的問題解決了,但是也會使的不是最優解,因此從這裡也說明了嶺迴歸是有偏估計。

在普通線性迴歸的基礎上新增約束:

                                                                                             \sum_{j=1}^{p} \omega _{j}^{2}\leq t    (2)

       通過拉格朗日乘子法將(1)、(2)轉變為

                                                                         æºå¨å­¦ä¹ å®ææç¨ï¼åäºï¼ï¼çº¿æ§åå½æé«ç¯ä¹ä¹é«ç©å·å¥ä»¶äºæä»·é¢æµ

       對w求導,迴歸係數的計算公式變形如下:

機器學習實戰教程(十二):線性迴歸提高篇之樂高玩具套件二手價預測

------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 

式中,矩陣 I 是一個mxm的單位矩陣加上一個λI從而使得矩陣非奇異,進而能對矩陣求逆

       嶺迴歸最先用來處理特徵數多於樣本數的情況,現在也用於在估計中加入偏差,從而得到更好的估計。這裡通過引入λ來限制了所有w之和,通過引入該懲罰項,能夠減少不重要的引數,這個技術在統計學中也可以叫做縮減(shrinkage)。縮減方法可以去掉不重要的引數,因此能更好地裂解資料。此外,與簡單的線性迴歸相比,縮減法能夠取得更好的預測效果。

from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
import numpy as np


def loadDataSet(fileName):
    numFeat = len(open(fileName).readline().split('\t')) - 1  # 統計 X的個數
    xArr = []
    yArr = []
    fr = open(fileName)
    for line in fr.readlines():  # 逐行讀取,濾除空格等
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)  # 新增資料
        yArr.append(float(curLine[-1]))  # 新增標籤
    return xArr, yArr


# ***************************************************
def ridgeRegress(xMat, yMat, lam=0.2):
    xTx = xMat.T * xMat
    denom = xTx + np.eye(np.shape(xMat)[1]) * lam
    if np.linalg.det(denom) == 0.0:
        print('矩陣為奇異矩陣,不能轉置')
        return
    ws = denom.I * (xMat.T * yMat)
    print('ws',ws)
    return ws


# ***************************************************
def ridgeTest(xArr, yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    yMean = np.mean(yMat, axis=0)
    yMat = yMat - yMean
    xMeans = np.mean(xMat, axis=0)
    xVar = np.var(xMat, axis=0)  # 求方差
    #print(xVar)
    xMat = (xMat - xMeans) / xVar  # 使每個維度特徵具有相同的重要性,所有特徵都減去各自的均值併除以方差
    # ------------------------------------------------------------------------
    numTestPts = 30
    wMat = np.zeros((numTestPts, np.shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegress(xMat, yMat, np.exp(i - 10))    # lambda以e的指數變化,最初是一個非常小的數
        wMat[i, :] = ws.T
    # ------------------------------------------------------------------------
    print('wMat',wMat)
    return wMat


def plotwMat():
    font = FontProperties(fname=r'c:\windows\fonts\simsun.ttc', size=14)
    abX, abY = loadDataSet('test.txt')
    redgeWeights = ridgeTest(abX, abY)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(redgeWeights)
    ax_title_text = ax.set_title(u'log(lambada)與迴歸係數的關係', FontProperties=font)
    ax_xlabel_text = ax.set_xlabel(u'log(lambada)', FontProperties=font)
    ax_ylabel_text = ax.set_ylabel(u'迴歸係數', FontProperties=font)
    plt.setp(ax_title_text, size=20, weight='bold', color='red')
    plt.setp(ax_xlabel_text, size=10, weight='bold', color='black')
    plt.setp(ax_ylabel_text, size=10, weight='bold', color='black')
    plt.show()


if __name__ == '__main__':
    plotwMat()

       縮減方法(逐步線性迴歸或嶺迴歸),就是將一些係數縮減成很小的值或者直接縮減為0。這樣做,就增大了模型的偏差(減少了一些特徵的權重),通過把一些特徵的迴歸係數縮減到0,同時也就減少了模型的複雜度。消除了多餘的特徵之後,模型更容易理解,同時也降低了預測誤差。但是當縮減過於嚴厲的時候,就會出現過擬合的現象,即用訓練集預測結果很好,用測試集預測就糟糕很多。 

       前向逐步線性迴歸演算法屬於一種貪心演算法,即每一步都儘可能減少誤差。通過每次微調各個迴歸係數,計算預測誤差。那個使誤差最小的一組迴歸係數,就是我們需要的最佳迴歸係數。

from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
import numpy as np


def loadDataSet(fileName):
    numFeat = len(open(fileName).readline().split('\t')) - 1  # 統計 X的個數
    xArr = []
    yArr = []
    fr = open(fileName)
    for line in fr.readlines():  # 逐行讀取,濾除空格等
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)  # 新增資料
        yArr.append(float(curLine[-1]))  # 新增標籤
    return xArr, yArr


def regularize(xMat, yMat):
    '''
    :param xMat: X資料集
    :param yMat: Y資料集
    :return: 標準化後的X資料集、標準化後的Y資料集
    '''
    inxMat = xMat.copy()
    inyMat = yMat.copy()
    yMean = np.mean(yMat, 0)
    inyMat = yMat - yMean
    inMeans = np.mean(inxMat, 0)
    inVar = np.var(inxMat, 0)
    inxMat = (inxMat - inMeans) / inVar  # ???
    return inxMat, inyMat


def rssError(yArr, yHatArr):
    '''
    誤差大小評價函式
    :param yArr: 預測值
    :param yHatArr: 真實值
    :return:
    '''
    return ((yArr - yHatArr) ** 2).sum()


def stageWise(xArr, yArr, eps=0.01, numIt=100):
    '''
    前向逐步線性迴歸
    :param xArr: X輸入資料
    :param yArr: Y預測資料
    :param eps: 每次迭代需要調整的步長
    :param numIt: 迭代次數
    :return: returnMat -numIt次迭代的迴歸係數矩陣
    '''
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xMat, yMat = regularize(xMat, yMat)
    m, n = np.shape(xMat)
    returnMat = np.zeros((numIt, n))
    ws = np.zeros((n, 1))
    wsTest = ws.copy()
    wsMax = ws.copy()
    # ----------------------------------------------------------
    for i in range(numIt):
        lowestError = float('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


def plotstageWiseMat():
    '''
    :return:
    '''
    font = FontProperties(fname=r'c:\windows\fonts\simsun.ttc', size=14)
    xArr, yArr = loadDataSet('test.txt')
    returnMat = stageWise(xArr, yArr, 0.005, 1000)    # !!!!!!
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(returnMat)
    ax_title_text = ax.set_title(u'前向逐步迴歸:迭代次數與迴歸係數的關係', FontProperties=font)
    ax_xlabel_text = ax.set_xlabel(u'迭代次數', FontProperties=font)
    ax_ylabel_text = ax.set_ylabel(u'迴歸係數', FontProperties=font)
    plt.setp(ax_title_text, size=15, weight='bold', color='red')
    plt.setp(ax_xlabel_text, size=10, weight='bold', color='black')
    plt.setp(ax_ylabel_text, size=10, weight='bold', color='black')
    plt.show()


if __name__ == '__main__':
    plotstageWiseMat()

       有些係數從始至終都是約為0的,這說明它們不對目標造成任何影響,也就是說這些特徵很可能是不需要的。逐步線性迴歸演算法的優點在於它可以幫助人們理解模型並做出改進。當構建了一個模型後,可以執行該演算法找出重要的特徵,這樣就有可能及時停止對那些不重要特徵的收集

簡單小栗子

       一種樂高套件基本上在幾年後就會停產,但樂高的收藏者之間仍會在停產後彼此交易。本次使用迴歸方法對收藏者之間的交易價格進行預測。

原始資料下載地址:資料下載

1、線性迴歸演算法

from bs4 import BeautifulSoup
import numpy as np


def scrapePage(retX, retY, inFile, yr, numPce, origPrc):
    """
    函式說明:從頁面讀取資料,生成retX和retY列表
    Parameters:
        retX - 資料X
        retY - 資料Y
        inFile - HTML檔案
        yr - 年份
        numPce - 樂高部件數目
        origPrc - 原價
    Returns:
        無
    """
    # 開啟並讀取HTML檔案
    with open(inFile, encoding='utf-8') as f:
        html = f.read()
    soup = BeautifulSoup(html)
    i = 1
    # 根據HTML頁面結構進行解析
    currentRow = soup.find_all('table', r="%d" % i)
    while (len(currentRow) != 0):
        currentRow = soup.find_all('table', r="%d" % i)
        title = currentRow[0].find_all('a')[1].text
        lwrTitle = title.lower()
        # 查詢是否有全新標籤
        if (lwrTitle.find('new') > -1) or (lwrTitle.find('nisb') > -1):
            newFlag = 1.0
        else:
            newFlag = 0.0
        # 查詢是否已經標誌出售,我們只收集已出售的資料
        soldUnicde = currentRow[0].find_all('td')[3].find_all('span')
        if len(soldUnicde) == 0:
            pass
            # print("商品 #%d 沒有出售" % i)
        else:
            # 解析頁面獲取當前價格
            soldPrice = currentRow[0].find_all('td')[4]
            priceStr = soldPrice.text
            priceStr = priceStr.replace('$', '')
            priceStr = priceStr.replace(',', '')
            if len(soldPrice) > 1:
                priceStr = priceStr.replace('Free shipping', '')
            sellingPrice = float(priceStr)
            # 去掉不完整的套裝價格
            if sellingPrice > origPrc * 0.5:
                # print("%d\t%d\t%d\t%f\t%f" % (yr, numPce, newFlag, origPrc, sellingPrice))
                retX.append([yr, numPce, newFlag, origPrc])
                retY.append(sellingPrice)
        i += 1
        currentRow = soup.find_all('table', r="%d" % i)


def setDataCollect(retX, retY):
    """
    函式說明:依次讀取六種樂高套裝的資料,並生成資料矩陣
    Parameters:
        無
    Returns:
        無
    """
    scrapePage(retX, retY, './lego/lego8288.html', 2006, 800, 49.99)  # 2006年的樂高8288,部件數目800,原價49.99
    scrapePage(retX, retY, './lego/lego10030.html', 2002, 3096, 269.99)  # 2002年的樂高10030,部件數目3096,原價269.99
    scrapePage(retX, retY, './lego/lego10179.html', 2007, 5195, 499.99)  # 2007年的樂高10179,部件數目5195,原價499.99
    scrapePage(retX, retY, './lego/lego10181.html', 2007, 3428, 199.99)  # 2007年的樂高10181,部件數目3428,原價199.99
    scrapePage(retX, retY, './lego/lego10189.html', 2008, 5922, 299.99)  # 2008年的樂高10189,部件數目5922,原價299.99
    scrapePage(retX, retY, './lego/lego10196.html', 2009, 3263, 249.99)  # 2009年的樂高10196,部件數目3263,原價249.99


def loadDataSet(fileName):
    numFeat = len(open(fileName).readline().split('\t')) - 1  # 統計 X的個數
    xArr = []
    yArr = []
    fr = open(fileName)
    for line in fr.readlines():  # 逐行讀取,濾除空格等
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)  # 新增資料
        yArr.append(float(curLine[-1]))  # 新增標籤
    return xArr, yArr


def regularize(xMat, yMat):
    '''
    :param xMat: X資料集
    :param yMat: Y資料集
    :return: 標準化後的X資料集、標準化後的Y資料集
    '''
    inxMat = xMat.copy()
    inyMat = yMat.copy()
    yMean = np.mean(yMat, 0)
    inyMat = yMat - yMean
    inMeans = np.mean(inxMat, 0)
    inVar = np.var(inxMat, 0)
    inxMat = (inxMat - inMeans) / inVar  # ???
    return inxMat, inyMat


def rssError(yArr, yHatArr):
    '''
    誤差大小評價函式
    :param yArr: 預測值
    :param yHatArr: 真實值
    :return:
    '''
    return ((yArr - yHatArr) ** 2).sum()


def standRegres(xArr, yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xTx = xMat.T * xMat
    if np.linalg.det(xTx) == 0.0:
        print('矩陣為奇異矩陣,不能求逆')
        return
    ws = xTx.I * (xMat.T * yMat)
    print('ws', ws)
    return ws


def useStandRegres():
    '''
    使用簡單的線性迴歸
    :return:
    '''
    lgX = []
    lgY = []
    #lgX, lgY = loadDataSet('lego.txt')
    setDataCollect(lgX, lgY)
    # i=0
    # for elem in lgY:
    #     i+=1
    #     print(elem)
    # print(i)
    # print([x for x in lgX])
    print('lgX', lgX)
    print('lgY', lgY)
    data_num, features_num = np.shape(lgX)
    lgX1 = np.mat(np.ones((data_num, features_num + 1)))
    lgX1[:, 1:5] = np.mat(lgX)
    ws = standRegres(lgX1, lgY)
    print('%f%+f*年份%+f*部件數量%+f*是否為全新%+f*原價' % (ws[0], ws[1], ws[2], ws[3], ws[4]))


if __name__ == '__main__':
    useStandRegres()

可以看出存在不合理的地方,比如是否為全新以及部件數量。

2、 嶺迴歸

使用嶺迴歸,通過交叉驗證,找到使誤差最小的λ對應的迴歸係數。

from bs4 import BeautifulSoup
import numpy as np
import random


def scrapePage(retX, retY, inFile, yr, numPce, origPrc):
    """
    函式說明:從頁面讀取資料,生成retX和retY列表
    Parameters:
        retX - 資料X
        retY - 資料Y
        inFile - HTML檔案
        yr - 年份
        numPce - 樂高部件數目
        origPrc - 原價
    Returns:
        無
    """
    # 開啟並讀取HTML檔案
    with open(inFile, encoding='utf-8') as f:
        html = f.read()
    soup = BeautifulSoup(html)
    i = 1
    # 根據HTML頁面結構進行解析
    currentRow = soup.find_all('table', r="%d" % i)
    while (len(currentRow) != 0):
        currentRow = soup.find_all('table', r="%d" % i)
        title = currentRow[0].find_all('a')[1].text
        lwrTitle = title.lower()
        # 查詢是否有全新標籤
        if (lwrTitle.find('new') > -1) or (lwrTitle.find('nisb') > -1):
            newFlag = 1.0
        else:
            newFlag = 0.0
        # 查詢是否已經標誌出售,我們只收集已出售的資料
        soldUnicde = currentRow[0].find_all('td')[3].find_all('span')
        if len(soldUnicde) == 0:
            pass
            # print("商品 #%d 沒有出售" % i)
        else:
            # 解析頁面獲取當前價格
            soldPrice = currentRow[0].find_all('td')[4]
            priceStr = soldPrice.text
            priceStr = priceStr.replace('$', '')
            priceStr = priceStr.replace(',', '')
            if len(soldPrice) > 1:
                priceStr = priceStr.replace('Free shipping', '')
            sellingPrice = float(priceStr)
            # 去掉不完整的套裝價格
            if sellingPrice > origPrc * 0.5:
                # print("%d\t%d\t%d\t%f\t%f" % (yr, numPce, newFlag, origPrc, sellingPrice))
                retX.append([yr, numPce, newFlag, origPrc])
                retY.append(sellingPrice)
        i += 1
        currentRow = soup.find_all('table', r="%d" % i)


def setDataCollect(retX, retY):
    """
    函式說明:依次讀取六種樂高套裝的資料,並生成資料矩陣
    Parameters:
        無
    Returns:
        無
    """
    scrapePage(retX, retY, './lego/lego8288.html', 2006, 800, 49.99)  # 2006年的樂高8288,部件數目800,原價49.99
    scrapePage(retX, retY, './lego/lego10030.html', 2002, 3096, 269.99)  # 2002年的樂高10030,部件數目3096,原價269.99
    scrapePage(retX, retY, './lego/lego10179.html', 2007, 5195, 499.99)  # 2007年的樂高10179,部件數目5195,原價499.99
    scrapePage(retX, retY, './lego/lego10181.html', 2007, 3428, 199.99)  # 2007年的樂高10181,部件數目3428,原價199.99
    scrapePage(retX, retY, './lego/lego10189.html', 2008, 5922, 299.99)  # 2008年的樂高10189,部件數目5922,原價299.99
    scrapePage(retX, retY, './lego/lego10196.html', 2009, 3263, 249.99)  # 2009年的樂高10196,部件數目3263,原價249.99


def loadDataSet(fileName):
    numFeat = len(open(fileName).readline().split('\t')) - 1  # 統計 X的個數
    xArr = []
    yArr = []
    fr = open(fileName)
    for line in fr.readlines():  # 逐行讀取,濾除空格等
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)  # 新增資料
        yArr.append(float(curLine[-1]))  # 新增標籤
    return xArr, yArr


def regularize(xMat, yMat):
    '''
    :param xMat: X資料集
    :param yMat: Y資料集
    :return: 標準化後的X資料集、標準化後的Y資料集
    '''
    inxMat = xMat.copy()
    inyMat = yMat.copy()
    yMean = np.mean(yMat, 0)
    inyMat = yMat - yMean
    inMeans = np.mean(inxMat, 0)
    print(inMeans)
    inVar = np.var(inxMat, 0)
    inxMat = (inxMat - inMeans) / inVar  # ???
    return inxMat, inyMat


def rssError(yArr, yHatArr):
    '''
    誤差大小評價函式
    :param yArr: 預測值
    :param yHatArr: 真實值
    :return:
    '''
    return ((yArr - yHatArr) ** 2).sum()


def standRegres(xArr, yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xTx = xMat.T * xMat
    if np.linalg.det(xTx) == 0.0:
        print('矩陣為奇異矩陣,不能求逆')
        return
    ws = xTx.I * (xMat.T * yMat)
    print('ws', ws)
    return ws


# ***************************************************
def ridgeRegres(xMat, yMat, lam=0.2):
    xTx = xMat.T * xMat
    denom = xTx + np.eye(np.shape(xMat)[1]) * lam
    if np.linalg.det(denom) == 0.0:
        print('矩陣為奇異矩陣,不能轉置')
        return
    ws = denom.I * (xMat.T * yMat)
    print('ws', ws)
    return ws


# ***************************************************
def ridgeTest(xArr, yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    yMean = np.mean(yMat, axis=0)
    yMat = yMat - yMean
    xMeans = np.mean(xMat, axis=0)
    xVar = np.var(xMat, axis=0)  # 求方差
    # print(xVar)
    xMat = (xMat - xMeans) / xVar  # 使每個維度特徵具有相同的重要性,所有特徵都減去各自的均值併除以方差
    # ------------------------------------------------------------------------
    numTestPts = 30
    wMat = np.zeros((numTestPts, np.shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegres(xMat, yMat, np.exp(i - 10))  # lambda以e的指數變化,最初是一個非常小的數
        wMat[i, :] = ws.T
    # ------------------------------------------------------------------------
    #print('wMat', wMat)
    return wMat


def crossValidation(xArr, yArr, numVal=10):
    '''
    交叉驗證嶺迴歸
    :param xArr: X資料集
    :param yArr: Y資料集
    :param numVal: 交叉驗證次數
    :return: wMat: 迴歸係數矩陣
    '''
    m = len(yArr)   #統計樣本個數
    indexList = list(range(m))  #生成索引列表
    errorMat = np.zeros((numVal, 30))
    for i in range(numVal):
        trainX = []
        trainY = []
        testX = []
        testY = []
        random.shuffle(indexList)   #打亂次序
        # 90% 為訓練集,10%為測試集
        for j in range(m):
            if j < m * 0.9:
                trainX.append(xArr[indexList[j]])
                trainY.append(yArr[indexList[j]])
            else:
                testX.append(xArr[indexList[j]])
                testY.append(yArr[indexList[j]])
    # ------------------------------------------------------------
        wMat = ridgeTest(trainX, trainY)    # 獲得30個不同lambda下的嶺迴歸係數
        for k in range(30):
            matTestX = np.mat(testX)
            matTrainX = np.mat(trainX)
            meanTrain = np.mean(matTrainX, 0)
            varTrain = np.var(matTrainX, 0)
            matTestX = (matTestX - meanTrain) / varTrain    # ?????
            yEst = matTestX * np.mat(wMat[k, :]).T + np.mean(trainY)    # ???
            errorMat[i, k] = rssError(yEst.T.A, np.array(testY))    # 統計誤差
    print('errorMat', errorMat)
    meanErrors = np.mean(errorMat, 0)   # 計算每次交叉驗證的平均誤差
    minMean = float(min(meanErrors))    # 找到最小誤差
    bestWeights = wMat[np.nonzero(meanErrors == minMean)]   # ?找到最佳迴歸係數
    print('bestWeights', bestWeights)
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    meanX = np.mean(xMat, 0)
    varX = np.var(xMat, 0)
    unReg = bestWeights / varX  # ??????
    print('%f%+f*年份%+f*部件數量%+f*是否為全新%+f*原價' %
          ((-1 * np.sum(np.multiply(meanX, unReg)) + np.mean(yMat)), unReg[0, 0],
           unReg[0, 1], unReg[0, 2], unReg[0, 3]))


def useStandRegres():
    '''
    使用簡單的線性迴歸
    :return:
    '''
    lgX = []
    lgY = []
    # lgX, lgY = loadDataSet('lego.txt')
    setDataCollect(lgX, lgY)
    # i=0
    # for elem in lgY:
    #     i+=1
    #     print(elem)
    # print(i)
    # print([x for x in lgX])
    print('lgX', lgX)
    print('lgY', lgY)
    data_num, features_num = np.shape(lgX)
    lgX1 = np.mat(np.ones((data_num, features_num + 1)))
    lgX1[:, 1:5] = np.mat(lgX)
    ws = standRegres(lgX1, lgY)
    print('%f%+f*年份%+f*部件數量%+f*是否為全新%+f*原價' % (ws[0], ws[1], ws[2], ws[3], ws[4]))


if __name__ == '__main__':
    # useStandRegres()
    lgX = []
    lgY = []
    setDataCollect(lgX, lgY)
    crossValidation(lgX, lgY)

 因為其隨機性,所以每次執行的結果可能略有不同。可以看出,它與常規的最小二乘法,即普通的線性迴歸沒有太大差異。

修改程式碼:

if __name__ == '__main__':
    # useStandRegres()
    lgX = []
    lgY = []
    setDataCollect(lgX, lgY)
    #crossValidation(lgX, lgY)
    print(ridgeTest(lgX,lgY))

       如果只選擇一個特徵來做預測的話,我們應該選擇第4個特徵。如果可以選擇2個特徵的話,應該選擇第4個和第2個特徵。這種分析方法使得我們可以挖掘大量資料的內在規律。在僅有4個特徵時,該方法的效果也許並不明顯;但如果有100個以上的特徵,該方法就會變得十分有效:它可以指出哪個特徵是關鍵的,而哪些特徵是不重要的。

3、使用Sklearn的linear_model

æºå¨å­¦ä¹ å®ææç¨ï¼åäºï¼ï¼çº¿æ§åå½æé«ç¯ä¹ä¹é«ç©å·å¥ä»¶äºæä»·é¢æµ

æºå¨å­¦ä¹ å®ææç¨ï¼åäºï¼ï¼çº¿æ§åå½æé«ç¯ä¹ä¹é«ç©å·å¥ä»¶äºæä»·é¢æµ

引數說明如下:

  • alpha:正則化係數,float型別,預設為1.0。正則化改善了問題的條件並減少了估計的方差。較大的值指定較強的正則化。
  • fit_intercept:是否需要截距,bool型別,預設為True。也就是是否求解b。
  • normalize:是否先進行歸一化,bool型別,預設為False。如果為真,則迴歸X將在迴歸之前被歸一化。 當fit_intercept設定為False時,將忽略此引數。 當迴歸量歸一化時,注意到這使得超引數學習更加魯棒,並且幾乎不依賴於樣本的數量。 相同的屬性對標準化資料無效。然而,如果你想標準化,請在呼叫normalize = False訓練估計器之前,使用preprocessing.StandardScaler處理資料。
  • copy_X:是否複製X陣列,bool型別,預設為True,如果為True,將複製X陣列; 否則,它覆蓋原陣列X。
  • max_iter:最大的迭代次數,int型別,預設為None,最大的迭代次數,對於sparse_cg和lsqr而言,預設次數取決於scipy.sparse.linalg,對於sag而言,則預設為1000次。
  • tol:精度,float型別,預設為0.001。就是解的精度。
  • solver:求解方法,str型別,預設為auto。可選引數為:auto、svd、cholesky、lsqr、sparse_cg、sag。
    • auto根據資料型別自動選擇求解器。
    • svd使用X的奇異值分解來計算Ridge係數。對於奇異矩陣比cholesky更穩定。
    • cholesky使用標準的scipy.linalg.solve函式來獲得閉合形式的解。
    • sparse_cg使用在scipy.sparse.linalg.cg中找到的共軛梯度求解器。作為迭代演算法,這個求解器比大規模資料(設定tol和max_iter的可能性)的cholesky更合適。
    • lsqr使用專用的正則化最小二乘常數scipy.sparse.linalg.lsqr。它是最快的,但可能在舊的scipy版本不可用。它是使用迭代過程。
    • sag使用隨機平均梯度下降。它也使用迭代過程,並且當n_samples和n_feature都很大時,通常比其他求解器更快。注意,sag快速收斂僅在具有近似相同尺度的特徵上被保證。您可以使用sklearn.preprocessing的縮放器預處理資料。
  • random_state:sag的偽隨機種子。

修改程式碼: 

def usesklearn():
    '''
    :return:
    '''
    from sklearn import linear_model
    reg = linear_model.Ridge(alpha=.5)
    lgX = []
    lgY = []
    setDataCollect(lgX, lgY)
    reg.fit(lgX, lgY)
    print('%f%+f*年份%+f*部件數量%+f*是否為全新%+f*原價' % (reg.intercept_, reg.coef_[0], reg.coef_[1], reg.coef_[2], reg.coef_[3]))


if __name__ == '__main__':
    # useStandRegres()
    # lgX = []
    # lgY = []
    # setDataCollect(lgX, lgY)
    # crossValidation(lgX, lgY)
    # print(ridgeTest(lgX,lgY))
    usesklearn()

 

 獲得的結果與以上兩種方法的結果類似。

總結

  • 與分類一樣,迴歸也是預測目標值的過程迴歸與分類的不同點在於,前者預測連續型別變數,而後者預測離散型別變數
  • 嶺迴歸是縮減法的一種,相當於對迴歸係數的大小施加了限制。另一種很好的縮減法是lasso。lasso難以求解,但可以使用計算簡便的逐步線性迴歸方法求的近似解。