【每天进步一点点】机器学习基础——基于鲍鱼年龄预测的线性回归Demo

Tianyi_Li 发表于 2020/05/26 20:20:55 2020/05/26
【摘要】 机器学习基础——基于鲍鱼年龄预测的线性回归Demo(附代码)。回归分析是一种预测性的建模技术,它研究的是因变量(目标)和自变量(预测器)之间的关系。这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。通常使用曲线/线来拟合数据点,目标是使曲线到数据点的距离差异最小。
  1. 回归问题

    回归分析是一种预测性的建模技术,它研究的是因变量(目标)和自变量(预测器)之间的关系。这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。通常使用曲线/线来拟合数据点,目标是使曲线到数据点的距离差异最小。

   2. 线性回归

    线性回归是回归问题中的一种,线性回归假设目标值与特征之间线性相关,即满足一个多元一次方程。通过构建损失函数,来求解损失函数最小时的参数w和b。通长我们可以表达成如下公式:

                                                                                                             image.png

     y^为预测值,自变量x和因变量y是已知的,而我们想实现的是预测新增一个x,其对应的y是多少。因此,为了构建这个函数关系,目标是通过已知数据点,求解线性模型中w和b两个参数。

   3. 主要方式

    线性回归主要有梯度下降,正则方程,基于kernel的线性回归等。

    这里只介绍下梯度下降:

梯度下降是一种优化方法,在机器学习中被广泛使用。它的主要思想是在优化目标函数的时候,沿着负梯度方向去减小函数值,以此达到我们的优化目标。

image.png

image.png

image.png


        一般来说,梯度下降算法无法避免局部极值点的产生,因此其最优点会随着初始点选择不同而不同,解决这个问题的方法是随机进行初始化,寻找多个最优点,再在这些最优点之间比较。就本题而言,本题是一个线性回归问题,他的目标函数是一个凸二次函数,只有一个极值点,因此无论初始点选在哪里最优点都相等。

        除了最基本的梯度下降外,该算法还有许多的变体,如批量梯度下降,随机梯度下降等。它们的不同之处在于一次性使用多少数据来计算目标函数的梯度。也就是在参数更新准确性和参数更新花费时间两方面做出权衡。以随机梯度下降为例,当数据量较大时,每一次迭代都需要遍历全部数据,使得参数更新缓慢,为了解决这个问题,更新参数时不选取全部m个训练示例,只使用其中的一个或一部分,这样加快了迭代速度,但是可能导致不能精确收敛到最优值。


好了,上代码

# -*- coding:utf-8 -*-
# Created on 2020/05/26
# @author: Tianyi_Li
# Method: 基于线性回归(Linear Regression)的鲍鱼年龄预测
# Reference: https://cuijiahua.com/blog/2017/11/ml_11_regression_1.html

# 导入相关的库
import matplotlib.pyplot as plt
import numpy as np
from sklearn import decomposition

# 读取数据
def loadDataSet(fileName):
    """
    Function specification:
        设数据集为M * N 矩阵,将每行的前N - 1列数据抽成一个矩阵,将最后的一列作为另一个矩阵
    Parameters:
        fileName - 文件名
    Returns:
        xArr - x数据集,表示数据
        yArr - y数据集,表示标签
    Reference:
        https://www.cuijiahua.com/
        https://blog.csdn.net/wzj_123123/article/details/77938565
    Modify:
        2020/5/26
    """

    # 方法一,直接调用函数
    data = np.loadtxt(fileName)
    xArr = data[:, 0:-1]    # 除最后一列外存入xArr
    yArr = data[:, -1]  # 将最后一列存入yArr

    '''
    方法二:逐行读取
    numFeat = len(open(fileName).readline().split('\t')) - 1
    xArr = []
    yArr = []
    fr = open(fileName)
    for line in fr.readlines():
        print("line:", line)
        lineArr = []
        curLine = line.strip('\n').split(' ')
        for i in curLine:
            if i != '':
                lineArr.append(float(i))
        xArr.append(lineArr[0:-1])
        # print(curLine[-1])
        yArr.append(lineArr[-1])
    '''
    return xArr, yArr
    
    
# 线性回归
def standRegress(xArrTrain, yArrTrain):
    """
    Function specification:
    Parameters:
        xArrTrain - x数据集,训练集
        yArrTrain - y数据集,训练集
    Returns:
        ws - 回归系数
    Reference:
    https://blog.csdn.net/chivalrousli/article/details/52474376
    Modify:
        2020/5/26
    """

    xMat = np.mat(xArrTrain)
    yMat = np.mat(yArrTrain).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 plotLineRegression(xArrTest, yArrTest, xArrTrain, yArrTrain):
    """
    Function specification:
    绘制回归线
    Reference:
        https://blog.csdn.net/chivalrousli/article/details/52474376
    Modify:
        2020/5/26
    """

    ws = standRegress(xArrTrain, yArrTrain)  # 计算回归系数
    xMat = np.mat(xArrTest)  # 创建xMat矩阵
    yMat = np.mat(yArrTest)  # 创建yMat矩阵
    xCopy = xMat.copy()  # 拷贝xMat矩阵
    # xCopy.sort(0)  # 排序
    yHat = xCopy * ws  # 计算对应的y值

    fig = plt.figure()
    # ax = fig.add_subplot(111)
    m = xCopy.shape[0]
    xHat = np.linspace(1, m, m)
    plt.plot(xHat, yArrTest, c='red', label = 'yArrTest - test data')
    plt.plot(xHat, yHat, c='green', label = 'yHat - pridected data')
    plt.title('LineRegression yArrTest VS yHat')  # 绘制title
    plt.legend(loc='upper right')
    plt.show()
    
    
'''
# Created on 2020/5/26
# @author: AngelWings
# Method: 局部加权线性回归(Locally Weighted Linear Regression,LWLR)
# Reference: https://cuijiahua.com/blog/2017/11/ml_11_regression_1.html
'''

# 局部加权线性回归
# 使用局部加权线性回归计算回归系数w
def lwlr(testPoint, xArr, yArr, k = 1.0):
    """
    Function specification:
    Parameters:
        testPoint - 测试样本点
        xArr - x数据集,表示数据
        yArr - y数据集,表示标签
        k - 高斯核的k,自定义参数
    Returns:
        ws - 回归系数
    Refenence:
        https://blog.csdn.net/Albert_Wang_YY/article/details/54407650
    Modify:
        2020/5/26
    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T   # .T表示转置矩阵
    m = np.shape(xMat)[0]   # 输出m为xMat行数,即M
    weights = np.mat(np.eye((m)))   # 创建权重对角矩阵
    for j in range(m):  # 遍历数据集,根据高斯核函数构造权重矩阵
        diffMat = testPoint - xMat[j, :]
        weights[j, j] = 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))    # 计算回归系数
    xTx_pinv = np.linalg.pinv(xTx)
    ws = xTx_pinv * (xMat.T * (weights * yMat))    # 计算回归系数,这里求伪逆
    return testPoint * ws
    
    
# 局部加权线性回归测试
def lwlrTest(testArr, xArr, yArr, k=1.0):
    """
    Function specification:
    Parameters:
        testArr - 测试数据集,测试集
        xArr - x数据集,训练集
        yArr - y数据集,训练集
        k - 高斯核的k,自定义参数
    Returns:
        ws - 回归系数
    Reference:
    https://blog.csdn.net/chivalrousli/article/details/52474376
    Modify:
        2020/5/26
    """

    m = np.shape(testArr)[0]    # 计算测试数据集大小
    yHat = np.zeros(m)
    for i in range(m):  # 对每个样本点进行预测
        yHat[i] = lwlr(testArr[i], xArr, yArr, k)
    return yHat
    
    
# 误差大小评价函数
def MeanSquareError(xArrTest, yArrTest, xArrTrain, yArrTrain):
    """
    Function specification:
        选取70%数据作为训练数据,余下30%数据作为测试数据
    Returns:
        均方误差大小
    """

    ws = standRegress(xArrTrain, yArrTrain)  # 计算回归系数
    xMat = np.mat(xArrTest)  # 创建xMat矩阵
    yMat = np.mat(yArrTest)  # 创建yMat矩阵
    xCopy = xMat.copy()  # 深拷贝xMat矩阵
    # xCopy.sort(0)  # 排序
    yHat = xMat * ws  # 计算对应的y值
    # yHat = yHat.flatten().A[0]  # 将输出数据展开为一维列表

    sum = 0
    for i in range(len(yHat)):
        sum += ((yArrTest[i] - yHat[i]) ** 2)
    MSE = sum/2/len(yHat)
    return MSE
    
  
def LELR_MeanSquareError(lwlrTest, yArrTest):

    return (((lwlrTest - yArrTest) ** 2).sum()) / 2 / len(yArrTest)
    
    
# PCA Model
def myPCA_Module(x, n_components):

    '''
    x -- data
    n_components -- 指定希望PCA降维后的特征维度数目
    # decomposition.PCA(n_components) 说明:
    # sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False,
    # svd_solver=’auto’, tol=0.0, iterated_power=’auto’, random_state=None)
    # 主要使用参数n_components:指定希望PCA降维后的特征维度数目。用法如下:
    # 1. 最常用的做法是直接指定降维到的维度数目,此时n_components是一个大于等于1的整数。
    # 2. 指定主成分的方差和所占的最小比例阈值,让PCA类自动根据样本特征方差来决定降维到
    # 的维度数,此时n_components是一个(0,1]之间的数。
    # 3. 将参数设置为"mle", 此时PCA类会用MLE算法根据特征的方差分布情况自己去选择一定数
    # 量的主成分特征来降维。
    # 4. 用默认值,即不输入n_components,此时n_components=min(样本数,特征数)。
    '''

    pca = decomposition.PCA(n_components = n_components)

    # fit_transform(X)说明
    # 用X来训练PCA模型,同时返回降维后的数据。
    # newX = pca.fit_transform(X),newX就是降维后的数据。
    x_new = pca.fit_transform(x)

    # explained_variance_,它代表降维后的各主成分的方差值。方差值越大,则说明越是重要的主成分。
    print('pca.explained_variance_:', pca.explained_variance_)

    # explained_variance_ratio_,它代表降维后的各主成分的方差值占总方差值的比例,这个比例越大,则越是重要的主成分。
    print('pca.explained_variance_ratio_:', pca.explained_variance_ratio_)

    # 各个特征所占比例图绘制
    plt.figure()
    plt.plot(pca.explained_variance_, 'r')
    plt.xlabel('n_components', fontsize=16)
    plt.ylabel('explained_variance_', fontsize=16)
    plt.show()

    return x_new
    
    
if __name__ == '__main__':
    xArr, yArr = loadDataSet('AbaloneAge.txt')  # 加载数据集

    xArrTrain = xArr[0:2924]  # 训练数据集0-2924行
    xArrTrain = np.insert(xArrTrain, 0, 1, axis=1)  # 在第一列前插入一列“1”,获取常数项
    yArrTrain = yArr[0:2924]  # 训练数据集0-2924行

    xArrTest = xArr[2924:4178]  # 测试数据集2925-4177行
    xArrTest = np.insert(xArrTest, 0, 1, axis=1)    # 在第一列前插入一列“1”,获取常数项
    yArrTest = yArr[2924:4178]  # 测试数据集2925-4177行

    # 线性回归   
    # plotLineRegression(xArrTest, yArrTest, xArrTrain, yArrTrain)
    # print('Mean Square Error:', MeanSquareError(xArrTest, yArrTest, xArrTrain, yArrTrain))

    # 局部加权线性回归
    # yHat = lwlrTest(xArrTest, xArrTrain, yArrTrain, k = 0.003)
    # print('Mean Square Error:', LELR_MeanSquareError(yHat, yArrTest))

    # PCA and Linear Regression  ----  Mean Square Error: [[2.30770975]]

    xArrTrainPCA = myPCA_Module(xArrTrain, 7)
    xArrTrainPCA = np.insert(xArrTrainPCA, 0, 1, axis=1)    # 在第一列前插入一列“1”,获取常数项
    xArrTestPCA = myPCA_Module(xArrTest, 7)
    xArrTestPCA = np.insert(xArrTestPCA, 0, 1, axis=1)    # 在第一列前插入一列“1”,获取常数项
    
    plotLineRegression(xArrTestPCA, yArrTest, xArrTrainPCA, yArrTrain)
    print('Mean Square Error:', MeanSquareError(xArrTestPCA, yArrTest, xArrTrainPCA, yArrTrain))


 最终结果如图:

image.png


image.png


image.png


效果还行,MSE在2.47左右。线性回归是非常基础的方法,虽然现在可能用得不多(一般都是大数据训练模型了,但基础总是要掌握的嘛)。

是不是很简单,赶快试试吧。什么,没资源,来来来,ModelArts免费AI资源给你,https://console.huaweicloud.com/modelarts/?region=cn-north-4#/dashboard


最后附上代码和数据集,在附件哦,解压后上传.ipynb和.txt到NoteBook即可使用


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。