利用随机梯度递减解决线性回归问题(附python代码)

数据来源:来自加州大学埃文分校(UCI)机器学习数据库,采用白酒质量数据集合,共有4898条数据,共包含12项评价指标分别为酸度、游离二氧化硫、密度、pH、氯化物、硫酸盐、酒精度含量等,最后一项表示白酒的评级(0-10级)

链接:http://archive.ics.uci.edu/ml/datasets/Wine+Quality

一、认识数据

通过观察数据,有些指标范围在0-1之间,有些指标取值范围大的数百,小的又在小数点的百分位浮动,如果不对数据特征作处理,小数据特征很容易被大数据特征淹没,要进行归一化处理。

二、数据读取及预处理

定义了Database类,主要负责完成数据的读取和预处理。预处理包含两部分:(1)把csv文件中读取的字符串数值,转换为可计算的浮点数(由dataset_str_to_float方法来完成);(2)将第(1)步加工过的数据做归一化处理。

from csv import reader
class Database():
        def __init__(self):
            self.dataset=list()

        # 导入csv文件
        def load_csv(self,filename):
            with open(filename,'r',encoding='utf-8') as file:
                csv_reader=reader(file)
                headings=next(csv_reader)    # 读取表头,文件指针下移至第一条真正的数据
                for row in csv_reader:
                    if not row:       # 判定是否有空行,如有,则跳入下一行
                        continue
                    self.dataset.append(row)

        # 将字符串数转换为浮点数
        def dataset_str_to_float(self):
            col_len=len(self.dataset[0])
            for row in self.dataset:
                for column in range(col_len):
                    row[column]=float(row[column].strip())

        # 找到每一列(属性)的最小值和最大值
        def _dataset_minmax(self):
            self.minmax=list()
            for i in range(len(self.dataset[0])):
                col_values=[row[i] for row in self.dataset]
                value_min=min(col_values)
                value_max=max(col_values)
                self.minmax.append([value_min,value_max])

         # 将数据集合中的每个(列)属性都规整化到0~1之间
        def normalize_dataset(self):
            self._dataset_minmax()     # 获取每一列的最小值,最大值
            for row in self.dataset:
                for i in range(len(row)):
                    row[i]=(row[i]-self.minmax[i][0])/(self.minmax[i][1]-self.minmax[i][0])
            return self.dataset

三、训练模型,找到适配数据的权值

定义了线性单元类LinearUnit,它利用随机梯度递减的策略,完成权值网络更新的功能。

class LinearUnit(object):
    def __init__(self,input_para_num,acti_func):
          """
          :param input_para_num:
          :param acti_func:
          """
          self.activator=acti_func      # 初始化线性单元激活函数

    def predict(self,row_vec):
          """
          :param row_vec: 输入向量,输出线性单元的预测结果
          :return:
          """
          act_values=self.weights[0]
          for i in range(len(row_vec)-1):
              act_values+=self.weights[i+1]*row_vec[i]
          return self.activator(act_values)

    def train_sgd(self,dataset,rate,n_epoch):
          """
          :param dataset: 训练数据
          :param rate: 学习率
          :param n_epoch: 训练轮数
          :return:
          """
          self.weights=[0.0 for i in range(len(dataset[0]))]   # 权重向量初始化为0
          for i in range(n_epoch):
              for input_vec_label in dataset:
                  prediction=self.predict(input_vec_label)
                  self._update_weights(input_vec_label,prediction,rate)    # 更新权值

    def _update_weights(self,input_vec_label,prediction,rate):
          delta=input_vec_label[-1]- prediction
          self.weights[0]=self.weights[0]+rate+delta   # 更新权值:第一个哑元的权值
          for i in range(len(self.weights)-1):
              self.weights[i+1]=self.weights[i+1]+rate*delta*input_vec_label[i]

定义激活函数

# 定义激活函数f
def func_activator(input_value):
        return input_value

四、对测试数据进行预测,以验证模型的正确性

定义主方法,从训练数据中随机抽取4条数据,来验证模型的正确性(这些测试数据也必须先进行归一化处理,保证模型与测试数据在同一尺度上)。

# 构建训练数据
def get_training_dataset():
    db=Database()
    db.load_csv("winequality-white.csv")
    db.dataset_str_to_float()
    dataset=db.normalize_dataset()
    return dataset

def train_linear_unit():
    dataset=get_training_dataset()
    l_rate=0.01
    n_epoch=100
    linear_unit=LinearUnit(len(dataset[0]),func_activator)   # 创建训练线性单元,输入参数的特征数
    linear_unit.train_sgd(dataset,l_rate,n_epoch)   # 训练,迭代100轮,学习率为0.01
    return linear_unit          # 返回训练好的线性单元


if __name__=='__main__':
     LU=train_linear_unit()    # 获取训练数据并训练
     print("weights =",LU.weights)   # 打印训练获得的权重
     test_datas=[[0.38,0.14 ,0.23 ,0.15 ,0.15 ,0.09 ,0.21 ,0.18 ,0.36 ,0.29 ,0.32 ,0.5],
            [0.32,0.26 ,0.20 ,0.18 ,0.12 ,0.01 ,0.06 ,0.14 ,0.37 ,0.20 ,0.56 ,0.5],
            [0.32,0.12 ,0.20 ,0.03 ,0.07 ,0.16 ,0.33 ,0.06 ,0.40 ,0.20 ,0.76 ,0.66],
            [0.37,0.16 ,0.16 ,0.02 ,0.12 ,0.17 ,0.42 ,0.11 ,0.46 ,0.33 ,0.45 ,0.5]]
     for i in range(len(test_datas)):
        pred=LU.predict(test_datas[i])
        print("期望值={0},预测值={1}".format(test_datas[i][-1],pred))


输出结果:

weights = [1.3839765803171225, -0.9551010731530127, -0.427351513938813, -0.2812656304046924, 1.0103283347419902, -0.5671087345073004, -0.13481327366753815, -0.3471629881143812, -2.262791619220822, -0.4288675410738061, 0.04115382495757484, -0.2481081346020334]
期望值=0.5,预测值=0.2488085833942974
期望值=0.5,预测值=0.3964262500184253
期望值=0.66,预测值=0.3376413270279569
期望值=0.5,预测值=0.1563832018348324

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值