必要的数学概念

1、离散型随机变量及分布规律

1.1:0-1分布(两点分布)(伯努利分布):当

logseries分布 logistic分布的期望和方差_logseries分布

时,其分布函数为

logseries分布 logistic分布的期望和方差_人工智能_02

,期望为E=1*p+0*(1-p)=p,方差:D=p(1-p)1.2:二项分布(n重伯努利分布):分布函数:

logseries分布 logistic分布的期望和方差_数据结构与算法_03

,期望 E=np,方差:D = np(1-p)

1.3:泊松分布 :分布函数

logseries分布 logistic分布的期望和方差_迭代_04

,期望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则为最优解,求最小误差的这个过程称为最小二乘。

logseries分布 logistic分布的期望和方差_python_05

利用偏导求得最优解为:

logseries分布 logistic分布的期望和方差_logseries分布_06

logseries分布 logistic分布的期望和方差_数据结构与算法_07

 最小二乘:估计值与实际值之差的平方和最小。凸显优化的特点。

多元线性回归,W是一个向量,

logseries分布 logistic分布的期望和方差_logseries分布_08

,同样也可通过最小二乘求得最优解为

logseries分布 logistic分布的期望和方差_python_09

所以最终获得的多元线性模型为

logseries分布 logistic分布的期望和方差_迭代_10

③对数线性回归

logseries分布 logistic分布的期望和方差_迭代_11

 ④logistic回归(对数几率回归)

logseries分布 logistic分布的期望和方差_迭代_12

基于sigmoid函数

logseries分布 logistic分布的期望和方差_logseries分布_13

。 logistic回归的损失函数:

logseries分布 logistic分布的期望和方差_logseries分布_14

最大似然:通过参数选择使已知数据在某种意义下最大概率出现。(需要知道已知数据的概率分布函数)

   原本的是这样的

logseries分布 logistic分布的期望和方差_python_15

,为了简化计算取对数:

logseries分布 logistic分布的期望和方差_人工智能_16

 梯度上升算法

logseries分布 logistic分布的期望和方差_数据结构与算法_17

,α梯度上升算法优化logisitc损失函数:

logseries分布 logistic分布的期望和方差_人工智能_18

使用此公式迭代得出解(复合函数求偏导J(θ )--> h(θ)=g(θT) --> θT --> θ 

logseries分布 logistic分布的期望和方差_人工智能_19

 

logseries分布 logistic分布的期望和方差_数据结构与算法_20

logseries分布 logistic分布的期望和方差_数据结构与算法_21

                           

logseries分布 logistic分布的期望和方差_数据结构与算法_22

 

logseries分布 logistic分布的期望和方差_数据结构与算法_23

于是就可以得到θ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()


分类试验


logseries分布 logistic分布的期望和方差_logseries分布_24

logseries分布 logistic分布的期望和方差_人工智能_25

# -*- 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


 

改进前后的梯度上升算法对比


logseries分布 logistic分布的期望和方差_logseries分布_24

logseries分布 logistic分布的期望和方差_人工智能_25

# -*- 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  

logseries分布 logistic分布的期望和方差_人工智能_28

 

logistic回归:用算法求得权值参数--> 权值参数与特征相乘求和 --> 根据这个和是否大于0.5 分类


logseries分布 logistic分布的期望和方差_logseries分布_24

logseries分布 logistic分布的期望和方差_人工智能_25

# -*- 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