上一片讲解了Python实现批梯度下降法(batch gradient desent),不同于感知机算法每次计算一个样本就更新一次结果,BGD算法 在计算完所有样本一轮以后才更新一次权重,这样当样本量巨大的时候极大的影响了效率,因而出现了新的随机梯度算法(Stochastic gradient desent)其也被称为迭代/在线梯度下降,其每次只用一个样本对权重进行更新。除此之外还有最小批学习(mini-batch learning),使用一部分样本进行权重更新。
代码实现如下:(下载链接:https://github.com/Airuio/Implementing-Stochastic-gradient-descent-by-using-Python-)
import numpy as np
from numpy.random import seed
class AdalineSGD(object):
def __init__(self,eta=0.01,n_iter=10,shuffle=True,random_state=None):
self.eta = eta #学习率
self.n_iter = n_iter #迭代轮数
self.shuffle = shuffle #打乱排序样本
self.w_initialized = False #初始化标识
if random_state: #随机种子(此处可不要,不影响程序)
seed(random_state)
def fit(self,X,y):
self._initialize_weights(X.shape[1]) #初始化权重并标记已经初始化
self.cost_ = []
for i in range(self.n_iter):
if self.shuffle: #每轮开始时重新给样本排序
X,y = self._shuffle(X,y)
cost = []
for xi, target in zip(X,y):
cost.append(self._update_weights(xi, target)) #更新权重值
agv_cost = sum(cost)/len(y)
self.cost_.append(agv_cost) #记录本轮的损失函数均值
return self
def partial_fit(self,X,y): #实现在线学习,实时更新权重时调用此函数
if not self.w_initialized: #检查是否存在权重w,不存在则初始化。
self._initialize_weights(X.shape[1])
if y.reval().shape[0] > 1:
for xi, target in zip(X,y): #调用新数据进行更新
self._updata_weights(xi,target)
else:
self._update_weights(x,y)
return self
def _initialize_weights(self,m): #初始化权重,标记
self.w_ = np.zeros(1+m)
self.w_initialized = True
def _shuffle(self,X,y): #随机排序
r = np.random.permutation(len(y))
return X[r],y[r]
def _update_weights(self,xi,target):
output = self.net_input(xi) #计算预测值
errors = (target - output) #统计误差
self.w_[1:] += self.eta*xi.dot(errors)
self.w_[0] += self.eta * errors
cost = (errors**2).sum()/2.0 #损失函数
return cost
def net_input(self,X): #计算预测值
return np.dot(X,self.w_[1:]) + self.w_[0]
def activation(self,X): #激活函数~~此处等于预测值
return self.net_input(X)
def predict(self, X): #返回预测输出
return np.where(self.activation(X) >= 0.0, 1, -1)
同样的本文使用鸢尾花lris数据集进行试验,代码如下:
from AdalineSGD import AdalineSGD
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
df = pd.read_excel(io = 'lris.xlsx',header = None) #读取数据为Dataframe结构,没有表头行
y = df.iloc[0:100,4].values #取前100列数据,4列为标识
y = np.where(y == 'Iris-setosa', -1,1)
X = df.iloc[0:100,[0,2]].values #iloc为选取表格区域,此处取二维特征进行分类,values为返回不含索引的表
X_std = np.copy(X) #将样本特征归一化、标准化
X_std[:,0] = (X[:,0] - X[:,0].mean()) / X[:,0].std()
X_std[:,1] = (X[:,1] - X[:,1].mean()) / X[:,1].std()
ada = AdalineSGD(eta = 0.01, n_iter = 15,random_state = None)
ada.fit(X_std,y)
def plot_decision_region(X,y,classifier,resolution = 0.02):
markers = ('s','x','o','~','v')
colors = ('red','blue','lightgreen','gray','cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
#画出界面
x1_min, x1max = X[:,0].min() - 1, X[:,0].max() + 1
x2_min, x2max = X[:,1].min() - 1, X[:,1].max() + 1
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1max,resolution),
np.arange(x2_min,x2max,resolution)) #生成均匀网格点,
'''meshgrid的作用是根据传入的两个一维数组参数生成两个数组元素的列表。如果第一个参数是xarray,
维度是xdimesion,第二个参数是yarray,维度是ydimesion。那么生成的第一个二维数组是以xarray为行,
ydimesion行的向量;而第二个二维数组是以yarray的转置为列,xdimesion列的向量。'''
Z = classifier.predict(X = np.array([xx1.ravel(),xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
#在全图上每一个点(间隔0.2)计算预测值,并返回1或-1
plt.contourf(xx1,xx2,Z,alpha = 0.5,cmap = cmap) #画出等高线并填充颜色
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
#画上分类后的样本
for idx,cl in enumerate(np.unique(y)):
plt.scatter(x=X[y==cl,0], y=X[y==cl,1],alpha=0.8,
c=cmap(idx),marker=markers[idx],label=cl)
plot_decision_region(X_std, y, classifier = ada) #展示分类结果
plt.xlabel('sepal lenth [nondimensional]')
plt.ylabel('petal lenth [nondimensional]')
plt.legend(loc = 2)
plt.show()
plt.plot(range(1,len(ada.cost_)+1),ada.cost_,marker = 'o') #展示损失函数误差收敛过程
plt.xlabel('Epoches')
plt.ylabel('Average cost_')
plt.show()
运行结果如下: