我们这将使用[sklearn][6] 框架和手动方式实现梯度下降法对数据的回归操作
- 使用sklearn 框架
首先我们要导入sklearn 的包,代码如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import time
from sklearn.linear_model import LinearRegression,Ridge,LassoCV,RidgeCV,ElasticNetCV
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
我们导入了sklearn中常用的包,如LinearRegression,用来实现线性回归。
np.random.seed(0)
N = 10
x = np.linspace(0,6,N)+np.random.randn(N) #随机生成x
y = 1.8 * x**3 + x**2 + 14*x -7 +np.random.randn(N)#将x映射到y
x.shape = -1,1 #将x,y变成列向量
y.shape = -1,1
为了简单起见,我们使用随机产生的简单数据
plt.figure(figsize=(12,6),facecolor='w')
x_hat = np.linspace(x.min(),x.max(),num=100)
x_hat.shape = -1,1
#线性模型
model = LinearRegression() #定义好一个线性回归的类
model.fit(x,y) #对模型进行拟合
y_hat = model.predict(x_hat)#预测x_hat相对应的y,命名为y_hat
s1 = calcRScore(y,model.predict(x)) #calcRScore是手写的评价函数,不是sklearn中的函数,在下面会提出
print(model.score(x,y))
print('模块自带输出实现=======================')
print('参数列表:',model.coef_)
print('截距:',model.intercept_)
这样操作之后,我们实现了利用sklearn 的线性回归,画出拟合直线观察:
- 手动实现梯度下降
首先我们介绍一下梯度下降法的基本思想,如果要求某个函数的极值,最好的方法就是沿着该函数的梯度方向探寻,如果将函数的梯度记为 ∇ ∇ ,则函数 f(x,y) f ( x , y ) 的梯度有下表示:
#手动实现梯度下降法
def validate(X,Y): #判断输入X,Y,的数量是否相等
if(len(X) != len(Y)):
raise Exception("参数异常")
else:
m =len(x[0]) #判断X数据内部特征量是否异常
for i in X:
if len(i) !=m:
raise Exception("参数异常")
if len(Y[0]) != 1: #判断Y
raise Exception("参数异常")
def calcDiffe(x,y,a): #计算损失
lx = len(x)
la = len(a)
if lx ==la: #如果权重量和X的行数(也就是数据量)相等
result = 0
for i in range(lx):
result += x[i]*a[i] #则对应相乘
return y-result
elif lx +1 ==la: #若是不等(X 有偏置,也就是存在常数项)
result = 0
for i in range(lx):
result += x[i]*a[i]
result +=1*a[lx] #在对应相乘的基础上加上常数项
return y-result
else:
raise Exception("参数异常")
def fit(X,Y,alphas,thresh=1e-16,maxIter=20,addConstantItem=True): #训练函数
import math
import numpy as np
validate(X,Y)
l = len(alphas) #alpha数,我们在l个alpha中寻找最好的alpha
m = len(Y) #可以理解成数据量
n = len(x[0])+1 if addConstantItem else len(x[0]) #X的特征量(当addConstantItem 为True 时,给X 加上偏置量)
B = [True for i in range(l)] #判断alpha是否已最优
J = [np.nan for i in range(l)] #存放对应alpha的损失
a = [[0 for j in range(n)] for i in range(l)] #存放对应alpha的权重(w)
#开始计算
for times in range(maxIter):
for i in range(l): #遍历alpha
if not B[i]: #如果当前alphas已经找到最优值,则不进行计算
continue
ta = a[i]
for j in range(n): #遍历特征
alpha = alphas[i]
ts = 0
for k in range(m): #遍历数据
if j == n -1 and addConstantItem:
ts += alpha*calcDiffe(X[k],Y[k][0],a[i])*1 #梯度(无偏置)
else:
ts += alpha*calcDiffe(X[k],Y[k][0],a[i])*X[k][j]#梯度(有偏置)
t = ta[j] +ts
ta[j] = t #更新权重
#所有特征遍历完毕
flag = True
js = 0
for k in range(m): #这个循环是计算损失
js += math.pow(calcDiffe(X[k],Y[k][0],a[i]),2)
if js > J[i]: #如果
flag = False
break
if flag:
J[i] = js
for j in range(n):
a[j][j] = ta[j]
else:
B[i] = False
#计算完一个循环,当目标函数小于一个阈值,则结束循环
r = [0 for j in J if j <= thresh]
if len(r) >0:
break
r = [0 for b in B if not b]
if len(r)>0:
break
min_a = a[0]
min_j = J[0]
min_alpha = alphas[0]
for i in range(l):
if J[i] '最优的alpha值为:',min_alpha)
return min_a
def predict(X,a):
Y=[]
n =len(a) - 1
for x in X:
result = 0
for i in range(n):
result += x[i]*a[i]
result += a[n]
Y.append(result)
return Y
def calcRScore(y,py):
if len(y) != len(py):
raise Exception("参数异常")
import math
import numpy as np
avgy = np.average(y)
m = len(y)
rss = 0.0
tss = 0
for i in range(m):
rss += math.pow(y[i]-py[i],2)
tss += math.pow(y[i]-avgy,2)
r = 1.0 - 1.0*rss/tss
return r
#自模型
print('y: ',y)
ma = fit(x,y,np.logspace(-4,-2,100),addConstantItem=True)
y_hat2 = predict(x_hat,ma)
s2 = calcRScore(y,predict(x,ma))
print('自定义参数==============================')
print('参数列表',ma)
#开始画图
plt.plot(x,y,'ro',ms=10,zorder = 3)
plt.plot(x_hat,y_hat,color='#b624db',lw=2,alpha=0.75,label='thc01 $R:%.3f'%s1,zorder=2)
# plt.plot(x_hat,y_hat2,color='#6d49b6',lw=2,alpha=0.75,label='thc01 $R:%.3f'%s2,zorder=1)
plt.legend('upper left')
plt.grid(True)
plt.xlabel('X',fontsize=16)
plt.ylabel('Y',fontsize=16)
plt.suptitle('The Change',fontsize=22)
plt.show()