python MachinelEarning机器学习笔记day01

day01-概述-数据预处理-一元线性回归-岭回归-多项式回归
    一、概述
        1、什么是机器学习
            人工智能:
                通过人工的方法,实现或近似实现某些需要人类智能处理的问题,
                都可以称为人工智能
            机器学习:
                机器学习是一门能够让编程计算机从数据中学习的计算机科学。
                一个计算机程序在完成任务T之后,获得经验E,而该经验的效果
                可以通过P得以表现,如果随着T的增加,借助P来表现的E也可以
                同步增进,即P与T成正增长关系,则称这样的程序为机器学习系统。
                即:自我完善、自我修正、自我增强
        2、为什么需要机器学习
            1、有助于提高系统的可维护性和可扩展性:
                简化或替换人工方式的模式识别,易于系统的开发维护和升级换代。
            2、用于解决算法非常复杂或没有算法的问题:
                对于那些算法过于复杂,或者没有明确解法的问题,机器学习
                系统具有得天独厚的优势。
            3、规则发现,算法自动生成,获得对业务的洞见:
                通过借鉴机器学习的过程,反向推理出隐藏在业务数据背后的规则
                    ----数据挖掘
        3、机器学习的类型
            1、按照学习方式划分:有监督学习、无监督学习、半监督学习、强化学习
                    强化学习:决策奖励的办法,划分奖励与惩罚的,鼓励奖励类学习
            2、按照学习过程划分:批量学习、增量学习
            3、按照学习策略划分:规则学习(基于模型)、实例学习(基于经验)
        4、机器学习的基本流程
            1、数据准备:
                数据采集
                数据清洗                    
            2、机器学习:
                数据预处理
                选择模型
                训练模型
                验证模型
            3、业务应用:
                使用模型
                维护和升级
        5、机器学习的基本问题
            回归问题:
                由已知的分布于连续域中的输入和输出,通过不断模拟训练,
                找到输入和输出之间的联系,通常这种联系可以通过一个函数
                方程被形式化,如:y=w0+w1x+w2x^2+w3x^3...,当提供未知
                输出的输入时,就可以根据以上函数方程,预测出与之对应的
                连续输出。这就就是回归问题。
                例:
                    根据输入预测分布于连续域中的输出。
                    1    2
                    2    4
                    3    6             ----->  得到预测函数y = 2 x
                    3.5  7      
                    4.5  ? -> 9  
            分类问题:
                如果将回归问题中的输出为连续域,若变为输出离散域,那么
                该问题就是一个分类问题。
                可以说,分类问题是一个特殊的回归问题。
                例:
                    根据输入预测分布于离散域中的输出。
                        1    0
                        2    1
                        3    0      ------>奇偶判断:奇数 0 , 偶数 1
                        4    1      
                        5    ? -> 0
            聚类问题:
                从已知的输入中寻找某种模式,比如相似性,根据该模式将
                输入划分为不同的集群,并对新的输入应用同样的划分方式,
                以确定其归属的集群。
                即:根据样本特征的相似性将其划分为不同的族群
            降维问题:
                在不影响学习效果的前提下减少样本的特征数
                从大量的特征中
                例如高斯模糊,浮雕效果,等等都是保留关键特征的方法
    二、数据预处理
        1.框架
            import sklearn
                经典机器学习框架
                用于学习的科学工具包,使用比较广泛的一种机器学习工具
            import sklearn.preprocessing as sp 
        2.样本矩阵
            在我们所面对的数据中,通常我们会调整为数据结构
            这个数据结构叫:样本矩阵,即训练样本
            分为输入数据和输出数据:
                                 输入数据                输出数据
                            特征1 特征2 特征3 ...
                             身高  体重  年龄  性别
                样本1   1.7   60    25    男
                样本1   1.5   50    20    女
                ...
                输出数据通常为一个一位数组或列向量
                通过机器学习来获得输入数据和输出数据之间关系,以便输出数据
                一个样本,与一个输出数据元素,是一一对应关系。
        3.均值移除(标准化:标准正态分布)
            标准正态分布特征:均值为0,方差为1    
            均值移除主要解决问题:
                在一个样本中,不同特征和均值分散度不一致的问题
                如:特征A 均值为10     误差+-5
                        特征B 均值为1000   误差+-5000
                    此时两个特征体现在一个事件时,特征A就很难体现出来,
                    被特征B淹没了(特征淹没)。
                    解决:通过算法调整令样本矩阵中特征的平均值为0,标准差为1,
                            这样一来,所有特征对最终模型的预测结构结果都有接近一致
                            的贡献,模型对每个特征的倾向更加平衡
            标准化过程:
                1.均值移除过程:
                        如有三个特征,[a b c] 平均值为:m = (a+b+c)/3
                        设a'=a-m  b'=b-m  c'=c-m,
                        得到新的特征值[a' b' c']
                        新特征值的平均值为:
                                m' = (a+b'+c')/3
                                     = (a-m+b-m+c-m)/3
                                     = (a+b+c-3m)/3
                                     = (a+b+c)/3-m = m-m
                                     =0 (均值移除成功)
                2.标准差计算过程:
                        离差分别为:  (a-m)  (b-m)  (c-m)
                        离差方分别为:(a-m)^2  (b-m)^2  (c-m)^2
                                    方差为:((a-m)^2+(b-m)^2+(c-m)^2)/3
                        得到标准差s =sqrt(((a-m)^2+(b-m)^2+(c-m)^2)/3)
                                    得出:(a-m)^2+(b-m)^2+(c-m)^2) = 3s^2
                        将新的特征值除以标准差,得到新的数组:[a" b" c"]
                                其中:a"=a'/s   b"=b'/s  c"=c'/s    
                            对新的数组再次求标准差:
                                计算可得知新数组的均值m"=0
                                标准差s"=sqrt(((a"-m")^2+(b"-m")^2+(c"-m")^2)/3)
                                                =sqrt((a"^2+b"^2+c"^2)/3) 
                                                =sqrt(((a'/s)^2+(b'/s)^2+(c'/s)^2)/3)
                                                =sqrt((a'^2+b'^2+c'^2)/(3s^2))
                                                =sqrt(((a-m)^2+(b-m)^2+(c-m)^2)/(3s^2))
                                                =sqrt((3s^2)/(3s^2))
                                                =1
            自动计算模块:
                sp.scale(原始样本矩阵)-->获得均值移除后的样本矩阵        
            代码示例:std.py
                import numpy as np
                import sklearn.preprocessing as sp
                raw_samples = np.array([ #样本
                        [3, -1.5,    2, -5.4],
                        [0,    4, -0.3,  2.1],
                        [1,  3.3, -1.9, -4.3]
                ])
                #以下手动完成均值移除过程
                print(raw_samples.mean())#这是计算所有元素的平均值
                print(raw_samples.mean(axis=0))#这是按列方向计算平均值
                print(raw_samples.std(axis=0))#按列方向计算标准差
                std_samples = raw_samples.copy()
                for col in std_samples.T: #T转置,通过遍历获得列数据
                        col_mean = col.mean()
                        col_std = col.std()
                        col -= col_mean
                        col /= col_std
                print(std_samples)
                #均值手动移除成功,机器学习训练模型矩阵就用std_samples
                print(std_samples.mean(axis=0)) #都是-16次方以上,为0
                print(std_samples.std(axis=0))#标准差为1
                #以下用sklearn模块自动移除均值
                std_samples = sp.scale(raw_samples)
                print(std_samples)
                print(std_samples.mean(axis=0))
                print(std_samples.std(axis=0))
        4.范围缩放
            概念引例:
                    如果有三组平均分数:A:90, B:80, C:5
                      就怎么看,哪组分数最高?认为90?
                        其实不尽然,因为A是150分制,B是100分制,C是5分制
                        如此看来,5分最高
                所以在此情况下拿分数去训练,显然是不行的,
                此时就需要使用范围缩放:
                    要么统一为0-150方式,要么0-100,要么0-1 ,...
            概念:
                将样本矩阵中每列元素通过某种线性变换(y=kx+b),
                使得所有列的元素都处在同样的范围区间。
            实现过程:                
                设有一个特征数组中有最大值max,最小值min
                已知目标范围最大值max' 1,最小值min' 0
                求解 kx + b = y 的方程组中的k,b
                即:
                    k min + b = min'
                    k max + b = max'
                    | min |  *   | k | = | min' |
                    | max |      | b |   | max' |
                    ----------   -----   ---------
                         a           x             b
                    解线性方程组:
                    x = np.linalg.solve(a, b)     得出k ,b    
            模块:
                范围缩放器=sp.MinMaxScaler(
                        feature_range=(min', max'))
                范围缩放器.fit_transform(原始样本矩阵)
                        ->获得范围缩放后的样本矩阵
            注:有时候也把[0,1]区间作为目标范围的缩放,称为“归一化”
            代码示例:mms.py
                import numpy as np
                import sklearn.preprocessing as sp
                raw_samples = np.array([ #样本
                        [3, -1.5,    2, -5.4],
                        [0,    4, -0.3,  2.1],
                        [1,  3.3, -1.9, -4.3]
                ])
                mms_samples = raw_samples.copy()
                #以下手动方法计算范围缩放:
                for col in mms_samples.T:
                        col_max = col.max()
                        col_min = col.min()
                        a = np.array([
                                [col_min,1],
                                [col_max,1]
                        ])
                        b = np.array([0,1])
                        x = np.linalg.solve(a,b)
                        #根据:y=kx+b
                        col *= x[0] # kx
                        col += x[1] # kx + b
                print(mms_samples)
                #以下模块缩放器计算范围缩放:
                mms = sp.MinMaxScaler(feature_range=(0, 1)) #创建缩放器
                mms_samples = mms.fit_transform(raw_samples)#获得范围缩放后的样本矩阵
                print(mms_samples)
        5.归一化
            概念:
                用每个样本的各个特征值占该样本所有特征值的绝对值的总和
                的比例来代替该特征值本身。
                即:特征值占比来代替特征值
            概念引例:
                以下为各语言各年份使用人数的样本:
                                Python   Java   C++    PHP
                    2017     10     20      5     2
                    2018     20     10     10     1
                    2019      5     2      1      0
                    样本值 / 特征值之和:
                                         10/37 --> (10+20+5+2)/37 *100% = 1 
                                         20/41        所以叫归一
                                             5/8          通过占比反映增量趋势
            模块:sp.normalize(, norm='l1')
                        ->归一化后的样本矩阵
                norm=    'l1':绝对值之和,l1范数
                          'l2':绝对值平方之和,l2范数
                             ...
                            'ln':绝对值n次方之和,ln范数
            代码示例:nor.py
                import numpy as np
                import sklearn.preprocessing as sp
                raw_samples = np.array([ #样本
                        [3, -1.5,    2, -5.4],
                        [0,    4, -0.3,  2.1],
                        [1,  3.3, -1.9, -4.3]
                ])
                nor_samples = raw_samples.copy()
                #以下手动归一化
                for row in nor_samples:
                        row_abssum = abs(row).sum()
                        row /= row_abssum
                print(nor_samples)
                print(abs(nor_samples).sum(axis=1))
                #以下使用模块归一化
                nor_samples = sp.normalize(raw_samples,norm='l1')
                print(nor_samples)
                print(abs(nor_samples).sum(axis=1))
        6.二值化
            概念:
                根据给定的阈值,将样本矩阵中的每一个特征值与该阈值进行
                比较,凡是大于该阈值者为1,否则为0,将样本矩阵简化为只
                由0和1组成的矩阵,以此来简化学习模型。
                可称为0,1化,或者叫开关化
                对细节不关心
            模块:
                二值化器=sp.Binarizer(threshold=阈值)
                二值化器.transform(原始样本矩阵)
                        ->二值化后的样本矩阵
            代码示例:bin.py
                import numpy as np
                import sklearn.preprocessing as sp
                raw_samples = np.array([ #样本
                        [3, -1.5,    2, -5.4],
                        [0,    4, -0.3,  2.1],
                        [1,  3.3, -1.9, -4.3]
                ])
                bin_samples = raw_samples.copy()
                #假如设定阈值为1.4
                bin_samples[bin_samples <= 1.4] =0
                bin_samples[bin_samples > 1.4] =1
                print(bin_samples)
                #模块创建
                bin = sp.Binarizer(threshold=1.4)
                bin_samples = bin.transform(raw_samples)
                print(bin_samples)
        7.独热编码
            概念:
                用一个只包含一个1和若干个0的序列来表达每个特征值的编码方式,
                借此即保留了样本矩阵的所有细节,同时又得到一个只包含1、0
                的稀疏矩阵,即可以提供模型的容错性,同时还能节省内存空间。
            概念引例:
                假如有以下4个样本,3个特征:
                        1        3        2
                        7        5        4
                        1        8        6
                        7        3        9
                    --------------------------
                    第一列:1用10表示,7用01表示
                    第二列:3用100表示,5用010表示,8用001表示
                    第三列:2用1000表示,4用0100表示,6用0010表示,9用0001表示
                    得到以下编码字典:
                        1:10  3:100 2:1000
                        7:01  5:010 4:0100
                                    8:001 6:0010
                                                9:0001
                    将编码字典对原矩阵进行替换如下:
                        101001000
                        010100100
                        100010010
                        011000001
                    变为典型的二值稀疏矩阵,就形成了独热编码
            模块:
                独热编码器=sp.OneHotEncoder(categories='auto',
                        sparse=是否紧凑, dtype=元素类型)
                独热编码器.fit_transform(原始样本矩阵)
                        ->独热编码后的样本矩阵
            代码示例:ohe.py:
                import numpy as np
                import sklearn.preprocessing as sp
                raw_samples = np.array([ #样本
                        [1 ,       3 ,       2],
                        [7 ,       5 ,       4],
                        [1 ,       8 ,       6],
                        [7 ,       3 ,       9]
                ])
                #以下手动创建独热编码:
                code_tables = []#建立编码字典列表
                for col in raw_samples.T:
                        #针对一列创建编码字典
                        code_table={}
                        for val in col:
                                code_table[val] = None
                        code_tables.append(code_table)
                #为编码字典列表中的编码字典添加值
                for code_table in code_tables:
                        size = len(code_table)
                        #code_table.keys()对每个列键排序
                        #enumerate(sorted(code_table.keys())),获得排序序号
                        for one,key in enumerate(sorted(code_table.keys())):
                                code_table[key]=np.zeros(shape=size,dtype=int)
                                code_table[key][one] = 1
                #根据编码字典表对原始样本矩阵做独热编码
                ohe_samples = []
                for raw_sample in raw_samples:
                        ohe_sample = np.array([],dtype=int)
                        for i,key in enumerate(raw_sample):
                                ohe_sample = np.hstack((ohe_sample,code_tables[i][key]))
                        ohe_samples.append(ohe_sample)
                ohe_samples = np.array(ohe_samples)
                print(ohe_samples)
                #使用独热编码器模块:
                ohe = sp.OneHotEncoder(sparse=False,dtype=int,categories='auto')
                ohe_samples = ohe.fit_transform(raw_samples)
                print(ohe_samples)
        8.标签编码
            概念:
                将文本形式的特征值变为数值形式的特征值
                将样本矩阵中的非数值列,按照字典序中的序号进行替换,
                以此把非数值形式的特征值数值化,便于在学习模型中参与运算。
            概念引例:
                    职务    编码1     车     编码2
                    员工    3     丰田    3
                    组长    4     福特        4
                    经理        1     奥迪    1
                    老板        2     宝马    2
                    编码数值顺序按照字符顺序,与本身含义顺序无关
                    如有关,则不能使用标签编码
            模块:
                标签编码器=sp.LabelEncoder()
                标签编码器.fit_transform(原始非数值列)
                        ->标签编码后的数值列
                逆向标签编码器.inverse_tansform(标签编码后的数值列)
                        ->原始非数值列
            代码示例:lab.py:
                import numpy as np
                import sklearn.preprocessing as sp
                raw_samples = np.array(
                        ['audi' ,'ford','audi','toyota','ford','bmw','toyota','bmw'])
                lbe =  sp.LabelEncoder()
                lbe_samples = lbe.fit_transform(raw_samples)
                print(lbe_samples)
                raw_samples = lbe.inverse_transform(lbe_samples)
                print(raw_samples)
    三、一元线性回归
        1.预测函数
                    根据输入预测分布于连续域中的输出。
                        1    2
                        2    4
                        3    6    -----> 得到预测函数y = 2 x
                        3.5  7      
                        4.5  ?  -----> 9 
                一元预测函数模型为:y=w0+w1x 
                注:一元线性回归的方程一定是这样的模型格式
                任务就是通过寻找预测函数模型参数w0和w1,
                以便满足输入和输出之间的联系
        2.单样本误差
            假定有一值为x,对应的实际值为y,
            带入方程后,得到预测值,即y':
                x--->[y=w0+w1x]-->y'-->y-y'就是样本误差
            单样本误差e = (1/2)*(实际值y-预测值y')^2
        3.总样本误差
            E=∑(e)=∑((1/2)*(y-y')^2)
        4.损失函数
            Loss(w0,w1)= ∑((1/2)*(y-y')^2) = ∑((1/2)*(y-(w0+w1x))^2)
            一元线性回归任务变为:
             寻找可以使损失函数取得最小值的模型参数w0和w1。
        5.梯度下降法
            随机选择一组模型参数w0和w1
            计算损失函数在该模型参数处的梯度<------+ 
                [∂loss/∂w0,∂loss/∂w1]                |
            再计算与该梯度反方向的修正步长         |
                [-η∂loss/∂w0,-η∂loss/∂w1] η学习率    |
            再计算下一组模型参数:                 |
                w0 = w0-η∂loss/∂w0                   |
                w1 = w1-η∂loss/∂w1 ----------------->+
            注:η学习率 (learning rate),控制模型的学习进度
                    学习率设置
                            在训练过程中,一般根据训练轮数设置动态变化的学习率。
                            刚开始训练时:学习率以 0.01 ~ 0.001 为宜。
                            一定轮数过后:逐渐减缓。
                            接近训练结束:学习速率的衰减应该在100倍以上。
                            
            再执行下一个循环,计算梯度,逐渐逼近
            直到满足迭代终止条件:
                    迭代次数足够多,如10万次
                    或损失值已经足够小
                    或损失值已经不再明显减少
            Loss(w0,w1)= ∑((1/2)*(y-y')^2) , y'= w0 + w1x
            ∂loss/∂w0
             =∑(∂(1/2)*(y-y')^2)/∂w0)
             =∑((y-y')*∂(y-y')/∂w0)
             =∑((y-y')*(∂y/∂w0-∂y'/∂w0)) 因为y是已知常量,所以∂y/∂w0=0
       =-∑((y-y')*(∂y'/∂w0))    因为∂y'/∂w0=1
             =-∑((y-y'))
            ∂loss/∂w1
             =∑(∂(1/2)*(y-y')^2)/∂w1)
             =∑((y-y')*∂(y-y')/∂w1)
             =∑((y-y')*(∂y/∂w1-∂y'/∂w1)) 因为y是已知常量,所以∂y/∂w1=0
       =-∑((y-y')*(∂y'/∂w1))    因为∂y'/∂w1=x
             =-∑((y-y')*x)
        6.多元线性回归
            即样本函数模型为:y=w0+w1x1+w2x1+...+wnxn
            其实质同一元线性回归是一样的。
            Loss(w0,w1,w2,...,wn) = ∑((1/2)*(y-(w0+w1x1+w2x2+...+wnxn]))^2)
            w0 = w0-η∂loss/∂w0 
            w1 = w1-η∂loss/∂w1
            w2 = w2-η∂loss/∂w2
                    ...        ...
            wn = wn-η∂loss/∂wn
            ∂loss/∂w0 = -∑((y-y'))
            ∂loss/∂w1 = -∑((y-y')*x1)
            ∂loss/∂w2 = -∑((y-y')*x2)
                    ...        ...
            ∂loss/∂wn = -∑((y-y')*xn)
            预测函数:y'= w0+w1x1+w2x2+...+wnxn
        6.模块
            import sklearn.linear_model as lm
            线性回归器 = lm.LinearRegression()
            线性回归器.fit(已知输入,已知输出) #计算模型参数
            线性回归器.predict(新的输入)-->获得新的输出(预测输出)
        7.模型保存与调用
            import pickle
            保存:
                预测输出成功后,即可保存预测模型
                with open('文件名','wb') as f: 
                    pickle.dump(model,f)
            调用:
                with open('模型文件','rb') as f: 
                    model = pickle.load(f)
        8.示例代码:
            示例一:手动处理 gd.py (手动处理线性回归)
                import numpy as np
                import matplotlib.pyplot as mp
                from mpl_toolkits.mplot3d import axes3d
                train_x = np.array([0.5,0.6,0.8,1.1,1.4]) #输入样本
                train_y = np.array([5.0,5.5,6.0,6.8,7.0]) #输出样本
                #手动方法实现一元线性回归:
                n_epoches = 1000 #设定迭代终止条件:最大迭代次数
                lrate = 0.01  # η学习率
                epoches,losses = [],[] #epoches迭代批次列表 , losses 每次迭代损失值
                w0,w1 = [1],[1]  #保存每次迭代得出的值,初始值设为1
                for epoch in range(1,n_epoches + 1):
                        epoches.append(epoch)
                        furch_y = w0[-1] + w1[-1] * train_x #预测输出y'
                        losses.append(
                        ((train_y - furch_y)**2/2).sum())#Loss(w0,w1)= ∑((1/2)*(y-y')^2)计算损失值
                        # print('{:4}>w0={:.8f},|w1={:.8f},loss={:.8f}'.format(
                        #     epoches[-1],w0[-1],w1[-1],losses[-1]
                        # ))
                        d0 = -(train_y - furch_y).sum() #∂loss /∂w0 = -∑((y-y'))
                        d1 = -((train_y - furch_y) * train_x).sum() #∂loss/∂w1 = -∑((y-y')* x)
                        w0.append(w0[-1] - lrate * d0)  # w0 = w0 - η∂loss/∂w0
                        w1.append(w1[-1] - lrate * d1)  # w1 = w1 - η∂loss/∂w1
                w0 = np.array(w0[:-1]) #注:实际w0会产生1001组数据,所以少去一个。
                w1 = np.array(w1[:-1])
                sorted_indexes = train_x.argsort()
                test_x = train_x[sorted_indexes]
                test_y = train_y[sorted_indexes]
                pred_test_y = w0[-1] + w1[-1] * test_x #预测输出,一元线性方程y = w0 + w1 * x
                grid_w0,grid_w1 = np.meshgrid(  #创建点阵并网格化
                        np.linspace(0,9,500), np.linspace(0,3.5,500))
                #用网格化计算对应损失值
                flat_w0,flat_w1 = grid_w0.ravel(),grid_w1.ravel() #扁平化视图
                flat_loss = (((flat_w0 + np.outer(train_y,flat_w1))-\
                                        train_y.reshape(-1,1))**2).sum(axis=0)/2 #outer外积  计算损失值
                grid_loss = flat_loss.reshape(grid_w0.shape)
                mp.figure('Linear Regression',facecolor='lightgray')
                mp.title('Linear Regression',fontsize=20)
                mp.xlabel('x',fontsize=14)
                mp.xlabel('y',fontsize=14)
                mp.tick_params(labelsize=10)
                mp.grid(linestyle=':')
                mp.scatter(train_x,train_y,marker='s',c='dodgerblue',
                                alpha=0.5,s=80,label='Traning')  #训练样本点
                mp.scatter(test_x,test_y,marker='D',c='orangered',
                                alpha=0.5,s=40,label='Testing')
                mp.scatter(test_x,pred_test_y,c='orangered',
                                alpha=0.5,s=40,label='Predicted')  #预测输出
                for x,y,pred_y in zip(test_x,test_y,pred_test_y):#连线长度即为单样本误差
                        mp.plot([x,x],[y,pred_y],c='orangered',alpha=0.5,linewidth=1)
                mp.plot(test_x,pred_test_y,'--',c='limegreen',
                                label='Regression',linewidth=1)
                mp.legend()
                #训练过程
                mp.figure('Training Progress',facecolor='lightgray')
                mp.subplot(311)
                mp.title('Training Progress',fontsize=20)
                mp.ylabel('w0',fontsize=14)
                mp.gca().xaxis.set_major_locator(mp.MultipleLocator(100))
                mp.tick_params(labelsize=10)
                mp.grid(linestyle=':')
                mp.plot(epoches,w0,c='dodgerblue',label='w0')
                mp.legend()
                mp.subplot(312)
                mp.ylabel('w1',fontsize=14)
                mp.gca().xaxis.set_major_locator(mp.MultipleLocator(100))
                mp.tick_params(labelsize=10)
                mp.grid(linestyle=':')
                mp.plot(epoches,w1,c='limegreen',label='w1')
                mp.legend()
                mp.subplot(313)#损失值
                mp.title('loss',fontsize=20)
                mp.xlabel('epoch',fontsize=14)
                mp.ylabel('loss',fontsize=14)
                mp.gca().xaxis.set_major_locator(mp.MultipleLocator(100))
                mp.tick_params(labelsize=10)
                mp.grid(linestyle=':')
                mp.plot(epoches,losses,c='orangered',label='loss')
                mp.legend()
                mp.tight_layout()
                mp.figure('Loss function')
                ax = mp.gca(projection='3d')
                mp.title('Loss function',fontsize=20)
                ax.set_xlabel('w0',fontsize=14)
                ax.set_ylabel('w1',fontsize=14)
                ax.set_zlabel('loss',fontsize=14)
                mp.tick_params(labelsize=10)
                #mp.grid(linestyle=':')
                ax.plot_surface(grid_w0,grid_w1,grid_loss,
                                                rstride=10,cstride=10,cmap='jet')
                ax.plot(w0,w1,losses,'o-',c='orangered',label='BGD')
                mp.legend()
                #梯度下降
                mp.figure('Batch Gradient Descent',facecolor='lightgray') #批量梯度下降
                mp.title('Batch Gradient Descent',fontsize=20)
                mp.xlabel('x',fontsize=14)
                mp.xlabel('y',fontsize=14)
                mp.tick_params(labelsize=10)
                mp.grid(linestyle=':')
                mp.contourf(grid_w0,grid_w1,grid_loss,1000,cmap='jet')#等高线图
                cntr = mp.contour(grid_w0,grid_w1,grid_loss,10,colors='black',
                                     linewidths=0.5)
                mp.clabel(cntr,inline_spacing=0.1,fmt='%.2f',
                                    fontsize=8)#标准等高线高度值
                mp.plot(w0,w1,'o-',c='orangered',label='BGD')
                mp.legend()
                mp.show()
            示例二:模块处理 line.py(模块处理线性回归)
                import numpy as np
                import matplotlib.pyplot as mp
                import sklearn.linear_model as lm
                import sklearn.metrics as sm
                # train_x = np.array([0.5,0.6,0.8,1.1,1.4]) #输入样本
                # train_y = np.array([5.0,5.5,6.0,6.8,7.0]) #输出样本
                # lm = lm.LinearRegression()
                # lm.fit(train_x.reshape(train_x.size,1),train_y)
                # print(lm.predict(train_x.reshape(train_x.size,1)))
                x,y = [],[]
                with open('./data/single.txt','r') as f:
                        for line in f.readlines():
                             data = [float(substr) for substr in  line.split(',')]
                             x.append(data[:-1])
                             y.append(data[-1])
                x = np.array(x)
                y = np.array(y)
                model = lm.LinearRegression()
                model.fit(x,y)
                pred_y = model.predict(x)#预测输出 y是实际输出,两者之差为样本误差
                #sm.r2_score二次得分,看看二者有多少相等,多少不等
                r2score =sm.r2_score(y,pred_y) # 计算公式:1/(1+E) 误差归一化
                #print(r2score)   #误差越小,r2score越接近1
                mp.figure('Linear Regression',facecolor='lightgray')
                mp.title('Linear Regression',fontsize=20)
                mp.xlabel('x',fontsize=14)
                mp.xlabel('y',fontsize=14)
                mp.tick_params(labelsize=10)
                mp.grid(linestyle=':')
                mp.scatter(x,y,marker='s',c='dodgerblue',
                                alpha=0.75,s=60,label='Traning') #样本散点图
                sorted_indices = x.ravel().argsort()#画图前排序
                mp.plot(x[sorted_indices],pred_y[sorted_indices],
                                c='orangered',label='Regression') #绘制回归线:预测输出线
                mp.legend()
                mp.tight_layout()
                mp.show()
            示例三:保存预测模型 dump.py
                import pickle    #序列号工具,内存和文件进行序列号
                import numpy as np
                import sklearn.linear_model as lm
                import sklearn.metrics as sm
                x,y = [],[]
                with open('./data/single.txt','r') as f:
                        for line in f.readlines():
                             data = [float(substr) for substr in  line.split(',')]
                             x.append(data[:-1])
                             y.append(data[-1])
                x = np.array(x)
                y = np.array(y)
                model = lm.LinearRegression()
                model.fit(x,y)
                pred_y = model.predict(x)#预测输出 y是实际输出,两者之差为样本误差
                #sm.r2_score二次得分,看看二者有多少相等,多少不等
                r2score =sm.r2_score(y,pred_y) # 计算公式:1/(1+E) 误差归一化
                #print(r2score)   #误差越小,r2score越接近1
                with open('./data/linear.pkl','wb') as f: #保存训练模型
                        pickle.dump(model,f)
            示例四:调用训练模型 load.py
                import pickle    #序列号工具,内存和文件进行序列号
                import numpy as np
                import sklearn.metrics as sm
                x,y = [],[]
                with open('./data/single.txt','r') as f:
                        for line in f.readlines():
                             data = [float(substr) for substr in  line.split(',')]
                             x.append(data[:-1])
                             y.append(data[-1])
                x = np.array(x)
                y = np.array(y)
                with open('./data/linear.pkl','rb') as f: #调查已经存在的模型
                        model = pickle.load(f)
                pred_y = model.predict(x)
                r2score =sm.r2_score(y,pred_y)
                print(r2score)
    四、岭回归
        1.概念
            因loss(w0,w1)=∑((1/2)*(y-(w0+w1x]))^2)
            岭回归方程为:
                Loss(w0,w1)=loss(w0,w1)-正则强度*f(w0,w1)(正则项)
                f(w0,w1)称为正则项
                目的是要让Loss(w0,w1)达到最小,但因为有了
                正则强度*正则项的存在,loss(w0,w1)则会偏离最小值
                如果正则强度*正则项越大,则loss(w0,w1)对异常样本的
                倾向性就会越弱。通过正则强度进行控制。
            通过正则的方法,即在损失函数中加入正则项,
                以减弱模型参数对熟练数据的匹配度,以此规避少量样本
                因为明显偏移正常范围的异常而影响模型的回归效果。
            注:此处正则不是对字符串的操作,不是正则表达式的意思
                    而是让步的意思
            普通的线性回归,在计算总样本误差即损失值时,对所有训
            练样本一视同仁,因此极少数"坏"样本会使得预测模型偏离
            于大多数好样本所遵循的规则,影响模型的预测精度。
            岭回归就是:
                在线性回归的基础之上,为每个训练样本分配不同的权重,越是
                能够反应一般规律的大多数好样本所得到的权重越大,而极少数
                偏离于一般规律的坏样本则只能获得较低的权重,从而使得最终
                的预测模型尽可能偏向于多数好样本,而弱化少数坏样本对模型
                的影响。
        2.模块
            model = lm.Ridge(正则强度,fit_intercept=True)
            fit_intercept:是否约束斜率和截距,
                                        True反向破坏样本匹配效果
            正则强度:也是叫惩罚力度:[0, oo)
            正则强度越小,权重差异就越小,0表示无差异,等同线性回归
            类似正则强度这些数据,叫超参数,因为无法通过算法得出,
                只能通过实验或试验人为获得的数据。
                但有一种自动化选优的方式获取超参数
            网格搜索是一种自动化选优的方法:把所有超参数排列组合到
                一个表中,可以自动一个一个去测试,然后将结果分值都返回,
                然后挑选一个分值(或效果)最好的作为最终使用的参数。
            可不同行业,不同的数据源,创建超参数经验数据表
        代码示例:rdg.py
            import numpy as np
            import matplotlib.pyplot as mp
            import sklearn.linear_model as lm
            x,y = [],[]
            with open('./data/abnormal.txt','r') as f:
                    for line in f.readlines():
                         data = [float(substr) for substr in  line.split(',')]
                         x.append(data[:-1])
                         y.append(data[-1])
            x = np.array(x)
            y = np.array(y)
            model1 = lm.LinearRegression() #model1为线性回归模型
            model1.fit(x,y)
            pred_y1 = model1.predict(x)#线性回归预测值
            model2 = lm.Ridge(300,fit_intercept=True)#model2为岭回归模型
            model2.fit(x,y)
            pred_y2 = model2.predict(x)#岭回归预测值
            mp.figure('Linear & Ridge Regression',facecolor='lightgray')
            mp.title('Linear & Ridge Regression',fontsize=20)
            mp.xlabel('x',fontsize=14)
            mp.xlabel('y',fontsize=14)
            mp.tick_params(labelsize=10)
            mp.grid(linestyle=':')
            mp.scatter(x,y,marker='s',c='dodgerblue',
                            alpha=0.75,s=60,label='Traning') #样本散点图
            sorted_indices = x.ravel().argsort()
            mp.plot(x[sorted_indices],pred_y1[sorted_indices],
                            c='orangered',label='Linear') #绘制线性回归线
            mp.plot(x[sorted_indices],pred_y2[sorted_indices],
                            c='dodgerblue',label='Ridge') #绘制岭回归线
            #可以看出,岭回归线受上方三个不良样本的影响较小
            #正则强度如果0,则岭回归就同线性回归重叠
            mp.legend()
            mp.tight_layout()
            mp.show()
    五、多项式回归
        1.概念
            y = w0+w1x+w2x^2+w3x^3+...+wnx^n
            令:x=x1, x^2=x2, x^3=x3 ,..., x^n=xn
            以上多项式回归方程就简化为多元线性回归方程
            即:y = w0+w1x1+w2x2+w3x3+...+wnxn
            loss = Loss(w0,w1,...,wn)
            x->多项式特征扩展-x1,x2,x3,...,xn->线性回归->w0~wn
                        \________________________________/
                                                管线                                                                                        
        2.模块
            import sklearn.pipeline as pl
            import sklearn.preprocessing as sp
            多项式特征扩展器=sp.PolynomialFeatures(最高次幂)
            线性回归器=lm.LinearRegression()
            管线模型=pl.make_pipeline(多项式特征扩展器,线性回归器)
            管线模型.fit(x,y) # [x,y]-BGD->[w0,w1,w2,w3,...,wn]
            管线模型.predict(x)->pred_y
        3.欠拟合:过于简单的模型,或者训练集的规模过小,导致模型无法真实
            地反应输入和输出之间的规律,出现训练集和测试集的评估分值都比
            较低的现象。可以通过增加模型的复杂度,或者增加训练集的规模,
            提高模型的拟合度,优化其性能。
        4.过拟合:过于复杂的模型,或者特征数过多,导致模型失去足够的一般性,
            即太过于倾向训练数据,反而对训练集以外的预测性能大幅下降。可以
            减少特征数,或者降低模型的复杂度,在训练集和测试集的拟合程度上
            寻求一个折衷,提高模型的泛化能力。
        5.代码示例:poly.py
            import numpy as np
            import sklearn.pipeline as pl
            import sklearn.preprocessing as sp
            import sklearn.metrics as sm
            import matplotlib.pyplot as mp
            import sklearn.linear_model as lm
            train_x,train_y = [],[]
            with open('./data/single.txt','r') as f:
            #with open('./data/abnormal.txt', 'r') as f:
                    for line in f.readlines():
                         data = [float(substr) for substr in  line.split(',')]
                         train_x.append(data[:-1])
                         train_y.append(data[-1])
            train_x = np.array(train_x)
            train_y = np.array(train_y)
            #在多项式特征扩展器的参数是超参数,合适的大小才能真实反映样本情况
            #过大,容易形成过拟合,太小,欠拟合
            sp = sp.PolynomialFeatures(10)#多项式特征扩展器,最高为x**10,增加9列,共10列
            lm = lm.LinearRegression() #线性回归器
            model = pl.make_pipeline(sp,lm) #创建多项式管线模型
            model.fit(train_x,train_y) #计算模型参数(w0,w1,...w10)
            pred_train_y = model.predict(train_x) #获得多项式回归预测值
            print(sm.r2_score(train_y,pred_train_y))
            test_x = np.linspace(train_x.min(),train_x.max(),1000).reshape(-1,1)
            pred_test_y = model.predict(test_x)
            mp.figure('Polynomial Regression',facecolor='lightgray')
            mp.title('Polynomial Regression',fontsize=20)
            mp.xlabel('x',fontsize=14)
            mp.xlabel('y',fontsize=14)
            mp.tick_params(labelsize=10)
            mp.grid(linestyle=':')
            mp.scatter(train_x,train_y,c='dodgerblue',
                            alpha=0.75,s=60,label='Sample')
            mp.plot(test_x,pred_test_y,c='orangered',label='Regression')
            mp.legend()
            mp.tight_layout()
            mp.show()

猜你喜欢

转载自blog.csdn.net/pinecn/article/details/89743056