线性回归(二)

本文参考:

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难以求解,但可以使用计算简便的逐步线性回归方法求的近似解。

猜你喜欢

转载自blog.csdn.net/qq_35134144/article/details/84133985