三种方法实现 softmax 回归模型自定义、sklearn、tensorflow

一、原理

softmax回归

逻辑回归和softmax回归的区别

二、示例代码1-Softmax_Sklearn

sklearn的LogisticRegression模块对鸢尾花数据集进行Softmax 回归多分类

Iris_Data脚本:对数据标准化、标签独热编码、打乱样本排序

# 导入 pandas 库,用于数据分析和处理

import pandas as pd

# 读取 iris.csv 文件,其中包含了鸢尾花数据集,返回一个 DataFrame 对象

data = pd.read_csv('Softmax Regression/iris.csv')

# 从 DataFrame 对象中获取 Species 列的值,返回一个一维数组,表示鸢尾花的类别

ydata = data['Species'].values

# 从 DataFrame 对象中获取第 1 到第 4 列的值,返回一个二维数组,表示鸢尾花的特征

xdata = data.iloc[:, 1:5].values

# 数据处理

# 导入 numpy 库,用于科学计算和数组操作

import numpy as np

# 对 xdata 数组进行标准化,即减去每一列的均值,再除以每一列的标准差,返回一个新的数组,表示标准化后的特征

handle_x_data = (xdata - np.mean(xdata, axis=0)) / np.std(xdata, axis=0)

# 对 ydata 数组进行独热化,即将每个类别用一个向量表示,其中只有一个元素为 1,其余为 0,返回一个新的数组,表示独热化后的类别

ydata = pd.get_dummies(data['Species']).values

# 因为数据中类别比较集中,不易于训练,因此打乱数据

# 首先将 handle_x_data 数组和 ydata 数组在水平方向(即列方向)拼接在一起,返回一个新的数组,表示特征和类别的组合

xydata = np.hstack((handle_x_data, ydata))

# 对 xydata 数组进行随机打乱,使得每一行的顺序变化,但是每一行的内容不变,返回一个新的数组,表示打乱后的数据

np.random.shuffle(xydata)

# 分离数据

# 从 xydata 数组中获取前 4 列的值,返回一个新的数组,表示打乱后的特征

X_DATA = xydata[:, :4]

# 从 xydata 数组中获取后 3 列的值,返回一个新的数组,表示打乱后的类别

Y_DATA = xydata[:, 4:]

# 将 X_DATA 数组和 Y_DATA 数组组成一个列表,赋值给 Data 变量,表示最终的数据集

Data = [X_DATA, Y_DATA]

Softmax_Sklearn.py

#-*- coding:utf-8 -*-

import sys

import io

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

# 导入 sklearn 库,用于机器学习相关的功能

import sklearn as sk

# 导入 Iris_Data 模块,其中包含了鸢尾花数据集

from Iris_Data import Data as smdata

# 导入 numpy 库,用于科学计算和数组操作

import numpy as np

# 从 sklearn.linear_model 模块导入 LogisticRegression 类,用于实现逻辑回归或 Softmax 回归

from sklearn.linear_model import LogisticRegression

# 创建一个 LogisticRegression 的实例,指定参数为多分类模式,使用 sag 算法,正则化系数为 200,最大迭代次数为 10000

sklr = LogisticRegression(multi_class='multinomial', solver='sag', C=200, max_iter=10000)

# 从 prettytable 模块导入 PrettyTable 类,用于格式化输出混淆矩阵

from prettytable import PrettyTable

# 定义一个函数,用于计算并输出真实标签和预测标签之间的混淆矩阵

def confusion(realy, outy, method='Sklearn'):

# 创建一个 PrettyTable 的实例,用于存储混淆矩阵的数据

mix = PrettyTable()

# 获取真实标签中的所有类别,并按照降序排序

type = sorted(list(set(realy.T[0])), reverse=True)

# 设置表格的列名,第一列为方法名,后面的列为预测的各个类别

mix.field_names = [method] + ['预测:%d类'%si for si in type]

# 用一个字典来存储混淆矩阵的数据,键为真实的类别,值为一个列表,表示预测为各个类别的样本数量

cmdict = {}

# 遍历真实的类别

for jkj in type:

# 初始化一个空列表

cmdict[jkj] = []

# 遍历预测的类别

for hh in type:

# 计算真实为 jkj 类,预测为 hh 类的样本数量,并添加到列表中

hu = len(['0' for jj in range(len(realy)) if realy[jj][0] == jkj and outy[jj][0] == hh])

cmdict[jkj].append(hu)

# 遍历真实的类别

for fu in type:

# 将每一行的数据添加到表格中,第一列为真实的类别,后面的列为预测的各个类别的样本数量

mix.add_row([u'真实:%d类'%fu] + cmdict[fu])

# 返回表格对象

return mix

# 定义一个函数,用于将独热编码的类别变为标识为 1,2,3 的类别

def transign(eydata):

# 初始化一个空列表

ysign = []

# 遍历独热编码的类别

for hh in eydata:

# 找到 1 的位置,加 1 后作为类别标识,并添加到列表中

ysign.append([list(hh).index(1) + 1])

# 将列表转化为 numpy 数组并返回

return np.array(ysign)

# 主函数

if __name__ == '__main__':

# 调用sklearn的LogisticRegression实例的 fit 方法,用鸢尾花数据集的特征和类别来训练 Softmax 回归模型

regre = sklr.fit(smdata[0], transign(smdata[1]).T[0])

# 调用 predict 方法,用训练好的模型来预测鸢尾花数据集的类别

predata = np.array([sklr.predict(smdata[0])]).T

# 打印模型的系数,包括权重向量和截距项

print('系数为:\n', np.hstack((sklr.coef_, np.array([sklr.intercept_]).T)).T)

# 调用 confusion 函数,输出真实标签和预测标签之间的混淆矩阵

    print('混淆矩阵:\n', confusion(transign(smdata[1]), predata))

输出结果:

输出结果是用 Softmax 回归对鸢尾花数据集进行多分类的结果,其中:

系数为:是一个 5×3 的二维数组,它表示 Softmax 回归模型的参数矩阵,每一列表示一个类别的权重向量和截距项,每一行表示一个特征的系数。例如,第一列表示第一类(山鸢尾)的权重向量和截距项,第一行表示第一个特征(萼片长度)的系数。混淆矩阵:是一个 3×3 的二维表格,它表示模型的预测结果和真实标签之间的对应关系,每一行表示真实的类别,每一列表示预测的类别,每个单元格表示真实为某一类,预测为某一类的样本数量。例如,第一行第一列表示真实为第一类(山鸢尾),预测为第一类(山鸢尾)的样本数量,为 49。

三、示例代码2-Softmax-TensorFlow

使用 TensorFlow 2.x 实现 softmax 回归模型,对鸢尾花数据集进行分类。代码的主要步骤如下:

导入所需的模块,如 tensorflow,numpy,prettytable 等。定义一个 confusion 函数,用于计算混淆矩阵,评估模型的分类效果。函数的参数包括:

realy:真实的类别标签,是一个一维数组。outy:预测的类别标签,是一个一维数组。method:模型的名称,用于在表格的第一列显示,默认为 TensorFlow。定义一个 transign 函数,用于将独热编码的类别变为标识为 1,2,3 的类别。函数的参数是:

eydata:独热编码的类别标签,是一个二维数组,每一行是一个样本,每一列是一个类别的独热编码。定义一个 trans_tf 函数,用于构建和训练 softmax 回归模型。函数的参数包括:

datax:输入数据的特征矩阵,是一个二维数组,每一行是一个样本,每一列是一个特征。datay:输入数据的标签矩阵,是一个二维数组,每一行是一个样本,每一列是一个类别的独热编码。prea:预测数据的特征矩阵,是一个二维数组,用于测试模型的泛化能力。learn_rate:学习率,控制梯度下降的速度,默认为 0.8。iter_tiems:迭代次数,控制训练的轮数,默认为 40000。error:误差阈值,控制训练的提前结束条件,默认为 1e-9。在 trans_tf 函数中,首先将输入数据和标签转换为张量,然后定义变量 Weight 和 Bias,用于存储 softmax 回归的参数。接着定义模型的输出 model_output,使用 tf.nn.softmax 函数将线性组合转换为概率分布。然后定义损失函数 costfunc,使用交叉熵作为分类的代价,并加入 L2 正则化项,防止过拟合。接下来定义优化器 optimizer,使用梯度下降法更新参数。最后,在循环中执行训练步骤,记录损失函数的值,直到达到迭代次数或误差阈值。最后,返回损失函数的值,预测数据的类别,以及模型的参数。在主函数中,首先从 Iris_Data 模块中导入鸢尾花数据集,然后调用 trans_tf 函数,传入训练数据和预测数据,得到训练结果。然后打印模型的参数和混淆矩阵,评估模型的分类效果。最后,使用 matplotlib 模块绘制损失函数的图像,展示模型的收敛过程。

import tensorflow as tf

# 导入 Iris 数据集,将其分为特征数据 smdata[0] 和标签数据 smdata[1]

from Iris_Data import Data as smdata

import numpy as np

# 定义一个函数,用于计算混淆矩阵

from prettytable import PrettyTable

def confusion(realy, outy, method='TensorFlow'):

mix = PrettyTable()

type = sorted(list(set(realy.T[0])), reverse=True)

mix.field_names = [method] + ['预测:%d类'%si for si in type]

cmdict = {}

for jkj in type:

cmdict[jkj] = []

for hh in type:

hu = len(['0' for jj in range(len(realy)) if realy[jj][0] == jkj and outy[jj][0] == hh])

cmdict[jkj].append(hu)

for fu in type:

mix.add_row(['真实:%d类'%fu] + cmdict[fu])

# 返回表格对象

return mix

# 定义一个函数,用于将独热编码的类别变为标识为 1,2,3 的类别

def transign(eydata):

ysign = []

for hh in eydata:

ysign.append([list(hh).index(1) + 1])

return np.array(ysign)

# 定义一个函数,用于构建 softmax 回归模型 使用tensorflow2.x

def trans_tf(datax, datay, prea, learn_rate=0.8, iter_tiems=40000, error=1e-9):

x_data = tf.convert_to_tensor(datax, dtype=tf.float32)

y_target = tf.convert_to_tensor(datay, dtype=tf.float32)

Weight = tf.Variable(tf.random.normal(shape=[len(datax[0]), len(datay[0])]))

Bias = tf.Variable(tf.random.normal(shape=[1, len(datay[0])]))

def model_output(x_data):

x_data= tf.cast(x_data, tf.float32)

return tf.nn.softmax(tf.add(tf.matmul(x_data, Weight), Bias))

def cross_entropy(y_target, y_pred):

return tf.reduce_sum(y_target * tf.math.log(y_pred))

def regularizer():

return tf.nn.l2_loss(Weight) * 2 / 20000

def costfunc(y_target, y_pred):

return -cross_entropy(y_target, y_pred) / len(datax) + regularizer()

optimizer = tf.optimizers.SGD(learn_rate) # 梯度

#optimizer = tf.optimizers.Momentum(learning_rate=learn_rate, momentum=0.9) # 动量法

#optimizer = tf.optimizers.Adadelta(learning_rate=learn_rate, rho=0.55, epsilon=1e-08)

#optimizer = tf.optimizers.Adam(learning_rate=learn_rate, beta1=0.9, beta2=0.99, epsilon=1e-08)

loss_vec = []

# 开始训练

for i in range(iter_tiems):

with tf.GradientTape() as tape:

y_pred = model_output(x_data)

loss = costfunc(y_target, y_pred)

gradients = tape.gradient(loss, [Weight, Bias])

optimizer.apply_gradients(zip(gradients, [Weight, Bias]))

loss_vec.append(loss.numpy())

if len(loss_vec) > 2:

if loss_vec[-2] - loss_vec[-1] >= 0 and (loss_vec[-2] - loss_vec[-1]) <= error:

break

predata = model_output(prea)

maxnumber = tf.reduce_max(predata, axis=1)

y_pre_type = []

for jj in range(len(maxnumber)):

fu = tf.where(tf.equal(predata[jj], maxnumber[jj]))[0][0] + 1

y_pre_type.append([fu])

y_pre_type = np.array(y_pre_type)

# 返回成本函数的值的列表,预测的类别的数组,以及权重矩阵和偏置向量的值

return loss_vec, y_pre_type, Weight.numpy(), Bias.numpy()

# 主函数

if __name__ == '__main__':

tf_result = trans_tf(smdata[0], smdata[1], smdata[0])

print('系数:\n', np.vstack((tf_result[2], tf_result[3])))

print('混淆矩阵:\n', confusion(transign(smdata[1]), tf_result[1]))

# 绘制成本函数的图像

import matplotlib.pyplot as plt

from pylab import mpl # 作图显示中文

# 设置中文字体为仿宋

mpl.rcParams['font.sans-serif'] = ['FangSong']

# 设置不显示负号

mpl.rcParams['axes.unicode_minus'] = False

plt.plot(list(range(len(tf_result[0]))), tf_result[0], '-', linewidth=5)

plt.title('成本函数图')

plt.ylabel('Cost 值')

plt.xlabel('迭代次数')

plt.show()

输出结果:

四、示例代码3-Softmax  自定义实现

使用逻辑回归模型对鸢尾花数据集进行分类,评估模型的效果。代码使用了梯度下降法和正则化技术来优化模型的参数,使用了混淆矩阵和成本函数来评估模型的性能。代码使用了 numpy 库来进行矩阵运算,使用了 prettytable 库来生成表格,使用了 matplotlib 库来绘制图像。

from Iris_Data import Data as smdata

import numpy as np

class LRReg:

def __init__(self, learn_rate=0.9, iter_times=40000, error=1e-17):

self.learn_rate = learn_rate

self.iter_times = iter_times

self.error = error

# w和b合为一个参数,也就是x最后加上一列全为1的数据。

def trans(self, xdata):

one1 = np.ones(len(xdata))

xta = np.append(xdata, one1.reshape(-1, 1), axis=1)

return xta

# 梯度下降法

def Gradient(self, xdata, ydata, func=trans):

xdata = func(self, xdata)

# 系数w,b的初始化

self.weights = np.zeros((len(xdata[0]), len(ydata[0])))

# 存储成本函数的值

cost_function = []

for i in range(self.iter_times):

# 计算np.exp(X.W)的值

exp_xw = np.exp(np.dot(xdata, self.weights))

#计算y_predict每一行的和值

sumrow = np.sum(exp_xw, axis=1).reshape(-1, 1)

# 计算除去和值得值

devi_sum = exp_xw / sumrow

# 计算减法

sub_y = ydata - devi_sum

# 得到梯度

grad_W = -1 / len(xdata) * np.dot(xdata.T, sub_y)

# 正则化

# 成本函数中添加系数的L2范数

l2norm = np.sum(0.5 * np.dot(self.weights.T, self.weights) / len(xdata))

last_grad_W = grad_W + 0.002 * self.weights / len(xdata)

# 计算最大似然的对数的值

likehood = np.sum(ydata * np.log(devi_sum))

cost = - likehood / len(xdata) + l2norm

cost_function.append(cost)

# 训练提前结束

if len(cost_function) > 2:

if 0 <= cost_function[-2] - cost_function[-1] <= self.error:

break

#更新

self.weights = self.weights - self.learn_rate * last_grad_W

return self.weights, cost_function

# 预测

def predict(self, xdata, func=trans):

pnum = np.dot(func(self, xdata), self.weights)

# 选择每一行中最大的数的index

maxnumber = np.max(pnum, axis=1)

# 预测的类别

y_pre_type =[]

for jj in range(len(maxnumber)):

fu = list(pnum[jj]).index(maxnumber[jj]) + 1

y_pre_type.append([fu])

return np.array(y_pre_type)

# 将独热编码的类别变为标识为1,2,3的类别

def transign(eydata):

ysign = []

for hh in eydata:

ysign.append([list(hh).index(1) + 1])

return np.array(ysign) #

#计算混淆矩阵

from prettytable import PrettyTable

def confusion(realy, outy, method='AnFany'):

mix = PrettyTable()

type = sorted(list(set(realy.T[0])), reverse=True)

mix.field_names = [method] + ['预测:%d类'%si for si in type]

# 字典形式存储混淆矩阵数据

cmdict = {}

for jkj in type:

cmdict[jkj] = []

for hh in type:

hu = len(['0' for jj in range(len(realy)) if realy[jj][0] == jkj and outy[jj][0] == hh])

cmdict[jkj].append(hu)

# 输出表格

for fu in type:

mix.add_row(['真实:%d类'%fu] + cmdict[fu])

return mix

# 主函数

if __name__ == '__main__':

lr_re = LRReg() #

lf = lr_re.Gradient(smdata[0], smdata[1])

y_calss_pre = lr_re.predict(smdata[0])

print('系数:\n', lr_re.weights)

print('混淆矩阵:\n', confusion(transign(smdata[1]), y_calss_pre))

# 绘制成本函数图

import matplotlib.pyplot as plt

from pylab import mpl # 作图显示中文

mpl.rcParams['font.sans-serif'] = ['FangSong'] # 设置中文字体新宋体

mpl.rcParams['axes.unicode_minus'] = False

plt.plot(list(range(len(lf[1]))), lf[1], '-', linewidth=5)

plt.title('成本函数图')

plt.ylabel('Cost 值')

plt.xlabel('迭代次数')

plt.show()

输出结果:

代码解读:

五、以上三种softmax回归对比(自定义、sklearn、tensorflow2.x)

使用三种不同的方法实现 softmax 回归模型,对一个人工生成的数据集进行多分类,并绘制不同方法的分割结果和混淆矩阵。

# 引入三种方法

import Softmax_AnFany as SM_A # 需要注释105行以后的内容

import Softmax_Sklearn as SM_S # 需要注释37行以后的内容

import Softmax_TensorFlow as SM_T # 需要注释86行以后的内容

import matplotlib.pyplot as plt # 引入绘图模块

from pylab import mpl # 作图显示中文

mpl.rcParams['font.sans-serif'] = ['FangSong'] # 设置中文字体新宋体

mpl.rcParams['axes.unicode_minus'] = False # 设置正常显示负号

import numpy as np # 引入数值计算模块

x_data = np.random.random((900, 2)) # 生成900个二维特征的随机样本

y_data = [] # 初始化标签列表

for dat in x_data: # 遍历每个样本

if dat[1] - 3 * dat[0] + 0.5 >= 0: # 根据一个线性函数划分为第一类

y_data.append([1, 0, 0]) # 用独热编码表示类别

elif dat[1] - 3 * dat[0] + 0.5 < 0 and dat[1] - 3 * dat[0] + 1.5 > 0 : # 根据另一个线性函数划分为第二类

y_data.append([0, 1, 0]) # 用独热编码表示类别

elif dat[1] - 3 * dat[0] + 1.5 <= 0: # 其他情况划分为第三类

y_data.append([0, 0, 1]) # 用独热编码表示类别

y_data = np.array(y_data) # 将标签列表转换为数组

def divided(xdata, ydata, percent=0.2): # 定义一个函数,用于将数据集划分为训练集和测试集

sign_list = list(range(len(xdata))) # 生成样本的序号列表

#用于测试的序号

select_sign = sorted(np.random.choice(sign_list, int(len(xdata)*percent), replace=False)) # 随机选择一定比例的序号作为测试集的序号

no_select_sign = [isign for isign in sign_list if isign not in select_sign] # 剩余的序号作为训练集的序号

x_predict_data = xdata[select_sign] # 根据测试集的序号筛选特征矩阵

y_predict_data = ydata[select_sign] # 根据测试集的序号筛选标签矩阵

x_train_data = xdata[no_select_sign] # 根据训练集的序号筛选特征矩阵

y_train_data = ydata[no_select_sign] # 根据训练集的序号筛选标签矩阵

return x_train_data, y_train_data, x_predict_data, y_predict_data #返回训练集和测试集的特征矩阵和标签矩阵

# 数据名称

Train_X, Train_Y, Predict_X, Predict_Y = divided(x_data, y_data) # 调用函数,划分数据集

# 绘制散点图

def fig_scatter(exdata, eydata, titl='训练数据散点图', co=['r', 'b', 'g'], marker=['o','*','^']): # 定义一个函数,用于绘制数据集的散点图

for ii in range(len(eydata[0])): # 遍历每个类别

datax = exdata[eydata[:, ii] == 1] # 根据标签矩阵筛选出属于该类别的样本

plt.scatter(datax[:, 0], datax[:, -1], c=co[ii], s=50, marker=marker[ii]) # 绘制样本的散点图,用不同的颜色和标记表示不同的类别

plt.title(titl) # 设置图的标题

plt.legend(['1类', '2类', '3类']) # 设置图例

plt.xlabel('X1 值') # 设置x轴标签

plt.ylabel('X2 值') # 设置y轴标签

# 计算不同的方法得到的结果

# AnFany

lr_re = SM_A.LRReg() # 创建一个Softmax_AnFany模块中的LRReg类的实例

lf = lr_re.Gradient(Train_X, Train_Y) # 调用Gradient方法,传入训练数据,得到参数矩阵和成本函数的值的列表

Pre = lr_re.predict(Predict_X) # 调用predict方法,传入测试数据,得到预测类别的数组

print('AnFany混淆矩阵:\n', SM_A.confusion(SM_A.transign(Predict_Y), Pre)) # 调用confusion函数,传入真实类别和预测类别,得到混淆矩阵,打印混淆矩阵

# Sklearn

regre = SM_S.sklr.fit(Train_X, SM_S.transign(Train_Y).T[0]) # 调用Softmax_Sklearn模块中的sklr对象的fit方法,传入训练数据,得到参数矩阵

predata = np.array([SM_S.sklr.predict(Predict_X)]).T # 调用sklr对象的predict方法,传入测试数据,得到预测类别的数组

print('Sklearn混淆矩阵:\n',SM_S.confusion(SM_S.transign(Predict_Y), predata)) # 调用confusion函数,传入真实类别和预测类别,得到混淆矩阵,打印混淆矩阵

# TensorFlow

tf_result = SM_T.trans_tf(Train_X, Train_Y, Predict_X) # 调用Softmax_TensorFlow模块中的trans_tf函数,传入训练数据和测试数据,得到参数矩阵和预测类别的数组

print('TensorFlow混淆矩阵:\n', SM_T.confusion(SM_T.transign(Predict_Y), tf_result[1])) # 调用confusion函数,传入真实类别和预测类别,得到混淆矩阵,打印混淆矩阵

plt.subplot(2, 1, 1) # 创建一个2行1列的子图,选择第一个子图

fig_scatter(Train_X, Train_Y) # 调用fig_scatter函数,绘制训练数据的散点图

plt.subplot(2, 1, 2) # 选择第二个子图

plt.text(0.5, 0.9, '训练的结果展示', size='large', weight='extra bold') # 在图中添加文本,显示标题

plt.axis('off') # 关闭坐标轴

plt.text(0.00, 0.7, 'AnFany 系数\n%s'%lr_re.weights, size='large') # 在图中添加文本,显示AnFany方法的参数矩阵

plt.text(0.33, 0.5, 'Sklearn 系数\n%s'%np.hstack((SM_S.sklr.coef_, np.array([SM_S.sklr.intercept_]).T)).T, size='large') # 在图中添加文本,显示Sklearn方法的参数矩阵

plt.text(0.66, 0.3, 'TensorFlow 系数\n%s'%np.vstack((tf_result[2], tf_result[3])), size='large') # 在图中添加文本,显示TensorFlow方法的参数矩阵

plt.show() # 显示图像

# 输出预测的结果

#根据三种方法生成的系数,绘制分割线

#绘制三种方法各自生成的直线需要的数据

def tnd_ydata(datdxx, weights): # 定义一个函数,用于计算不同方法的参数矩阵对应的分割面的值

dmin = datdxx[:, 0] # 取特征矩阵的第一列

x1da = np.linspace(datdxx[:, 0].min() - 0.2, datdxx[:, 0].max() + 0.2, 100) # 在第一列的最小值和最大值之间生成100个等间距的点

x2da = np.linspace(datdxx[:, 1].min() - 0.2, datdxx[:, 1].max() + 0.2, 100) # 在第二列的最小值和最大值之间生成100个等间距的点

X, Y = np.meshgrid(x1da, x2da) # 生成网格矩阵,用于表示特征空间中的所有点

ydaset = [] # 初始化分割面的值的列表

tw = weights.T # 转置参数矩阵 kx(n+1) 3x3

for hh in range(len(tw)): # 遍历每个类别

yda = tw[hh][0] * X + tw[hh][1] * Y + tw[hh][2] # 计算每个点属于该类别的得分,即特征矩阵乘以参数矩阵的结果

ydaset.append(yda) # 将每个类别的得分矩阵存储在一个列表中 3x1 三个小矩阵构成一个大矩阵

return X, Y, ydaset # 返回网格矩阵和得分矩阵的列表

from mpl_toolkits.mplot3d import Axes3D # 引入三维绘图模块

Af_data = tnd_ydata(Train_X, lr_re.weights)# AnFany # 调用tnd_ydata函数,传入训练数据和AnFany方法的参数矩阵,得到AnFany方法的分割面的值

Sk_data = tnd_ydata(Train_X, np.hstack((SM_S.sklr.coef_, np.array([SM_S.sklr.intercept_]).T)).T) # Sklearn # 调用tnd_ydata函数,传入训练数据和Sklearn方法的参数矩阵,得到Sklearn方法的分割面的值

Tf_data = tnd_ydata(Train_X, np.vstack((tf_result[2], tf_result[3]))) # TensorFlow # 调用tnd_ydata函数,传入训练数据和TensorFlow方法的参数矩阵,得到TensorFlow方法的分割面的值

fig = plt.figure() # 创建一个plt.figure对象,用于绘制四个子图

ax = fig.add_subplot(2, 2, 1, projection='3d') # 创建一个2行2列的子图,选择第一个子图,设置为三维投影

fig_scatter(Train_X, Train_Y) # 调用fig_scatter函数,绘制训练数据的散点图,用不同的颜色和标记表示不同的类别

ax.plot_wireframe(Af_data[0], Af_data[1], Af_data[2][0], color='r') # 调用ax.plot_wireframe函数,绘制AnFany方法的第一类的分割面,用红色表示

ax.plot_wireframe(Af_data[0], Af_data[1], Af_data[2][1], color='b') # 调用ax.plot_wireframe函数,绘制AnFany方法的第二类的分割面,用蓝色表示

ax.plot_wireframe(Af_data[0], Af_data[1], Af_data[2][2], color='g') # 调用ax.plot_wireframe函数,绘制AnFany方法的第三类的分割面,用绿色表示

ax.set_zlabel(r'$X_{i} \dot W$') # 设置z轴的标签,用LaTeX表示

plt.title('AnFany训练得出的分割结果') # 设置图的标题

ax.set_yticks(np.linspace(-0.2, 1.4, 3)) # 设置y轴的刻度

ax.set_xticks(np.linspace(-0.2, 1.4, 3)) # 设置x轴的刻度

plt.legend(['1类', '2类', '3类', '1类分割面', '2类分割面', '3类分割面'], bbox_to_anchor=(1.2, 0.9)) # 设置图例,用bbox_to_anchor参数调整位置

ax = fig.add_subplot(2, 2, 2, projection='3d') # 选择第二个子图,设置为三维投影

fig_scatter(Train_X, Train_Y) # 调用fig_scatter函数,绘制训练数据的散点图,用不同的颜色和标记表示不同的类别

ax.plot_wireframe(Sk_data[0], Sk_data[1], Sk_data[2][0], color='r') # 调用ax.plot_wireframe函数,绘制Sklearn方法的第一类的分割面,用红色表示

ax.plot_wireframe(Sk_data[0], Sk_data[1], Sk_data[2][1], color='b') # 调用ax.plot_wireframe函数,绘制Sklearn方法的第二类的分割面,用蓝色表示

ax.plot_wireframe(Sk_data[0], Sk_data[1], Sk_data[2][2], color='g') # 调用ax.plot_wireframe函数,绘制Sklearn方法的第三类的分割面,用绿色表示

ax.set_zlabel(r'$X_{i} \dot W$') # 设置z轴的标签,用LaTeX表示

ax.set_yticks(np.linspace(-0.2, 1.4, 3)) # 设置y轴的刻度

ax.set_xticks(np.linspace(-0.2, 1.4, 3)) # 设置x轴的刻度

plt.title('Sklearn训练得出的分割结果') # 设置图的标题

plt.legend(['1类', '2类', '3类', '1类分割面', '2类分割面', '3类分割面'], bbox_to_anchor=(1.2, 0.9)) # 设置图例,用bbox_to_anchor参数调整位置

ax = fig.add_subplot(2, 2, 3, projection='3d') # 选择第三个子图,设置为三维投影

fig_scatter(Train_X, Train_Y) # 调用fig_scatter函数,绘制训练数据的散点图,用不同的颜色和标记表示不同的类别

ax.plot_wireframe(Tf_data[0], Tf_data[1], Tf_data[2][0], color='r') # 调用ax.plot_wireframe函数,绘制TensorFlow方法的第一类的分割面,用红色表示

ax.plot_wireframe(Tf_data[0], Tf_data[1], Tf_data[2][1], color='b') # 调用ax.plot_wireframe函数,绘制TensorFlow方法的第二类的分割面,用蓝色表示

ax.plot_wireframe(Tf_data[0], Tf_data[1], Tf_data[2][2], color='g') # 调用ax.plot_wireframe函数,绘制TensorFlow方法的第三类的分割面,用绿色表示

ax.set_zlabel(r'$X_{i} \dot W$') # 设置z轴的标签,用LaTeX表示

ax.set_yticks(np.linspace(-0.2, 1.4, 3)) # 设置y轴的刻度

ax.set_xticks(np.linspace(-0.2, 1.4, 3)) # 设置x轴的刻度

plt.title('TensorFlow训练得出的分割结果') # 设置图的标题

plt.legend(['1类', '2类', '3类', '1类分割面', '2类分割面', '3类分割面'], bbox_to_anchor=(1.2, 0.9)) # 设置图例,用bbox_to_anchor参数调整位置

ax = fig.add_subplot(2, 2, 4) # 选择第四个子图

plt.title('预测结果三种方法的混淆矩阵对比') # 设置图的标题

plt.text(0.2, 0.6, SM_A.confusion(SM_A.transign(Predict_Y), Pre)) # 在图中添加文本,显示AnFany方法的混淆矩阵

plt.text(0.2, 0.3, SM_S.confusion(SM_S.transign(Predict_Y), predata)) # 在图中添加文本,显示Sklearn方法的混淆矩阵

plt.text(0.2, 0.0, SM_T.confusion(SM_T.transign(Predict_Y), tf_result[1])) # 在图中添加文本,显示TensorFlow方法的混淆矩阵

plt.axis('off') # 关闭坐标轴

plt.show() # 显示图像

输出结果:

参考网址:

(1) What are the differences between softmax regression and logistic .... https://ai.stackexchange.com/questions/6368/what-are-the-differences-between-softmax-regression-and-logistic-regression-oth.(2) Difference between logistic regression and softmax regression. https://stackoverflow.com/questions/36051506/difference-between-logistic-regression-and-softmax-regression.(3) Do logistic regression and softmax regression do the same thing?. https://datascience.stackexchange.com/questions/14110/do-logistic-regression-and-softmax-regression-do-the-same-thing.(4) Is multinomial logistic regression really the same as softmax .... https://stats.stackexchange.com/questions/466646/is-multinomial-logistic-regression-really-the-same-as-softmax-regression.(5) undefined. http://ufldl.stanford.edu/tutorial/supervised/SoftmaxRegression/.

(6)https://zhuanlan.zhihu.com/p/98061179

(7)https://github.com/Anfany/Machine-Learning-for-Beginner-by-Python3

The End

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: