机器学习--局部加权线性回归

局部加权线性回归

具体理论见上次笔记《线性回归》

预测鲍鱼年龄

import numpy as np

class LocalWeightedLinearRegression(object):
    def __init__(self,train_data,train_result):
        """
        :param train_data: 输入训练数据
        :param train_result: 训练数据真实结果
        """
        # 获得输入数据集的形状
        row, col = np.shape(train_data)
        # 构造输入数据数组
        self.Train_Data = [0] * row
        # 给每组输入数据增添常数项1
        for (index, data) in enumerate(train_data):
            Data = [1.0]
            # 把每组data拓展到Data内,即把每组data的每一维数据依次添加到Data
            Data.extend(list(data))
            self.Train_Data[index] = Data
        self.Train_Data = np.array(self.Train_Data)
        # 构造输入数据对应的结果
        self.Train_Result = train_result
        # 定义数据权重
        self.weight = np.zeros((row,row))
        # 定义局部加权回归模型参数
        self.Theta = []

    def Gaussian_Weight(self,data,k):
        """
        这是计算测试权重的函数
        :param data: 输入数据
        :param k: 带宽系数
        """
        # data的数据类型是np.array,那么利用dot方法
        # 进行矩阵运算的结果是矩阵,哪怕只有一个元素
        sum = np.sum(data*data)
        return np.exp(sum/(-2.0*k**2))

    def predict_NormalEquation(self,test_data,k):
        """
        这是利用正规方程对测试数据集的局部加权线性回归预测函数
        :param test_data: 测试数据集
        :param k: 带宽系数
        """
        # 对测试数据集全加入一维1,以适应矩阵乘法
        data = []
        for test in test_data:
            # 对测试数据加入1维特征,以适应矩阵乘法
            tmp = [1.0]
            tmp.extend(test)
            data.append(tmp)
        test_data = np.array(data)
        # 计算test_data与训练数据集之间的权重矩阵
        for (index, train_data) in enumerate(self.Train_Data):
            diff = test_data-self.Train_Data[index]
            self.weight[index, index] = self.Gaussian_Weight(diff, k)
        # 计算XTWX
        XTWX = self.Train_Data.T.dot(self.weight).dot(self.Train_Data)
        """
          0.001*np.eye(np.shape(self.Train_Data.T))是
          防止出现原始XT的行列式为0,即防止原始XT不可逆
       """
        # 获得输入数据数组形状
        row, col = np.shape(self.Train_Data)
        # 若XTWX的行列式为0,即XTWX不可逆,对XTWX进行数学处理
        if np.linalg.det(XTWX) == 0.0:
            XTWX = XTWX + 0.001 * np.eye(col, col)
        # 计算矩阵的逆
        inv = np.linalg.inv(XTWX)
        # 计算模型参数Thetha
        XTWY = self.Train_Data.T.dot(self.weight).dot(np.reshape(self.Train_Result,(len(self.Train_Result),1)))
        self.Theta = inv.dot(XTWY)
        # 对测试数据test_data进行预测
        predict_result = test_data.dot(self.Theta).T[0]
        return predict_result


import LocalWeightedLinearRegression as LWLR
from sklearn.model_selection import train_test_split
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

def Load_Abalone(path):
    """
    这是导入鲍鱼数据集的函数
    :param path: 文件路径
    """
    # 定义鲍鱼数据和结果数组
    data = []
    result = []
    # 打开路径为path的文件
    with open(path) as f:
        # 遍历文件中的每一行
        for line in f.readlines():
            str = line.strip().split(',')
            tmp = []
            length = len(str[1:])
            # 鲍鱼数据集中的第一个属性是性别,该属性属于离散数据
            # 因此导入数据时必须抛开这一列,最后一列是环数,加1.5可以预测年龄
            for (index,s) in enumerate(str[1:]):
                # 最后一个数据追加到result
                if index == length-1:
                    result.append(float(s)+1.5)
                # 否则剩下的数据追加到tmp临时数组
                else:
                    tmp.append(float(s))
            # 一组数据追加到数据集中
            data.append(tmp)
        data = np.array(data)
        result = np.array(result)
    return data,result

def Merge(data,col):
    """
    这是生成DataFrame数据的函数
    :param data:输入数据
    :param col:列名称数组
    """
    Data = np.array(data).T
    return pd.DataFrame(Data,columns=col)

def run_main():
    """
       这是主函数
    """
    # 导入鲍鱼数据集
    path = "./abalone_data.txt"
    Data,Result = Load_Abalone(path)

    # 把数据集分成训练集合测试集
    Train_Data,Test_Data,Train_Result,Test_Result = train_test_split\
        (Data,Result,test_size=0.01,random_state=10)

    # 解决Matplotlib中的中文乱码问题,以便于后面实验结果可视化
    mpl.rcParams['font.sans-serif'] = [u'simHei']
    mpl.rcParams['axes.unicode_minus'] = False

    # 可视化测试集
    col = ['长度','直径','高度','总重量','剥壳重量','内脏重量','壳重']

    # 遍历局部加权线性回归算法的预测结果
    fig = plt.figure()
    for (index, c) in enumerate(col):
        if index == 0:
            ax = fig.add_subplot(311)
        else:
            ax = fig.add_subplot(334+index-1)
        ax.scatter(Test_Data[:,index], Test_Result, alpha=0.5, c='b', s=10)
        ax.grid(True)
        plt.xlabel(c)
        plt.ylabel("鲍鱼年龄")
        # 子图之间使用紧致布局
        plt.tight_layout()
    plt.savefig("./测试结果可视化.jpg", bbox_inches='tight')
    plt.close()

    for (index,c) in enumerate(col):
        plt.scatter(Test_Data[:,index],Test_Result,alpha=0.5,c='b',s=10)
        plt.grid(True)
        plt.xlabel(c)
        plt.ylabel("鲍鱼年龄")
        plt.savefig("./"+c+"可视化.jpg",bbox_inches='tight')
        #plt.show()
        plt.close()

    # 初始化局部加权线性回归模型
    lwlr = LWLR(Train_Data,Train_Result)

    # 初始化局部加权回归带宽系数参数
    K = [0.0001,0.001,0.003,0.005,0.01,0.05,0.1,0.3,0.5]
    tmp = list(np.arange(1,101))
    K.extend(tmp)
    predict_result = []
    Loss = []
    # 把测试集进行从小到大排序
    sort = np.argsort(Test_Data[:, 1])
    Test_Data = Test_Data[sort]
    Test_Result = Test_Result[sort]
    # 遍历每个带宽系数,利用局部加权线性回归算法进行预测,并计算预测误差
    for k in K:
        # 在带宽系数k下,利用局部加权线性回归进行预测
        predict = lwlr.predict_NormalEquation(Test_Data,k)
        #print(np.shape(predict))
        # 计算每组数据的预测误差
        loss = (Test_Result-predict)**2
        print("k=%f时的误差:%f"%(k,np.sum(loss)))
        predict_result.append(predict)
        Loss.append(loss)
        # 可视化预测结果
        plt.scatter(Test_Data[:, 1], Test_Result, alpha=0.5, c='b', s=10)
        plt.plot(Test_Data[:,1],predict,'r')
        plt.grid(True)
        plt.xlabel('直径')
        plt.ylabel("鲍鱼年龄")
        plt.savefig("./k=" + str(k) + "可视化.jpg", bbox_inches='tight')
        plt.close()

    # 部分预测结果可视化
    # k = [0.1,0.3,1,3,10,100]
    k = [0.1,0.3,1,3,10,100]
    index= [6,7,9,11,18,108]
    # 遍历每个带宽系数,利用局部加权线性回归算法进行预测,并计算预测误差
    fig = plt.figure()
    for (j,(i,k_)) in enumerate(zip(index,k)):
        # 在带宽系数k下,利用局部加权线性回归进行预测
        predict = predict_result[i]
        # 可视化预测结果
        ax = fig.add_subplot(230+j+1)
        ax.scatter(Test_Data[:, 1], Test_Result, alpha=0.5, c='b', s=10)
        ax.plot(Test_Data[:,1],predict,'r')
        ax.grid(True)
        ax.legend(labels=["k=" + str(k_)], loc="best")
        plt.xlabel('直径')
        plt.ylabel("鲍鱼年龄")
        plt.tight_layout()
    plt.savefig("./部分预测结果.jpg")

    # 保存预测数据
    data = [Test_Result]
    col = ["真实结果"]
    for (index,k) in enumerate(K):
        data.append(predict_result[index])
        col.append("k="+str(k))
    Data = Merge(data,col)
    Data.to_excel("./真实结果与预测结果.xlsx")

    # 保存预测误差结果及其统计信息
    data = []
    col = []
    for (index, k) in enumerate(K):
        data.append(Loss[index])
        col.append("k=" + str(k))
    Data = Merge(data,col)
    Data.to_excel("./预测误差.xlsx")
    information = Data.describe()
    information.to_excel("./预测误差统计信息.xlsx")

    # 可视化不同带宽参数的局部加权线性回归模型在测试集的均方误差和预测标准差
    K = list(np.arange(1, 101))
    col = ["LWLR-MSE", "LWLR-std"]
    LWLR_MSE = list(information.loc['mean'])[9:]
    LWLR_std = list(information.loc['std'])[9:]
    plt.plot(K, LWLR_MSE, 'b')
    plt.plot(K, LWLR_std, 'c-.')
    plt.grid(True)
    plt.legend(labels=col, loc='best')
    plt.xlabel("带宽系数")
    plt.savefig("./局部加权线性回归的预测均方误差和标准差.jpg", bbox_inches='tight')
    plt.show()
    plt.close()

if __name__ == '__main__':
    run_main()

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值