1、导入模块
import random
import numpy as np
import pandas as pd
import sklearn
import matplotlib. pyplot as plt
2、读取数据
data1=pd.read_csv('data1.csv')
data2=pd.read_csv('data2.csv')
data3=pd.read_csv('data3.csv')
data4=pd.read_csv('data4.csv')
#补全代码-----end-------#
print(type(data1))
代码输出结果:
二、数据合并、描述性统计及预处理
1、数据合并
data=pd.concat([data1,data2],axis=0)
data=pd.concat([data,data3])
data=pd.concat([data,data4])
#补全代码-----end-------#
data=data.reset_index(drop=True)
print(data)
代码输出结果:
2、查看是否存在缺失值
#补全代码-----begin-----#
data.isnull()
#补全代码-----end-------#
代码输出:
3、查看数据集大小(行数,列数)
#补全代码-----begin-----#
print('数据集的大小:',data.shape)
#补全代码-----end-------#
代码输出:
4、显示数据前5行
data.head(5)
结果:
5、查看数据描述信息
#补全代码-----begin-----#
data.describe()
#补全代码-----end-------#
结果:
6、数据标准化
#标准化处理
from sklearn import preprocessing
features = pd.DataFrame(preprocessing.scale(data.iloc[:,1:]))
features.columns = data.columns[1:]
features
结果:
7、标签独热编码处理。
#标签独热编码处理
ohe = preprocessing.OneHotEncoder(sparse=False)
tmp = ohe.fit_transform(pd.DataFrame(data['0']))
label = pd.DataFrame([i for i in pd.DataFrame(tmp).values])
label['label'] = [i for i in label.values]
label
结果:
二、数据集划分
from sklearn.model_selection import train_test_split
#数据拆分
trainX, testX, trainY, testY = train_test_split(features, label['label'], test_size=0.2, random_state=0)
print('初始训练集的数据大小:',trainX.shape,'初始测试集的数据大小:', testX.shape, '目标训练集的数据大小:',trainY.shape,'初始测试集的数据大小:', testY.shape)
结果:
三、定义损失函数
# 交叉熵成本函数
class CrossEntropyCost(object):
@staticmethod
def fn(a, y):
# 使用0代替数组x中的nan元素,使用有限的数字代替inf元素
return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a)))
# 返回从输出层传回的误差Δ,注意参数Z不使用
@staticmethod
def delta(z, a, y):
return (a-y)
2、平方误差函数
# 定义平方损失函数
class QuadraticCost(object):
# 返回与输出相关联的成本
@staticmethod
def fn(a, y):
return 0.5*np.linalg.norm(a-y)**2
# 返回输出层传回的误差Δ
@staticmethod
def delta(z, a, y):
return (a-y) * sigmoid_prime(z)
四、定义激活函数及其导数
1、定义激活函数
# sigmoid函数
def sigmoid(z):
#补全代码-----begin-----#
return 1/(1+np.e**(-z))
#补全代码-----end-------#
2、求激活函数的导数
# sigmoid函数的导数
def sigmoid_prime(z):
return sigmoid(z) * (1 - sigmoid(z))
五、模型定义
#测试np.random.randn
import numpy as np
np.random.randn(2, 4)
结果:
核心代码 :
class Network(object):
def __init__(self, sizes, cost=QuadraticCost):
# sizes是一个列表,存放有每层神经元的个数
# 设置神经网络的层数
self.num_layers = len(sizes)
# sizes即每层神经元的个数
self.sizes = sizes
# 参数初始化方法
self.default_weight_initializer()
# 损失函数计算方法
self.cost = cost
# 初始化方法1-赋随机值(服从正态分布,方差为sqrt(x)),对权重和阈值(偏置)进行初始化
def default_weight_initializer(self):
# 阈值初始化,从第二层开始设置(第一层为输入层,不设置阈值)
# randn的作用就是从标准正态分布中返回一个或多个样本值,此处返回y行的向量
self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]]
# 权值初始化 此处每次返回y行x列的矩阵,构成权值列表
self.weights = [np.random.randn(y, x)/np.sqrt(x) for x, y in zip(self.sizes[:-1], self.sizes[1:])]
# 初始化方法1-(与默认初始化方法-初始化方法1相比,方差为1)
def large_weight_initializer(self):
self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]]
self.weights = [np.random.randn(y, x) for x, y in zip(self.sizes[:-1], self.sizes[1:])]
# 神经网络计算值正向传播,给定神经元的输入,计算其输出
def feedforward(self, a):
for b, w in zip(self.biases, self.weights):
a = sigmoid(np.dot(w, a)+b)
return a
# 误差反向传播,计算对应的梯度∇
def backprop(self, x, y):
#nabla 算符 ∇ “纳布拉”
#阈值与权重的“梯度”
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
# 激活函数的输出值 对于输入层,无激活函数,直接是训练实例x的值
activation = x[:,None]
# 用于存储所有经过激活函数后的输出值,当前放入输入层的激活函数——无激活函数,激活函数的输出等于输入x
activations = [activation]
# 用于存储所有中间向量z(中间神经元的输出,进激活函数之前的值)
zs = []
for b, w in zip(self.biases, self.weights):
# 计算中间变量(神经元的输出Z=W*X+b,还未经过激活函数时的值)
z = np.dot(w, activation)+b
# 存储所有中间向量z
zs.append(z)
# 过激活函数后的值,隐含层激活函数使用sigmoid函数sigmoid(W*X+b)
activation = sigmoid(z)
# 列表存储所有神经元经过激活函数后的值
activations.append(activation)
# 反向更新
# 输出层
# 计算输出层误差error
# 计算损失函数cost_derivative(
# 求梯度
delta = (self.cost).delta(zs[-1], activations[-1], y)
# 计算输出层的nabla_b,nabla_w
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
# 隐藏层
# 解释numpy.transpose()的作用:
# 起矩阵转置的作用。
# 详细解释此段代码的作用,添加注释-begin--#
for ls in range(2, self.num_layers):
z = zs[-ls] #存储从2到总神经网络的层数的所有中间向量
sp = sigmoid_prime(z) #求出sigmoid函数在z的导数
delta = np.dot(self.weights[-ls+1].transpose(), delta) * sp #返回输出层传回的误差Δ
# 逐层往前计算
nabla_b[-ls] = delta
nabla_w[-ls] = np.dot(delta, activations[-ls-1].transpose())
# 详细解释此段代码的作用,添加注释-end--#
return (nabla_b, nabla_w)
# 模型训方法SGD
# epochs表示训练多少轮, mini_batch_size表示每次从训练集中抽取多少实例,eta表示学习率,lmbda为正则化参数
#(实际不是随机梯度下降,而是小批量梯度下降MBGD:min-batch 小批量梯度下降法MBGD)
def SGD(self, training_data, epochs, mini_batch_size, eta,
# lmbda-正则化参数
lmbda = 0.0,
evaluation_data=None):
# 如果有验证集
if evaluation_data:
n_data = len(evaluation_data)
n = len(training_data)
#保存验证集损失、验证集上预测的准确次数
evaluation_cost, evaluation_accuracy = [], []
#保存训练集损失、训练集上预测的准确次数
training_cost, training_accuracy = [], []
# j代表第几轮,共epochs轮
for j in range(epochs):
# 将training_data中的数据随机打乱
random.shuffle(training_data)
# 每次抽取mini_batch_size大小的数据作为一小块,抽取时起点从0到n每次间隔mini_batch_size
mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]
# 对取出来的mini_batchs逐个进行更新
for mini_batch in mini_batches:
# 更新weights和biases
self.update_mini_batch(mini_batch, eta, lmbda, len(training_data))
#训练集损失
cost = self.total_cost(training_data,lmbda)
training_cost.append(cost)
#训练集上模型预测准确的次数
accuracy = self.accuracy(training_data)
training_accuracy.append(accuracy)
# 验证集损失
#补全代码-----begin-----#
cost1 = self.total_cost(evaluation_data,lmbda)
evaluation_cost.append(cost1)
#补全代码-----end-------#
# 验证集上模型预测准确的次数
#补全代码-----begin-----#
accuracy1 = self.accuracy(evaluation_data)
evaluation_accuracy.append(accuracy1)
#补全代码-----end-------#
#验证集数据转换
#argmax返回指定axis上最大值的下标;argmin则返回最小值的下标,参考:https://www.jb51.net/article/213986.htm
#对于验证集里的数据(x,y),返回模型的输出值feedforward(x)中的最大值与实际值y的最大值构成的元组
evaluate_data = [(np.argmax(self.feedforward(x).sum(axis=1)), np.argmax(y)) for (x, y) in evaluation_data]
return evaluation_cost, evaluation_accuracy, training_cost, training_accuracy,evaluate_data
# eta:学习率 n:训练集实例数量
# 传入单批量数据mini_batch,根据其x、y值(特征、标签),对整个神经网络的wights和biases进行更新
def update_mini_batch(self, mini_batch, eta, lmbda, n):
# 初始化 nabla 算符 ∇
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
for x, y in mini_batch:
# 计算对应的更新量
delta_nabla_b, delta_nabla_w = self.backprop(x, y[:,None])
nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
# 更新权重weights W'k=(1-(eta*lmbda/n))W-(eta/n)&C/&Wk &表示偏导 C表示损失函数
self.weights = [(1-eta*(lmbda/n))*w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)]
# 更新阈值biases b'k=bk-(eta/n)&C/&bk &表示偏导 C表示损失函数
self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)]
# 计算模型预测的准确次数
def accuracy(self, data_in):
results = [(np.argmax(self.feedforward(x).sum(axis=1)), np.argmax(y)) for (x, y) in data_in]
return sum(int(x == y) for (x, y) in results)
# 统计给定数据集data_in上的总误差
def total_cost(self, data_in, lmbda):
cost = 0.0
for x, y in data_in:
a = self.feedforward(a = x[:,None])
# 累积误差
cost += self.cost.fn(a, y)/len(data_in)
# 加上权重的L2正则化项:(lmbda/2n)*sum(w**2),len(data_in):数据集中包含实例个数
# 经验误差+结构误差,避免模型过拟合
cost += 0.5*(lmbda/len(data_in))*sum(np.linalg.norm(w)**2 for w in self.weights)
return cost
六、模型调用
#补全代码-----begin-----#
net=Network(sizes=[24,100,4,4],cost=CrossEntropyCost)
#补全代码-----end-------#
2、对权重和偏置进行初始化
#补全代码-----begin-----#
net.large_weight_initializer()
#补全代码-----end-------#
3、设置训练次数times为100。
#补全代码-----begin-----#
times=100
#补全代码-----end-------#
4、构造训练集
# 训练集数据格式转化
training_data = list(zip(trainX.to_numpy(),trainY.to_numpy()))
# 测试集数据格式转化
test_data = list(zip(testX.to_numpy(),testY.to_numpy()))
5、模型训练
#补全代码-----begin-----#
evaluation_cost, evaluation_accuracy, training_cost, training_accuracy,evaluate_data=net.SGD(training_data=training_data[:1000],
epochs=times, mini_batch_size=20, eta=0.4,
# lmbda-正则化参数
lmbda = 0.001,
evaluation_data=test_data)
print(evaluation_cost, evaluation_accuracy, training_cost, training_accuracy,evaluate_data)
#补全代码-----end-------#
代码输出结果:
6、计算模型准确率
##测试np.tile
arr1 = np.array([100,102,104,105])
arr2 = np.tile(200,4)
print(arr2)
arr3= arr1/arr2
print(arr3)
结果:
# 计算训练集的准确率training_accuracy
#补全代码-----begin-----#
arr4=np.array(training_accuracy)
arr5=np.tile(len(training_data),times)
arr6=arr4/arr5
print(arr6)
#补全代码-----end-------#
# 计算验证集的准确率evaluation_accuracy
#补全代码-----begin-----#
arr7=np.array(evaluation_accuracy)
arr8=np.tile(len(evaluate_data),times)
arr9=arr7/arr8
print(arr9)
#补全代码-----end-------#
结果:
七、数据可视化
#刘伟 21智能2班 18
x = np.arange(1, times+1, 1)
fig = plt.figure()
# plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=1)
ax1 = fig.add_subplot(4,1,1)
ax1 = plt.plot(x, evaluation_accuracy , 'g-', linewidth=2)
plt.ylabel('train_acc: %')
plt.grid()
#补全代码-----begin-----#
#绘制子图(4,1,2)
ax2 = fig.add_subplot(4,1,2)
ax2 = plt.plot(x, training_accuracy, 'r-', linewidth=2)
plt.ylabel('evaluation_acc: %')
plt.grid()
#补全代码-----end-------#
#补全代码-----begin-----#
#绘制子图(4,1,3)
ax2 = fig.add_subplot(4,1,3)
ax2 = plt.plot(x,training_cost, 'y-', linewidth=2)
plt.ylabel('train_cost')
plt.grid()
#补全代码-----end-------#
ax4 = fig.add_subplot(4,1,4)
ax4 = plt.plot(x, evaluation_cost, 'm-', linewidth=2)
plt.ylabel('evaluate_cost')
plt.xlabel('Epoch')
plt.grid()
fig.tight_layout()
plt.show()
输出结果:
到这里就基本上没有什么问题了,大家如果有什么问题都可以私信问我喔!
也可以关注我的公众号:风程序员
谢谢大家的关注!