1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 决策树 BP神经网络(BPNN) SVM实现iris鸢尾花数据集的分类

决策树 BP神经网络(BPNN) SVM实现iris鸢尾花数据集的分类

时间:2023-03-07 17:15:48

相关推荐

决策树 BP神经网络(BPNN) SVM实现iris鸢尾花数据集的分类

决策树 BP神经网络(BPNN) SVM实现iris鸢尾花数据集的分类

决策树

实现流程(详见代码)::

1.连续值处理

iris数据集是连续数据, 因为连续属性的可取值数目不再有限,因此不能像处理离散属性枚举离散属性取值来对结点进行划分。因此需要连续属性离散化,这里对数据集的离散化策略是二分法,

具体方法:

​ 将连续属性a的取值从小到大排序, 将相邻的属性值的中位数作为候选划分点, 这样,n个属性值可得到n-1个候选划分点, 计算样本集基于每个划分点t二分后的信息增益, 选择信息增益最大的候选划分点作为划分点(实际操作中只计算信息增益公式的减数部分)

2.计算样本集合的信息熵

3.计算属性的信息增益(由于信息熵相同, 每个属性实际只计算了公式的减数部分)

4.选择信息增益最大公式(减数部分最小)的属性作为根节点

5.对每个分支进一步划分, 使用递归计算其他节点

6.模型评估

from sklearn import datasetsimport mathimport numpy as npimport sys#获得属性的每个值的熵def getEntropy(counter):res = 0denominator = np.sum(counter)if denominator == 0:return 0for value in counter:if value == 0:continueres += value / denominator * math.log2(value / denominator if value > 0 and denominator > 0 else 1)return -res#随机抽取80%的训练集和20%的测试集def divideData():completeData = np.c_[iris.data, iris.target.T]np.random.shuffle(completeData)trainData = completeData[range(int(length * 0.8)), :]testData = completeData[range(int(length * 0.8), length), :]return [trainData, testData]#采用二分法对连续属性离散化#取连续集每两个数的中位点作为候选划分点,计算每个候选划分点的信息增益(这里只计算熵),获得最佳的划分点def discretization(index):temp = np.array(iris.data[:, index])temp= temp[temp[:].argsort()]feature=[]#计算小于划分点和大于划分点的结果数量集for i in range(len(temp)-1):counter1=[0,0,0]counter2=[0,0,0]counter1[0]=np.sum(iris.target[:i+1]==0)counter1[1] = np.sum(iris.target[:i + 1] == 1)counter1[2] = np.sum(iris.target[:i + 1] == 2)counter2[0] = np.sum(iris.target[i + 1:] == 0)counter2[1] = np.sum(iris.target[i + 1:] == 1)counter2[2] = np.sum(iris.target[i + 1:] == 2)feature.append([(temp[i]+temp[i+1])/2,counter1,counter2])minEntropy=sys.maxsizerazor=feature[0][0]#对每个划分点计算熵for i in range(len(feature)):leng=i+1remain = length - lengd1=getEntropy(feature[i][1])d2=getEntropy(feature[i][2])remain=length-lengentropy=(leng/length)*d1+(remain/length)*d2#选择熵最小(即信息增益最大)的特征作为划分点if entropy<minEntropy:minEntropy=entropyrazor=feature[i][0]return razor#连续值分割def getRazor():a = []for i in range(len(iris.feature_names)):a.append(discretization(i))print("切割点: ",a)return np.array(a)#寻找最大索引def findMaxIndex(dataSet):maxIndex = 0maxValue = -1for index, value in enumerate(dataSet):if value > maxValue:maxIndex = indexmaxValue = valuereturn maxIndex#递归生成树#featureSet: 特征集, dataSet: 数据集, counterSet: 三种花的个数def tree(featureSet, dataSet, counterSet):if (counterSet[0] == 0 and counterSet[1] == 0 and counterSet[2] != 0):return iris.target_names[2]if (counterSet[0] != 0 and counterSet[1] == 0 and counterSet[2] == 0):return iris.target_names[0]if (counterSet[0] == 0 and counterSet[1] != 0 and counterSet[2] == 0):return iris.target_names[1]if len(featureSet) == 0:return iris.target_names[findMaxIndex(counterSet)]if len(dataSet) == 0:return []res = sys.maxsizefinal = 0for feature in featureSet:i = razors[feature]set1 = []set2 = []counter1 = [0, 0, 0]counter2 = [0, 0, 0]for data in dataSet:index = int(data[-1])if data[feature] < i:set1.append(data)counter1[index] = counter1[index] + 1elif data[feature] >= i:set2.append(data)counter2[index] = counter2[index] + 1#计算属性的熵a = (len(set1) * getEntropy(counter1) + len(set2) * getEntropy(counter2)) / len(dataSet)#获得熵最小的属性作为树节点(即信息增益最大的属性)if a < res:res = afinal = featurefeatureSet.remove(final)child = [0, 0, 0]child[0] = final#递归生成其他树节点child[1] = tree(featureSet, set1, counter1)child[2] = tree(featureSet, set2, counter2)return child#模型评估def judge(test_data, tree):root = "unknow"while (len(tree) > 0):if isinstance(tree, str) and tree in iris.target_names:return treeroot = tree[0]if (isinstance(root, str)):return rootif isinstance(root, int):if test_data[root] < razors[root] and tree[1] != []:tree = tree[1]elif tree[2] != [] and (tree[1] == [] or (test_data[root] >= razors[root])):tree = tree[2]return rootif __name__ == '__main__':iris = datasets.load_iris()#随机获得80%的训练集和20%的测试集length = len(iris.target)[trainData, testData] = divideData()num = [0, 0, 0]for row in iris.data:num[int(row[-1])] = num[int(row[-1])] + 1#连续值分割razors = getRazor()#递归生成树tree = tree(list(range(len(iris.feature_names))), trainData,[np.sum(trainData[:, -1] == 0), np.sum(trainData[:, -1] == 1), np.sum(trainData[:, -1] == 2)])print("本次选取的训练集构建出的树: ", tree)#使用测试集进行模型评估index = 0right = 0print("预测结果 \t 实际结果")for data in testData:predict= judge(testData[index], tree)truth = iris.target_names[int(testData[index][-1])]index = index + 1if predict == truth:right = right + 1else:print(predict + "\t" + truth)print("决策树正确率: ", format(right / index*100,".2f"),"%")

BP神经网络(BPNN)

BP神经网络的大致思路:

1.信号的前向传播

​ 隐层神经元接收来自输入层的信号,隐层的每个神经元接收到的总输入值与神经元的阈值进行比较,然后通过“激活函数”处理以产生神经元的输出。输出层的神经元也是以同样方式产生神经元的输出。

2.反向计算梯度

计算代价函数进而求出输出层神经元的梯度项gj和隐层神经元的梯度项eh

3.更新权值和阈值

基于梯度下降策略, 以目标的负梯度方向对权值和阈值参数进行调整。

实现流程:

1.初始化参数

使用伪随机数来初始化权重和偏置矩阵

2.前向传播

根据初始化的参数计算隐层神经元的输入, 将tanh作为隐层的激活函数得到隐层的输出, 再计算输出层神经元的输入, 使用sigmoid作为第二层的激活函数得到输出

3.计算代价函数

使用交叉熵作为代价函数

4.反向传播

对每一个变量求导, 得到权重和偏置矩阵的导数

5.更新参数

利用梯度下降算法对权重和偏置矩阵进行更新

6.回到第二步迭代5000次

7.模型评估

import numpy as npfrom sklearn.preprocessing import OneHotEncoderfrom sklearn import datasets'''构建一个具有1个隐藏层的神经网络,隐层的大小为10'''# 1.初始化参数def initialize_parameters(n_x, n_h, n_y):np.random.seed(2)# 权重和偏置矩阵w1 = np.random.randn(n_h, n_x) * 0.01b1 = np.zeros(shape=(n_h, 1))w2 = np.random.randn(n_y, n_h) * 0.01b2 = np.zeros(shape=(n_y, 1))# 存储参数parameters = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}return parameters# 2.前向传播def forward_propagation(X, parameters):w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']# 通过前向传播来计算a2z1 = np.dot(w1, X) + b1# 这个地方需注意矩阵加法:虽然(w1*X)和b1的维度不同,但可以相加a1 = np.tanh(z1) # 使用tanh作为第一层的激活函数z2 = np.dot(w2, a1) + b2a2 = 1 / (1 + np.exp(-z2)) # 使用sigmoid作为第二层的激活函数# 通过字典存储参数cache = {'z1': z1, 'a1': a1, 'z2': z2, 'a2': a2}return a2, cache# 3.计算代价函数def compute_cost(a2, Y):m = Y.shape[1]#总的样本数# 采用交叉熵作为代价函数logprobs = np.multiply(np.log(a2), Y) + np.multiply((1 - Y), np.log(1 - a2))cost = - np.sum(logprobs) / mreturn cost# 4.反向传播(计算代价函数的导数)def backward_propagation(parameters, cache, X, Y):m = Y.shape[1]w2 = parameters['w2']a1 = cache['a1']a2 = cache['a2']# 反向传播,计算dw1、db1、dw2、db2dz2 = a2 - Ydw2 = (1 / m) * np.dot(dz2, a1.T)db2 = (1 / m) * np.sum(dz2, axis=1, keepdims=True)dz1 = np.multiply(np.dot(w2.T, dz2), 1 - np.power(a1, 2))dw1 = (1 / m) * np.dot(dz1, X.T)db1 = (1 / m) * np.sum(dz1, axis=1, keepdims=True)grads = {'dw1': dw1, 'db1': db1, 'dw2': dw2, 'db2': db2}return grads# 5.更新参数def update_parameters(parameters, grads, learning_rate=0.4):w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']dw1 = grads['dw1']db1 = grads['db1']dw2 = grads['dw2']db2 = grads['db2']# 更新参数w1 = w1 - dw1 * learning_rateb1 = b1 - db1 * learning_ratew2 = w2 - dw2 * learning_rateb2 = b2 - db2 * learning_rateparameters = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}return parameters# 建立神经网络def bpnn(X, Y, n_h, n_input, n_output, num_iterations=5000, print_cost=False):np.random.seed(3)n_x = n_input # 输入层节点数n_y = n_output# 输出层节点数# 1.初始化参数parameters = initialize_parameters(n_x, n_h, n_y)# 梯度下降循环for i in range(0, num_iterations):# 2.前向传播a2, cache = forward_propagation(X, parameters)# 3.计算代价函数cost = compute_cost(a2, Y)# 4.反向传播grads = backward_propagation(parameters, cache, X, Y)# 5.更新参数parameters = update_parameters(parameters, grads)# 每500次迭代,输出一次代价函数if print_cost and i % 500 == 0:print('迭代第%i次,代价函数为:%f' % (i, cost))return parameters# 6.模型评估def judge(parameters, x_test, y_test):w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']z1 = np.dot(w1, x_test) + b1a1 = np.tanh(z1)z2 = np.dot(w2, a1) + b2a2 = 1 / (1 + np.exp(-z2))# 结果的维度n_rows = a2.shape[0]n_cols = a2.shape[1]# 预测值结果存储output = np.empty(shape=(n_rows, n_cols), dtype=int)for i in range(n_rows):for j in range(n_cols):if a2[i][j] > 0.5:output[i][j] = 1else:output[i][j] = 0# 将one-hot编码反转为标签output = encoder.inverse_transform(output.T)output = output.reshape(1, output.shape[0])output = output.flatten()print('预测结果:', output)print('真实结果:', y_test)count = 0for k in range(0, n_cols):if output[k] == y_test[k]:count = count + 1else:print('错误分类样本序号:', k + 1)accuracy = count / int(a2.shape[1]) * 100print('BP神经网络准确率:%.2f%%' % accuracy)return output#随机抽取80%的训练集和20%的测试集def divideData():completeData = np.c_[iris.data, iris.target.T]np.random.shuffle(completeData)trainData = completeData[range(int(length * 0.8)), :]testData = completeData[range(int(length * 0.8), length), :]return [trainData, testData]if __name__ == "__main__":#获取iris数据集iris = datasets.load_iris()#随机获取80%训练集和20%测试集length = len(iris.target)[trainData, testData] = divideData()X=trainData[:,0:4].TY=trainData[:,-1].T# 将标签转换为one-hot编码,便于计算encoder = OneHotEncoder()Y = encoder.fit_transform(Y.reshape(Y.shape[0], 1))Y = Y.toarray().TY = Y.astype('uint8')# 输入4个节点,隐层10个节点,输出3个节点,迭代5000次parameters = bpnn(X, Y, n_h=10, n_input=4, n_output=3, num_iterations=5000, print_cost=True)x_test=testData[:,0:4].Ty_test=testData[:,-1].Tresult = judge(parameters, x_test, y_test)

SVM(支持向量机)

大致思路:

​ SVM学习的基本想法是求解能够正确划分训练数据集并且几何间隔最大的分离超平面。

该超平面要使得异类支持向量到超平面的距离最大, 即求最大间隔.

最大间隔式子是凸二次规划问题, 可以使用拉格朗日乘子法转化为对偶问题

计算对偶式的拉格朗日乘子可采用SMO算法

对于输入空间中的非线性分类问题,可以通过非线性变换将它转化为某个维特征空间中的线性分类问题,在高维特征空间中学习线性支持向量机。由于在线性支持向量机学习的对偶问题里,目标函数和分类决策函数都只涉及实例和实例之间的内积,所以不需要显式地指定非线性变换,而是用核函数替换当中的内积。

实现流程:

​ 使用skearn库svm.SVC函数训练分类器,并进行模型评估

from sklearn import svmfrom sklearn.model_selection import train_test_splitfrom sklearn.datasets import load_irisfrom sklearn.metrics import accuracy_score#获得iris数据集 iris = load_iris()#划分训练集(120)和测试集(30)X = iris.dataY = iris.targettrain_data, test_data, train_target, test_target = train_test_split(X, Y, random_state=1, train_size=0.8, test_size=0.2)#训练svm分类器#SVC的参数:# C: 惩罚参数# kernel: 核函数# gamma: 核函数参数# decision_function_shape: 策略,ovo: 一对一classifier = svm.SVC(C=2, kernel='rbf', gamma=10, decision_function_shape='ovo')classifier.fit(train_data, train_target.ravel()) # ravel函数在降维时默认是行序优先 #计算分类器的准确率 print("测试集准确率:", classifier.score(test_data, test_target))#直接调用accuracy_score计算准确率 tes_target = classifier.predict(test_data) # 测试集的预测结果print("测试集准确率:", accuracy_score(test_target, tes_target))

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。