线性回归数值型预测:预测鲍鱼的年龄

版权声明:个人水平有限,表述不当或疏漏之处欢迎读者提问交流,共同进步! 作者:J__Max 非商业转载请注明出处,商业转载请联系作者获得授权。 https://blog.csdn.net/J__Max/article/details/83475864

线性回归数值型预测:预测鲍鱼的年龄

一、实验准备

1、实验内容和目的

  • 根据训练集中给出的鲍鱼的各项生物特征参数以及其年龄,进行处理和拟合。然后使用拟合出来的模型来预测测试集中鲍鱼的年龄

  • 其中训练集为文件train.txt,测试集为文件test.txt。训练集中的每个样本有8个特征参数,最后的数字为其年龄;而测试集合中只存放每个样本的8个特征参数

2、实验原理

  • 前面学习的KNN分类算法和朴素贝叶斯分类算法的目标变量是标称型数据,而回归则是对连续型的数据做出处理,回归的目的是预测数值型数据的目标值
2.1 关于回归的背景了解
  • 回归的目的是预测数值型的目标值。最直接的方法就是依据输入写出一个目标值的计算公式。比如要计算一辆车的马力大小,可能会这么计算:

    H o r s e P o w e r = 0.0015 a n n u a l S a l a r y 0.99 h o u r s e L i s t e n i n g T o P u b l i c R a d i o HorsePower = 0.0015*annualSalary - 0.99*hourseListeningToPublicRadio

  • 这就是所谓的回归方程,其中的0.0015和-0.99称作回归系数,求这些回归系数的过程就是回归。一旦有了这些回归系数,再给定输入,做预测就非常容易了。具体的做法是用回归系数乘以输入值,再将结果相加,就能得到预测值

2.2 用线性回归找到最佳拟合直线
  • 大致的原理已经知道了,那么应当怎么从一大堆数据里求出回归方程呢?假定输入数据在矩阵 x \mathbf{x} 中,而回归系数存放在向量 w \mathbf{w} 中。那么对于给定的数据 x 1 x_1 ,预测结果将会通过 Y 1 = x 1 T w Y_1=x_1^T\mathbf{w} 给出。现在的问题是,手里有一些x和对应的y,怎样才能好到 w \mathbf{w} 呢?一个常用的方法就是找出使误差最小的 w \mathbf{w} 。这里的误差是指预测y值和真实y值之间的差值,使用该误差的简单累加会使得正差值和负差值相互抵消,所以采用平方误差

  • 平方误差可以写为:

    i = 1 m ( y i x i T w ) 2 \sum_{i=1}^{m}(y_i-x_i^T\mathbf{w})^2

  • 用矩阵表示还可以写做 ( y x w ) T ( y x w ) (y-x\mathbf{w})^T(y-x\mathbf{w}) 。如果对 w \mathbf{w} 求导,得到 x T ( y x w ) x^T(y-x\mathbf{w}) ,令其等于零,解得 w \mathbf{w} 如下:

    w ^ = ( X T X ) 1 X T y \hat{\mathbf{w}}=(X^TX)^{-1}X^Ty

  • 值得注意的是,上述的公式中包含 ( X T X ) 1 (X^TX)^{-1} ,也就是需要对矩阵求逆,因此这个方程只在逆矩阵存在的时候适应。然而,矩阵的逆有可能不存在,因此必须要在代码中对此作出判断

2.3 局部加权线性回归
  • 如果单纯的使用上述线性回归的方法,会出现欠拟合的问题,因为它求的是具有最小均方误差的无偏估计。显而易见,如果模型欠拟合将不能取得最好的预测效果。所以在此次预测任务中采用了局部加权线性回归算法

  • 在局部加权线性回归算法中,我们给待预测点附近的每个点赋予一定的权重;然后与2.1中的解法类似,在这个子集上基于最小均方差来进行普通的回归。该算法解出回归系数 w \mathbf{w} 的形式如下:

    w ^ = ( X T W X ) 1 X T W y \hat{\mathbf{w}}=(X^TWX)^{-1}X^TWy

  • 其中 W W 是一个矩阵,用来给每个数据点赋予权重。局部加权线性回归算法使用“核”来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下:

    w ( i , i ) = e x p ( x ( i ) x 2 k 2 ) w(i,i)=exp(\frac{\big|{x^{(i)}-x}\big|}{-2k^2})

二、进行实验

1、算法思路

  • 使用局部加权回归算法,对训练数据进行拟合操作。其中,通过高斯核参数k的调整来提高拟合效果;同时,对比在缩减不同特征项的情况下得到的拟合效果,取最优

2、算法步骤

  • (1) 对训练数据进行处理,提出每个训练样本的特征参数集以及y值

  • (2) 对测试数据进行处理,提出每个测试样本的特征参数集

  • (3) 使用局部加权回归算法对训练数据进行拟合,得到系数w

  • (4) 使用拟合得到的系数w,计算测试样本对应的y值

3、代码实现

  • 注:代码中的所有函数功能已注释在函数头部

  • (1) 处理训练数据和测试数据。因为训练数据中的每个样本包含y值而测试数据中的样本不包含,因此使用两个不同的功能函数分别进行处理

def loadTrainData(filename):
    """
    函数说明:
        加载训练数据
    :param filename:
        文件名
    :return:
        xArray - x数据集,即为每个训练样本的特征参数
        yArray - y数据集,即为每个训练样本的年龄
    """
    featNum = len(open(filename).readline().split(',')) - 2 # 特征参数的个数,其中舍掉了第一个性别特征

    file = open(filename)
    xArray = []
    yArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)
        yArray.append(float(tempLine[-1]))

    return xArray, yArray
def loadTestData(filename):
    """
    函数说明:
        加载测试数据
    :param filename:
        文件名
    :return:
        xArray - x数据集,即为每个测试样本的特征参数
    """
    featNum = len(open(filename).readline().split(',')) - 1 # 特征参数的个数,其中舍掉了第一个性别特征

    file = open(filename)
    xArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)

    return xArray
  • (2) 使用局部加权回归算法对训练数据进行拟合,得到系数w
def lwlRegression(testPoint, xArr, yArr, k=1.0):
    """
    函数说明:
        使用局部加权线性回归计算回归系数w
    :param testPoint:
        测试样本
    :param xArr:
        x训练数据集
    :param yArr:
        y训练数据集
    :param k:
        高斯核的k值,默认为1.0,可自定义
    :return:
        testPoint * ws - 计算得到的系数w对测试样本的预测值
    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weights = np.mat(np.eye((m)))
    for i in range(m):
        diffMat = testPoint - xMat[i, :]
        weights[i, i] = np.exp(diffMat * diffMat.T / (-2.0 * k ** 2))
    xTx = xMat.T * (weights * xMat)
    if np.linalg.det(xTx) == 0.0:
        print("不能求逆!")
        return

    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws
  • (3) 使用拟合得到的系数w,计算测试样本对应的y值
def RegressionTest(testArr, xArr, yArr, k=1.0):
    """
    函数说明:
        局部加权线性回归测试
    :param testArr:
        测试数据集
    :param xArr:
        x训练数据集
    :param yArr:
        y训练数据集
    :param k:
        高斯核的k值,默认为1.0,可自定义
    :return:
        yHat - 测试集合的所有预测值
    """
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlRegression(testArr[i], xArr, yArr, k)
    return yHat

4、总结

  • 使用局部加权线性回归算法得到的效果会优于最小二乘法;同时,进行不同特征项的缩减比较,发现舍掉第一个性别特征的情况下拟合效果会更好(已在代码中体现)

  • 大致总结了线性回归的优缺点:

    • 优点:结果易于理解,计算上不复杂

    • 缺点:对非线性的数据拟合效果不好

三、完整代码

#!/usr/bin/python
# -*- coding utf-8 -*-
# Project: Regression
# Author: jiangnan 
# Mail: [email protected]
# Date: 2018/10/13

import numpy as np

def loadTrainData(filename):
    """
    函数说明:
        加载训练数据
    :param filename:
        文件名
    :return:
        xArray - x数据集,即为每个训练样本的特征参数
        yArray - y数据集,即为每个训练样本的年龄
    """
    featNum = len(open(filename).readline().split(',')) - 2 # 特征参数的个数,其中舍掉了第一个性别特征

    file = open(filename)
    xArray = []
    yArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)
        yArray.append(float(tempLine[-1]))

    return xArray, yArray

def loadTestData(filename):
    """
    函数说明:
        加载测试数据
    :param filename:
        文件名
    :return:
        xArray - x数据集,即为每个测试样本的特征参数
    """
    featNum = len(open(filename).readline().split(',')) - 1 # 特征参数的个数,其中舍掉了第一个性别特征

    file = open(filename)
    xArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)

    return xArray

def lwlRegression(testPoint, xArr, yArr, k=1.0):
    """
    函数说明:
        使用局部加权线性回归计算回归系数w
    :param testPoint:
        测试样本
    :param xArr:
        x训练数据集
    :param yArr:
        y训练数据集
    :param k:
        高斯核的k值,默认为1.0,可自定义
    :return:
        testPoint * ws - 计算得到的系数w对测试样本的预测值
    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weights = np.mat(np.eye((m)))
    for i in range(m):
        diffMat = testPoint - xMat[i, :]
        weights[i, i] = np.exp(diffMat * diffMat.T / (-2.0 * k ** 2))
    xTx = xMat.T * (weights * xMat)
    if np.linalg.det(xTx) == 0.0:
        print("不能求逆!")
        return

    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws


def RegressionTest(testArr, xArr, yArr, k=1.0):
    """
    函数说明:
        局部加权线性回归测试
    :param testArr:
        测试数据集
    :param xArr:
        x训练数据集
    :param yArr:
        y训练数据集
    :param k:
        高斯核的k值,默认为1.0,可自定义
    :return:
        yHat - 测试集合的所有预测值
    """
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlRegression(testArr[i], xArr, yArr, k)
    return yHat

def main():
    """
    函数说明:
        主函数,综合调用上述功能函数完成工作
    """
    trainX, trainY = loadTrainData('train.txt');
    testX = loadTestData('test.txt')

    yHat = RegressionTest(testX, trainX, trainY, 0.1)

    # 输出预测结果
    for i in yHat:
        print(i)

if __name__ == '__main__':
    main()

猜你喜欢

转载自blog.csdn.net/J__Max/article/details/83475864