第1关:岭回归

任务描述

本关任务:编写一个能计算数组平均值和最大值的小程序。

相关知识

为了完成本关任务,你需要掌握:1.什么是岭回归,2.岭回归核心算法,3.lasso缩减。

什么是岭回归

stata岭回归结果分析 岭回归数据_数据挖掘

岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加人偏差,从而得到更好的估计。这里通过引入1来限制了所有《之和,通过引人该惩罚项,能够减少不重要的参数,这个技术在统计学中也叫做缩减(shrinkage )。 缩减方法可以去掉不重要的参数,因此能更好地理解数据。此外,与简单的线性回归相比,缩减法能取得更好的预测效果。

岭回归核心算法

stata岭回归结果分析 岭回归数据_人工智能_02

stata岭回归结果分析 岭回归数据_人工智能_03

lasso缩减

不难证明,在增加如下约束时,普通的最小二乘法回归会得到与岭回归的一样的公式:

stata岭回归结果分析 岭回归数据_数据挖掘_04

上式限定了所有回归系数的平方和不能大于

stata岭回归结果分析 岭回归数据_岭回归_05

。使用普通的最小二乘法回归在当两个或更多的特征相关时,可能会得出一个很大的正系数和一个很大的负系数。正是因为上述限制条件的存在,使用岭回归可以避免这个问题。 与岭回归类似,另一个缩减方法lasso也对回归系数做了限定,对应的约束条件如下:

stata岭回归结果分析 岭回归数据_回归_06

唯一的不同点在于,这个约束条件使用绝对值取代了平方和。虽然约束形式只是稍作变化,结果却大相径庭:在

stata岭回归结果分析 岭回归数据_岭回归_05

足够小的时候,一些系数会因此被迫缩减到0,这个特性可以帮助我们更好 地理解数据。这两个约束条件在公式上看起来相差无几,但细微的变化却极大地增加了计算复杂度(为了在这个新的约束条件下解出回归系数,需要使用二次规划算法)。

编程要求

根据提示,在右侧编辑器补充代码,绘制岭回归系数矩阵。

测试说明

根据所学完成右侧编程题。

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


# 加载数据
def loadDataSet(fileName):
    """
    Parameters:
        fileName - 文件名
    Returns:
        xArr - x数据集
        yArr - y数据集
    """
    numFeat = len(open(fileName).readline().split('\t')) - 1
    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):
    """
    Parameters:
        xMat - x数据集
        yMat - y数据集
    Returns:
        inxMat - 标准化后的x数据集
        inyMat - 标准化后的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):
    """
    Parameters:
        yArr - 预测值
        yHatArr - 真实值
    Returns:
    """
    return ((yArr - yHatArr) ** 2).sum()


# 前向逐步线性回归
def stageWise(xArr, yArr, eps=0.01, numIt=100):
    """
    Parameters:
        xArr - x输入数据
        yArr - y预测数据
        eps - 每次迭代需要调整的步长
        numIt - 迭代次数
    Returns:
        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))  # 初始化numIt次迭代的回归系数矩阵
    ws = np.zeros((n, 1))  # 初始化回归系数矩阵
    wsTest = ws.copy()
    wsMax = ws.copy()
    for i in range(numIt):  # 迭代numIt次
        # print(ws.T)                             #打印当前回归系数矩阵
        lowestError = float('inf');  # 正无穷
        for j in range(n):  # 遍历每个特征的回归系数
            for sign in [-1, 1]:
               ###########
               请在此处填写代码
               ##########
        ws = wsMax.copy()
        returnMat[i, :] = ws.T  # 记录numIt次迭代的回归系数矩阵
    return returnMat

第2关:前向逐步线性回归

任务描述

本关任务:根据前向逐步线性回归方法编写一个绘制岭回归系数矩阵的程序。

相关知识

为了完成本关任务,你需要掌握:1.向前逐步回归的思想,2.前向逐步线性回归的核心算法,3.逐步线性回归算法的好处。

向前逐步回归的思想

前向逐步回归算法可以得到与lasso差不多的效果,但更加简单。它属于一种贪心算法,即每一步都尽可能减少误差。一开始,所有的权重都设为1,然后每一步所做的决策是对某个权重增加或减少一个很小的值。

该算法的伪代码如下所示: 数据标准化,使其分布满足0均值和单位方差 在每轮迭代过程中: 设置当前最小误差lowestError为正无穷 对每个特征: 增大或缩小: 改变一个系数得到一个新的w 计算新w下的误差 如果误差Error小于当前最小误差lowestError:设置Wbest等于当前的w 将w设置为新的Wbest

前向逐步线性回归的核心算法

stata岭回归结果分析 岭回归数据_回归_08

stata岭回归结果分析 岭回归数据_stata岭回归结果分析_09

向前逐步线性回归算法的好处

逐步线性回归算法的实际好处并不在于能绘出漂亮的图,主要的优点在于它可以帮助人们理解现有的模型并做出改进。当构建了一个模型后,可以运行该算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。最后,如果用于测试,该算法每100次迭代后就可以构建出一个模型,可以使用类似于10折交叉验证的方法比较这些模型,最终选择使误差最小的模型。 当应用缩减方法(如逐步线性回归或岭回归) 时 ,模型也就增加了偏差(bias),与此同时却减小了模型的方差。

编程要求

根据提示,在右侧编辑器补充代码,绘制岭回归系数矩阵的程序。

测试说明

根据所学,完成右侧编程题。

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

# 加载数据
def loadDataSet(fileName):
    """
    Parameters:
        fileName - 文件名
    Returns:
        xArr - x数据集
        yArr - y数据集
    """
    numFeat = len(open(fileName).readline().split('\t')) - 1
    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 ridgeRegres(xMat, yMat, lam = 0.2):
    """
    Parameters:
        xMat - x数据集
        yMat - y数据集
        lam - 缩减系数
    Returns:
        ws - 回归系数
    """
   ##########
    xTx = xMat.T*xMat
    denom = xTx + eye(shape(xMat)[1])*lam
    if linalg.det(denmo) == 0.0:
        print("This matrix is singular, cannot do inverse")
        return
   ##########
    ws = denom.I * (xMat.T * yMat)
    return ws

# 岭回归测试
def ridgeTest(xArr, yArr):
    """
    Parameters:
        xMat - x数据集
        yMat - y数据集
    Returns:
        wMat - 回归系数矩阵
    """
    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)                    #行与行操作,求方差
    xMat = (xMat - xMeans) / xVar                    #数据减去均值除以方差实现标准化
    numTestPts = 30                                  #30个不同的lambda测试
    wMat = np.zeros((numTestPts, np.shape(xMat)[1])) #初始回归系数矩阵
    for i in range(numTestPts):                      #改变lambda计算回归系数
        ws = ridgeRegres(xMat, yMat, np.exp(i - 10)) #lambda以e的指数变化,最初是一个非常小的数,
        wMat[i, :] = ws.T                            #计算回归系数矩阵
    return wMat