线性回归、梯度下降原理介绍与案例python代码实现

梯度下降的公式:


其中L(θ)为损失函数;θ为参数值;α为学习速率,α越大每次迭代损失函数值下降越快,w变化越大。

下面我们来看一个二维参数的例子来说明,梯度下降的来源,为什么可以达到局部最低点。


图中每一个圈为一个等高线,具有相同的损失函数值,梯度下降的作用就是找到一个方向使得红点向最低点靠近,即使得损失函数值降低。每经过一次迭代w更新一次,损失函数值降低一次。红圈的半径为r

梯度下降的公式来源于泰勒的一阶展开式

泰勒公式就是说一个函数如果可无数次微分则有:


如果x与a非常接近时有


当上述红圈足够小是则有足够靠近a、b

损失函数的一阶泰勒展开式为:


其中为常数,分别设为s、u、v,则有:


其中:

要使得L(θ)最小,则要使==,则有:


其中a,b分别为参数的初始值,u、v分别为参数的偏导值;α为学习速率恒正,大小由半径r决定。

案例数据下载地址

#载入必须使用的python库
import csv
import numpy as np
import pandas as pd
import os
import math

#将数据保存到当前工作目录。
#若不知道当前工作目录可执行
os.getcwd()
#读取训练数据
file = open('train.csv','r',encoding='big5')
reader = csv.reader(file,delimiter=',')
data = []
n_row = 0
#在列表中创建18个空的子列表用于存放不同的变量数据,即是数据中每天中每个小时环境的检测数据类型(共18个)
for i in range(18):
    data.append([])
for row in reader:
    if n_row != 0:
        for i in range (3,27):
            if row[i] != 'NR':#'NR'代表当天没下雨,为字符串,通过以下条件可以避开无法浮点化的情况
                data[(n_row-1)%18].append(float(row[i]))
            else:
                data[(n_row-1)%18].append(float(0))
    n_row +=1 
file.close()

x = []
y = []
#数据共包含12个月。
for i in range(12):
    #每个月按时间每连续的10个小时做为一个样本,每个月共有471个样本
    for j  in range(471):
        x.append([])
        #每个小时有18个变量
        for t in range(18):
            #每个样本训练数据的x有9个小时的数据
            for s in range(9):
                x[471*i+j].append(data[t][480*i+j+s])
        #y以上面为例
        y.append(data[9][480*i+j+9])
    
#使用numpy库将x、y数组化
x= np.array(x)
y=np.array(y)
#此举是为了添加截距项
x=np.concatenate((np.ones((x.shape[0],1)),x),axis=1)
#设置参数w初始值           
w = np.zeros(len(x[0]))
#设置学习速率
l_rate = 10
#设置学习次数
repeat = 10000
#将x矩阵转置
x_t = x.transpose()
#创建全为0的数组
s_gra = np.zeros(len(x[0]))
#以下为梯度下降
for i in range(repeat):    
    hypo = np.dot(x,w)#参数与样本矩阵相乘计算出估计值    
    loss=hypo-y#估计值与真实值相减
    cost=np.sum(loss**2)/len(x)#计算出损失函数的值
    cost_a=math.sqrt(cost)
    gra=2*np.dot(x_t,loss)#梯度下降求偏导后的矩阵
    s_gra=s_gra+gra**2
    ada=np.sqrt(s_gra)#用于调整学习速率
    w=w-l_rate*gra/ada#梯度下降公式
    print('迭代次数:%d | 损失函数值:%f ' % (i,cost))

np.save('线性回归与梯度下降.npy',w)
w= np.load('线性回归与梯度下降.npy')

#读取测试数据
test_x = []
file_test = open('test.csv','r',encoding='big5')
data_test=csv.reader(file_test,delimiter=',')
r_row=0
for row in data_test:
    if r_row%18 == 0:
        test_x.append([])
        for i in range(2,11) :
            if row[i] !='NR':                
                test_x[r_row//18].append(float(row[i]))
            else:
                test_x[r_row//18].append(float(0))
    else:
        for i in range(2,11) :
            if row[i] !='NR':                
                test_x[r_row//18].append(float(row[i]))
            else:
                test_x[r_row//18].append(float(0))                                                
    r_row+=1
test_x=np.array(test_x)

test_x=np.concatenate((np.ones((test_x.shape[0],1)),test_x),axis= 1 )
            


ans=[]#用于存放测试结果
for i in range(len(test_x)):
    ans.append(['id_'+str(i)])    
    a= np.dot(w,test_x[i])#所得参数w与测试数据相乘得到结果,并放入ans列表中
    ans[i].append(a)

#存储数据
data_name='prediction.csv'
file_final=open(data_name,'w')
file_write=csv.writer(file_final,delimiter=',',lineterminator='\n')
file_write.writerow(['id','value'])
for i in range(len(ans)):
    file_write.writerow(ans[i])

file_final.close()

接下来使用测试数据查看预测效果

prediction_file=pd.DataFrame(pd.read_csv('prediction.csv',header=0))
ans_file=pd.DataFrame(pd.read_csv('ans.csv',header=0))
prediction_array = np.array(prediction_file)
prediction_value=prediction_array[:,1]
ans_array = np.array(ans_file)
ans_value=ans_array[:,1]
test_erro=math.sqrt(np.sum((prediction_value-ans_value)**2)/240)
print(test_erro)

猜你喜欢

转载自blog.csdn.net/pandacode/article/details/80378223