梯度下降的公式:
其中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)