必要的数学概念
1、离散型随机变量及分布规律
1.1:0-1分布(两点分布)(伯努利分布):当
时,其分布函数为
,期望为E=1*p+0*(1-p)=p,方差:D=p(1-p)1.2:二项分布(n重伯努利分布):分布函数:
,期望 E=np,方差:D = np(1-p)
1.3:泊松分布 :分布函数,期望E= λ,方差D= λ
2、最大似然估计(Likelihood):通过参数选择使已知数据最大概率出现
在条件概率中 P(X|θ) 表示在 θ条件下,X出现的概率,与之对应的就是似然函数: L(θ|X)已知数据X 在参数θ的作用下的概率,数值上等于P(X|θ)。
几种常见的线性回归
①线性回归; f(Xi)=WXi+b,其中Xi为特征,W与b是需要确定的参数,模型训练就是获得最佳的W与b
线性回归中的损失函数:用来衡量W与b是否最佳,使用均方误差。均方误差J(θ)=∑[f(Xi)-y]^2。目标是使得误差最小,利用偏导来求,偏导为0则为最优解,求最小误差的这个过程称为最小二乘。
利用偏导求得最优解为:
最小二乘:估计值与实际值之差的平方和最小。凸显优化的特点。
②多元线性回归,W是一个向量,
,同样也可通过最小二乘求得最优解为
所以最终获得的多元线性模型为
③对数线性回归:
④logistic回归(对数几率回归),基于sigmoid函数
。 logistic回归的损失函数:
最大似然:通过参数选择使已知数据在某种意义下最大概率出现。(需要知道已知数据的概率分布函数)
原本的是这样的
,为了简化计算取对数:
梯度上升算法:
,α梯度上升算法优化logisitc损失函数:
使用此公式迭代得出解(复合函数求偏导J(θ )--> h(θ)=g(θT) --> θT --> θ )
于是就可以得到θj 权重数组
代码部分
梯度上升算法的代码实现:
def sigmoid(inX): #定义好sigmoid函数
return 1.0 / (1 + np.exp(-inX))
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn) # 转换成numpy的mat
labelMat = np.mat(classLabels).transpose() # 转换成numpy的mat,并进行转置
m, n = np.shape(dataMatrix) # 返回dataMatrix的大小。m为行数,n为列数。
alpha = 0.001 # 移动步长,也就是学习速率,α
maxCycles = 500 # 最大迭代次数,公式中的m
weights = np.ones((n, 1)) #用于建立线性方程的权重值,我们使用这个算法的目的是获得Wi这些权重值,公式中的表示为θj
for k in range(maxCycles):
h = sigmoid(dataMatrix * weights) # 梯度上升矢量化公式
error = labelMat - h #上方推导的最后一个公式的y-hθ(x)
weights = weights + alpha * dataMatrix.transpose() * error
return weights.getA() # 将矩阵转换为数组,返回权重数组
决策边界
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.arange(-3.0, 3.0, 0.1)
y = (-weights[0] - weights[1] * x) / weights[2] #这个权重函数为毛这样设定????
ax.plot(x, y) #绘制决策边界
plt.title('BestFit') #绘制title
plt.xlabel('X1'); plt.ylabel('X2') #绘制坐标轴
plt.show()
分类试验
# -*- coding:UTF-8 -*-
import matplotlib.pyplot as plt
import numpy as np
def loadDataSet():
dataMat = [] #创建数据列表
labelMat = [] #创建标签列表
fr = open('testSet.txt') #打开文件
for line in fr.readlines(): #逐行读取
lineArr = line.strip().split() #去回车,放入列表
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #添加数据
labelMat.append(int(lineArr[2])) #添加标签
fr.close() #关闭文件
return dataMat, labelMat #返回
def sigmoid(inX):
return 1.0 / (1 + np.exp(-inX))
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn) #转换成numpy的mat
labelMat = np.mat(classLabels).transpose() #转换成numpy的mat,并进行转置
m, n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。
alpha = 0.001 #移动步长,也就是学习速率,控制更新的幅度。
maxCycles = 500 #最大迭代次数
weights = np.ones((n,1))
for k in range(maxCycles):
h = sigmoid(dataMatrix * weights) #梯度上升矢量化公式
error = labelMat - h
weights = weights + alpha * dataMatrix.transpose() * error
return weights.getA() #将矩阵转换为数组,返回权重数组
def plotBestFit(weights):
dataMat, labelMat = loadDataSet() #加载数据集
dataArr = np.array(dataMat) #转换成numpy的array数组
n = np.shape(dataMat)[0] #数据个数
xcord1 = []; ycord1 = [] #正样本
xcord2 = []; ycord2 = [] #负样本
for i in range(n): #根据数据集标签进行分类
if int(labelMat[i]) == 1:
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) #1为正样本
else:
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) #0为负样本
fig = plt.figure()
ax = fig.add_subplot(111) #添加subplot
ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's',alpha=.5)#绘制正样本
ax.scatter(xcord2, ycord2, s = 20, c = 'green',alpha=.5) #绘制负样本
x = np.arange(-3.0, 3.0, 0.1)
y = (-weights[0] - weights[1] * x) / weights[2]
ax.plot(x, y)
plt.title('BestFit') #绘制title
plt.xlabel('X1'); plt.ylabel('X2') #绘制label
plt.show()
if __name__ == '__main__':
dataMat, labelMat = loadDataSet()
weights = gradAscent(dataMat, labelMat)
plotBestFit(weights)
View Code
随机梯度上升算法(改进版)
改进一:学习率不断改变(变小)
改进二:随机选择样本,用完之后删除随机选择的样本,可以减少计算量
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。
weights = np.ones(n) #参数初始化
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次减小1/(j+i)。
randIndex = int(random.uniform(0,len(dataIndex))) #随机选取样本
h = sigmoid(sum(dataMatrix[randIndex]*weights)) #选择随机选取的一个样本,计算h
error = classLabels[randIndex] - h #计算误差
weights = weights + alpha * error * dataMatrix[randIndex] #更新回归系数
del(dataIndex[randIndex]) #删除已经使用的样本
return weights
改进前后的梯度上升算法对比
# -*- coding:UTF-8 -*-
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
import numpy as np
import random
def loadDataSet():
dataMat = [] # 创建数据列表
labelMat = [] # 创建标签列表
fr = open('testSet.txt') # 打开文件
for line in fr.readlines(): # 逐行读取
lineArr = line.strip().split() # 去回车,放入列表
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) # 添加数据
labelMat.append(int(lineArr[2])) # 添加标签
fr.close() # 关闭文件
return dataMat, labelMat # 返回
def sigmoid(inX):
return 1.0 / (1 + np.exp(-inX))
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn) # 转换成numpy的mat
labelMat = np.mat(classLabels).transpose() # 转换成numpy的mat,并进行转置
m, n = np.shape(dataMatrix) # 返回dataMatrix的大小。m为行数,n为列数。
alpha = 0.01 # 移动步长,也就是学习速率,控制更新的幅度。
maxCycles = 500 # 最大迭代次数
weights = np.ones((n, 1))
weights_array = np.array([])
for k in range(maxCycles):
h = sigmoid(dataMatrix * weights) # 梯度上升矢量化公式
error = labelMat - h
weights = weights + alpha * dataMatrix.transpose() * error
weights_array = np.append(weights_array, weights)
weights_array = weights_array.reshape(maxCycles, n)
return weights.getA(), weights_array # 将矩阵转换为数组,并返回
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m, n = np.shape(dataMatrix) # 返回dataMatrix的大小。m为行数,n为列数。
weights = np.ones(n) # 参数初始化
weights_array = np.array([]) # 存储每次更新的回归系数
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.01 # 降低alpha的大小,每次减小1/(j+i)。
randIndex = int(random.uniform(0, len(dataIndex))) # 随机选取样本
h = sigmoid(sum(dataMatrix[randIndex] * weights)) # 选择随机选取的一个样本,计算h
error = classLabels[randIndex] - h # 计算误差
weights = weights + alpha * error * dataMatrix[randIndex] # 更新回归系数
weights_array = np.append(weights_array, weights, axis=0) # 添加回归系数到数组中
del (dataIndex[randIndex]) # 删除已经使用的样本
weights_array = weights_array.reshape(numIter * m, n) # 改变维度
return weights, weights_array # 返回
def plotWeights(weights_array1, weights_array2):
# 设置汉字格式
font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
# 将fig画布分隔成1行1列,不共享x轴和y轴,fig画布的大小为(13,8)
# 当nrow=3,nclos=2时,代表fig画布被分为六个区域,axs[0][0]表示第一行第一列
fig, axs = plt.subplots(nrows=3, ncols=2, sharex=False, sharey=False, figsize=(20, 10))
x1 = np.arange(0, len(weights_array1), 1)
# 绘制w0与迭代次数的关系
axs[0][0].plot(x1, weights_array1[:, 0])
axs0_title_text = axs[0][0].set_title(u'梯度上升算法:回归系数与迭代次数关系', FontProperties=font)
axs0_ylabel_text = axs[0][0].set_ylabel(u'W0', FontProperties=font)
plt.setp(axs0_title_text, size=20, weight='bold', color='black')
plt.setp(axs0_ylabel_text, size=20, weight='bold', color='black')
# 绘制w1与迭代次数的关系
axs[1][0].plot(x1, weights_array1[:, 1])
axs1_ylabel_text = axs[1][0].set_ylabel(u'W1', FontProperties=font)
plt.setp(axs1_ylabel_text, size=20, weight='bold', color='black')
# 绘制w2与迭代次数的关系
axs[2][0].plot(x1, weights_array1[:, 2])
axs2_xlabel_text = axs[2][0].set_xlabel(u'迭代次数', FontProperties=font)
axs2_ylabel_text = axs[2][0].set_ylabel(u'W2', FontProperties=font)
plt.setp(axs2_xlabel_text, size=20, weight='bold', color='black')
plt.setp(axs2_ylabel_text, size=20, weight='bold', color='black')
x2 = np.arange(0, len(weights_array2), 1)
# 绘制w0与迭代次数的关系
axs[0][1].plot(x2, weights_array2[:, 0])
axs0_title_text = axs[0][1].set_title(u'改进的随机梯度上升算法:回归系数与迭代次数关系', FontProperties=font)
axs0_ylabel_text = axs[0][1].set_ylabel(u'W0', FontProperties=font)
plt.setp(axs0_title_text, size=20, weight='bold', color='black')
plt.setp(axs0_ylabel_text, size=20, weight='bold', color='black')
# 绘制w1与迭代次数的关系
axs[1][1].plot(x2, weights_array2[:, 1])
axs1_ylabel_text = axs[1][1].set_ylabel(u'W1', FontProperties=font)
plt.setp(axs1_ylabel_text, size=20, weight='bold', color='black')
# 绘制w2与迭代次数的关系
axs[2][1].plot(x2, weights_array2[:, 2])
axs2_xlabel_text = axs[2][1].set_xlabel(u'迭代次数', FontProperties=font)
axs2_ylabel_text = axs[2][1].set_ylabel(u'W1', FontProperties=font)
plt.setp(axs2_xlabel_text, size=20, weight='bold', color='black')
plt.setp(axs2_ylabel_text, size=20, weight='bold', color='black')
plt.show()
if __name__ == '__main__':
dataMat, labelMat = loadDataSet()
weights1, weights_array1 = stocGradAscent1(np.array(dataMat), labelMat)
weights2, weights_array2 = gradAscent(dataMat, labelMat)
plotWeights(weights_array1, weights_array2)
View Code
logistic回归:用算法求得权值参数--> 权值参数与特征相乘求和 --> 根据这个和是否大于0.5 分类
# -*- coding:UTF-8 -*-
import numpy as np
import random
def sigmoid(inX):
return 1.0 / (1 + np.exp(-inX))
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m, n = np.shape(dataMatrix) # 返回dataMatrix的大小。m为行数,n为列数。
weights = np.ones(n) # 参数初始化 #存储每次更新的回归系数
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.01 # 降低alpha的大小,每次减小1/(j+i)。
randIndex = int(random.uniform(0, len(dataIndex))) # 随机选取样本
h = sigmoid(sum(dataMatrix[randIndex] * weights)) # 选择随机选取的一个样本,计算h
error = classLabels[randIndex] - h # 计算误差
weights = weights + alpha * error * dataMatrix[randIndex] # 更新回归系数
del (dataIndex[randIndex]) # 删除已经使用的样本
return weights # 返回
def colicTest():
frTrain = open('horseColicTraining.txt') # 打开训练集
frTest = open('horseColicTest.txt') # 打开测试集
trainingSet = [];
trainingLabels = []
for line in frTrain.readlines():
currLine = line.strip().split('\t')
lineArr = []
for i in range(len(currLine) - 1):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[-1]))
trainWeights = stocGradAscent1(np.array(trainingSet), trainingLabels, 500) # 使用改进的随即上升梯度训练获得权值参数数组
errorCount = 0;
numTestVec = 0.0
for line in frTest.readlines():
numTestVec += 1.0
currLine = line.strip().split('\t')
lineArr = []
for i in range(len(currLine) - 1):
lineArr.append(float(currLine[i]))
if int(classifyVector(np.array(lineArr), trainWeights)) != int(currLine[-1]): #分类器结果与标签值比较判别正确情况
errorCount += 1
errorRate = (float(errorCount) / numTestVec) * 100 # 错误率计算
print("测试集错误率为: %.2f%%" % errorRate)
def classifyVector(inX, weights): #利用sigmoid函数特点定义分类
prob = sigmoid(sum(inX * weights))
if prob > 0.5:
return 1.0
else:
return 0.0
if __name__ == '__main__':
colicTest()
View Code