机械学习-逻辑回归

机械学习——关于假设函数模型的理解

划分数据的正负样本

参数约定

  • 样本数据
    X = ( X ( 1 ) X ( 2 ) X ( 3 ) . . . X ( i ) . . . X ( m ) ) = ( 1 1 1 . . 1 . . . 1 x 1 ( 1 ) x 1 ( 2 ) x 1 ( 3 ) . . x 1 ( i ) . . . x 1 ( m ) x 2 ( 1 ) x 2 ( 2 ) x 2 ( 3 ) . . . x 2 ( i ) . . . x 2 ( m ) x 3 ( 1 ) x 3 ( 2 ) x 3 ( 3 ) . . x 3 ( i ) . . . x 3 ( m ) . . . . . . . . . . . . . . . . . . . . . . . . x j ( i ) . . . . . . . . . . . . . . . . . . . . . . . x n ( 1 ) x n ( 2 ) x n ( 3 ) . . x n ( i ) . . . x n ( m ) ) ( n + 1 ) × m (1) X = \left( \begin{matrix} X^{(1)} & X^{(2)} & X^{(3)} & ... & X^{(i)}...& X^{(m)}\\ \end{matrix} \right)= \left( \begin{matrix} 1 & 1 & 1 & .. & 1 &... & 1\\ x_{1}^{(1)} & x_{1}^{(2)} & x_{1}^{(3)} & .. & x_{1}^{(i)} &... & x_{1}^{(m)}\\ x_{2}^{(1)} & x_{2}^{(2)} & x_{2}^{(3)} & ...& x_{2}^{(i)} &...& x_{2}^{(m)}\\ x_{3}^{(1)} & x_{3}^{(2)} & x_{3}^{(3)} & ..& x_{3}^{(i)} &...& x_{3}^{(m)}\\ .. & .. & ..&..&.. &...& ...\\ .. & .. & ..&..&x_{j}^{(i)} &... & ...\\ .. & .. & ..&..&.. &...& ....\\ x_{n}^{(1)} & x_{n}^{(2)} & x_{n}^{(3)} & ..& x_{n}^{(i)} &...& x_{n}^{(m)}\\ \end{matrix} \right)_{(n+1) \times m } \tag{1}X=(X(1)X(2)X(3)...X(i)...X(m))=1x1(1)x2(1)x3(1)......xn(1)1x1(2)x2(2)x3(2)......xn(2)1x1(3)x2(3)x3(3)......xn(3).................1x1(i)x2(i)x3(i)..xj(i)..xn(i)........................1x1(m)x2(m)x3(m)..........xn(m)(n+1)×m(1)
    Y = [ y ( 1 ) , y ( 2 ) , . . . . . . , y ( i ) , . . . , y ( m ) ] Y = [y^{(1)},y^{(2)},......,y^{(i)},...,y^{(m)}]Y=[y(1),y(2),......,y(i),...,y(m)]
    y ( i ) ∈ { 0 ∣ 1 } y^{(i)} \in \{{0 | 1}\}y(i){01} ——0为负样本1为正样本

  • 权重
    W = ( θ 1 θ 2 θ 3 . . . θ j . . . θ n ) n x × 1 (3) W = \left( \begin{matrix} \theta_{1} \\ \theta_{2} \\ \theta_{3} \\ ... \\ \theta_{j} \\ ...\\ \theta_{n}\\ \end{matrix} \right)_{n_{x} \times 1} \tag{3}W=θ1θ2θ3...θj...θnnx×1(3)

  • 偏置
    b ∈ R 为 实 数 b \in R为实数bR

算法过程

  • 假设函数
    Z = W T X + b = n p . d o t ( W . T , X ) + b Z = W^{T}X + b = np.dot(W.T, X) + bZ=WTX+b=np.dot(W.T,X)+b
    添加激活函数
    A = σ ( Z ) A = \sigma(Z)A=σ(Z)
  • 求dZ
    d Z = A − Y dZ = A - YdZ=AY
  • 求参数偏导(正则化)
    d W = 1 m ∗ X @ d Z . T + λ m ∗ W dW = \frac{1}{m} * X @dZ.T + \frac{\lambda}{m}*WdW=m1X@dZ.T+mλW
    d b = 1 m ∗ n p . s u m ( d Z ) db = \frac{1}{m}*np.sum(dZ)db=m1np.sum(dZ)
    @——矩阵乘法运算
  • 参数更新
    W : = W − α ∗ d W W := W - \alpha*dWW:=WαdW
    b : = b − α ∗ d b b := b - \alpha*dbb:=bαdb

代码演示

  • 导入相关库
import numpy as np
from matplotlib import pyplot as plt
from tqdm import tqdm
from tqdm.std import trange

#解决中文乱码
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

数据集加载

def load_data():
    """
    加载数据集
    return: 
           datd    array 数据集
    """
    data = np.loadtxt("data.txt",delimiter=",", dtype=np.float64)
    
    return data;

数据预处理

  • 数据集分割
def split_data_to_XY(data):
    """
    将数据集分割X和Y集合
    param:data     加载的数据集
    retrun: X_p   原始数据X
            Y     对应X_p的结果集
    """
    data = np.array(data, dtype=np.float32)
    X_p = data[:, :-1]
    Y   = data[:, -1].reshape((1, -1))
    
    return [X_p, Y]
  • 映射为多项式
def mapFeature(X_p):
    """
    映射为多项式——在原基础训练样本特征上的特征拓展(特征数量变多了)
    映射的多项式:
    parameters:  X_p    原始数据X  每列为一个特征值
    return:      X_map  映射为1多项式后的新特征样本数据, 每列仍然为一个特征
    
    """
    #映射算法-这里没有映射
    X_map = X_p
    
    return X_map
  • 特征归一化处理
def data_normal(X):
    """
    采用0均值归一化,仅需要对特征X进行归一化处理
    param:  X   list     训练样本数据   每列为一个特征
    return:
          X_nor   list  归一化化后的数据
          average  list X每列计算的均值
          variance  list X每列计算的方差
    """
    #计算均值   #axis=0 按列 axis=1 按行
    average = np.mean(X, axis=0).reshape((1, -1))  
    #计算方差
    variance = np.std(X, axis=0).reshape((1, -1))   
    #存储特征计算的方差和均值——第一行为均值  第二行为方差值
    np.savetxt("normal.txt", np.vstack((average, variance)))
    
    
    (n, m) = np.shape(X)
    X_nor = np.ones((n, 1))
    
    # print("X={0}".format(X))
    
    for i in range(m):
        tmp = (np.array(X[:, i]) - average[0, i]) / variance[0, i]
        X_nor = np.hstack((X_nor, tmp.reshape((-1, 1))))
    X_nor = X_nor[:, 1:]
    
    return X_nor
  • 样本向量化
def matrix(X_nor):
    """
    样本向量化
    """
    return np.transpose(X_nor)
  • 数据预处理函数封装
#数据预处理封装函数
def data_dispose(data):
    """
    数据预处理函数
    parameters:
               data      array   原始数据集按照data.txt中格式排列样本的数据
    return:
               X         array   数据预处理后向量化样本(每列为一个样本)
               average   array   对应data特征的均值为行向量
               variance  array   对应data特征的方差为行向量
    """
    #2.数据集分割
    [X_p, Y] = split_data_to_XY(data)
    #4.特征归一化处理
    X_nor = data_normal(X_p)
    #5.样本向量化
    X = matrix(X_nor)
    #6.绘制数据集图像
    plotData(data)
    
    return X

假设函数

def hypothesis( X, W,  b):
    """
    计算假设函数
    param:  X   array  预处理后的向量化样本数据集
            W   array  模型参数    列向量  
            b   float  参数偏置    实数
    return: A   array  预测结果值   行向量
    """
    W = np.array(W)
    X = np.array(X)
    
    #决策边界函数
    Z = np.reshape(W.T @ X + b,(1, -1))
    
    #添加激活函数
    A = 1 / (1 + np.exp(-Z))

    return np.reshape(A, (1, -1));

初始化模型参数

def init_param(X):
    """
    初始化模型参数
    param:  X      array   样本向量化后的数据集
    return: lambd  float   正则参数      常取0.01 0.1等
            W      array   特征权重参数  为列向量
            b      float   模型偏置      默认0
            learn_rate  float  学习率  常取0.01 0.1, 0.03, 0.3等
    """
    (n, m) = np.shape(X)
    #初始化W
    W = np.zeros((n, 1))
    #初始化b
    b = 0
    #初始化正则参数 
    lambd = 0.01
    #选择学习率
    learn_rate = 0.01
    
    return [W, b, lambd, learn_rate]

辅助绘图函数

def plotData(data):
    """
    绘制原始数据集图像
    param:data   array 数据集  按指定格式排布的
    """
    #判断维数
    (n, m) = np.array(data).shape
    
    c = []
    #数据标识
    for i in range(n):
        #负样本
        if data[i, -1] == 0:
            c.append("red")
                         
        elif data[i, -1] == 1:
             #正样本
            c.append("blue")
        else:
            #非法数据
            c.append("green")

    
    if m == 3:
        #绘制二维图像
        plt.scatter(data[:, 0], data[:, 1], c=c)
    if m == 4:
        fig = plt.figure()
        ax = fig.add_subplot(projection='3d')
        xs = data[:, 0]
        ys = data[:, 1]
        zs = data[:, 2]
        #绘制三维图像
        ax.scatter(xs, ys, zs, c=c)
    
    plt.title("训练样本分布图:蓝色=正样本;红色=负样本")

def plot_decision(data):
    """
    绘制决策边界图:利用等高线图 + 散点图绘制决策边界
    """
    #绘制决策边界的等高线图 +-.5是添加一点边缘填充
    x1_min, x1_max = data[:,0].min()-.5, data[:, 0].max() + .5
    x2_min, x2_max = data[:,1].min()-.5, data[:, 1].max() + .5
    h = 0.01
    
    #网格化
    xx, yy = np.meshgrid(np.arange(x1_min,x1_max, h), np.arange(x2_min, x2_max, h))
    
    #预测函数计算Z值 按列水平堆叠
    X = np.c_[xx.ravel(),yy.ravel()]
    Z = predict(X)
    
    Z = Z.reshape(xx.shape)
    
    
    #绘制等高线图
    plt.contourf(xx, yy, Z, 1, alpha=0.15)
    #绘制数据集的散点图
    plotData(data)

def plotJ(cost):
    """
    绘制代价函数图
    """
    plt.figure(figsize=(20, 10))
    plt.title("代价随迭代次数的变化图")
    plt.ylabel("cost: 总代价")
    plt.xlabel("epoch:迭代次数")
    plt.plot(cost)
    plt.figure()

模型训练

def train_LogisticRegression_model( X, Y, W, b = 0, lambd = 0.01, learn_rate = 0.01,epoch=1000):
    """
    训练逻辑回归模型参数
    param:
            X           array       向量化后的训练样本数据
            Y           array       对应X的结果集  为一个行向量
            W           array       列向量  默认为全为0
            b           float       模型偏置参数  默认0
            lambd       float       正则化参数  默认的0.01
            learn_rate  float       学习率  默认0.01
            epoch       int         迭代次数     默认1000
    return:
            optim_W   list   最优参数
            optim_b   float  最优偏置参数
            Cost      list   迭代样本的总代价
    """
    #存储所有迭代得到的参数
    Parameters = []
    #样本个数
    m = np.size(Y)
    #迭代总代价
    Cost = []
    #参数更新
    for n in tqdm(range(epoch)):
        
        #求解假设函数
        A = hypothesis(X, W, b) 

        #计算总代价
        L = -Y * np.log(A)-(1-Y)*np.log(1-A)
        cost = 1 / m * np.sum(L) + lambd / (2*m) * np.sum(W**2)
        Cost.append(cost)
            
        #计算梯度Gradient A = [a1, a2, a3, ... ,am]  
        dZ = A - np.reshape(Y, (1, -1))
        
        #正则处理
        dW = 1 / m * (X @ dZ.T) + lambd / m * W
        db = 1 / m * np.sum(dZ)
        #模型参数更新
        W = W - learn_rate * dW
        b = b - learn_rate * db
        Parameters.append([W,b])
    
    #寻找最优解
    k = Cost.index(min(Cost))
    optim =  Parameters[k]   
    
    #存储模型参数
    np.savetxt("model_W.txt",   optim[0])
    np.savetxt("model_b.txt", [optim[1]])
    
    return [optim, Cost]

模型预测

def predict(X):
    """
    模型预测
    parameters:
                X            array   原始数据集:每行为一个样本,每列为一个特征
    return:     pre_result   array   预测结果
    """
    
    #加载归一化数据集特征的均值和方差
    Normal = np.loadtxt("normal.txt")
    average = Normal[0, -1]   #均值
    variance = Normal[1, -1]  #方差

    
    # 数据归一化处理
    X_nor = (X - average) / variance
    #样本向量化
    X = X_nor.T
    
    #获取模型参数
    W = np.loadtxt("model_W.txt")
    b = np.loadtxt("model_b.txt")
    
    W = np.reshape(W, (-1, 1))
    pre_result =  np.around(hypothesis(X, W, b), 7)   #保留7为小数
    
    return pre_result
  • 主程序
#加载数据集
data = load_data()

#映射为多项式-----模型增强
data_map = mapFeature(data)

#数据预处理
X = data_dispose(data_map)

#初始化模型参数
[W, b, lambd, learn_rate] = init_param(X)

#迭代次数
epoch = 100000
#训练模型参数
[optim, Cost] = train_LogisticRegression_model(
    X,
    Y,
    W,
    b=0,
    lambd=-0.01,
    learn_rate=0.01,
    epoch=epoch,
    )

# #最优参数
W_optim = optim[0]
b_optim = optim[1]

#绘制代价图
plotJ(Cost)
#决策边界图像
#获取归一化的均值与方差值
normal = np.loadtxt("normal.txt")
plot_decision(data)

print("训练结果:")
print("W_optim={0}".format(W_optim))
print("b_optim={0}".format(b_optim))
print("min cost={0}".format(min(Cost)))

x = np.array([
    [74.49269241843041,84.84513684930135],
    [54.49269241843041,84.84513684930135],
    [90, 100.2131232143],
    [74.77589300092767,89.52981289513276],
    [82.22666157785568,42.71987853716458],
    [123.3, 123]
    ])

predict(x)

在这里插入图片描述

完整代码

在这里插入代码片

运行结果

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述


版权声明:本文为xsz123456p原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。