最近小白在啃西瓜书,一边啃一边啃一边实践,因此基于LDA顺手做了一个实例。数据来源是machinelearningmastery.com数据库中的钞票数据集,txt数据文本下载地址:http://t.cn/Rf8GdQo,有兴趣的小伙伴也可以用这个数据试试。
数据不多,一共有 1372 个观察值,4个输入变量和1个输出变量。变量名如下:
小波变换图像(连续)
小波偏斜变换图像(连续)
小波峰度变换图像(连续)
图像熵(连续)。
类(0 为真钞,1 为假钞)
很明显是一个四个变量,也就是四维的线性判别分析问题,与西瓜书上的二维多少有些不一样。最关键的问题就是用python.linalg.eig求完广义特征值后如何选择的问题,笔者在此程序中直接选择了最大广义特征值对应的特征向量作为w的解,依据是西瓜书上的原话“W的闭式解是d'个最大非零广义特征值对应的特征向量组成的矩阵,d'<=N-1”,其中N代表分类数,因为该数据是二分类数据,所以只需选择最大广义特征值对应的特征向量即可。至于二分类以上,有多个最大特征向量,该如何求解的问题,暂时还没有想明白,若有大佬知道可在底下留言告知。
制作这个实例,按照0.7的比例划分出训练集,剩下0.3作为测试集,因为只是一个练习实例,也没有设置验证集,只用最简单的准确率来判定这个LDA训练出的模型的准确性,结果尝试运行了十几次,每一次的准确率都在95%之上,还算不错,代码贴在下面。
import numpy as np import pandas as pd from scipy import linalg def split_data(data,split_radio): shuffle = np.random.permutation(data) test_size = int(len(data)*split_radio) training_data = shuffle[0:test_size] test_data = shuffle[test_size:] return training_data,test_data with open ("data_banknote_authentication.txt") as file: data = file.readlines() number_line = len(data) for i in range(number_line): data[i] = data[i].strip() data[i] = data[i].split(",") data = np.array(data) #提取data并转化为ndarray training_data,test_data = split_data(data,0.7) training_data_x1,training_data_x2 = [],[] for i in training_data: if i[4] == "0": training_data_x1.append(i[0:4]) else: training_data_x2.append(i[0:4]) training_data_x1 = np.array(training_data_x1) training_data_x2 = np.array(training_data_x2) #去除了labels且分好类的训练集 training_data_x1 = training_data_x1.astype(np.float32) training_data_x2 = training_data_x2.astype(np.float32) training_data = np.delete(training_data,-1,axis=1) training_data = training_data.astype(np.float32) test_data_labels = [] for i in test_data: test_data_labels.append(i[4]) test_data_labels = [int(i) for i in test_data_labels] test_data = np.delete(test_data,-1,axis=1)#去除了labels的测试集 test_data = test_data.astype(np.float32) #LDA开始 u = np.mean(training_data,axis=0) u_0 = np.mean(training_data_x1,axis=0) u_1 = np.mean(training_data_x2,axis=0) S_w = np.cov(training_data_x1, rowvar=False) + np.cov(training_data_x2, rowvar=False) S_b = len(training_data_x1)*np.dot((u_0-u).reshape(-1,1),(u_0-u).reshape(1,-1))+\ len(training_data_x2)*np.dot((u_1-u).reshape(-1,1),(u_1-u).reshape(1,-1)) eig = linalg.eig(S_b,S_w) r = eig[0] r = list(r) r_enumerate = enumerate(r) r_max = max(r) order = [] for i in r_enumerate: if i[1] == r_max: order.append(i[0]) w = eig[order[0]+1] w1 = w[:,0] m = 0 for i in training_data_x1: m += np.dot(w1,i) x0 = m/len(training_data_x1) n = 0 for i in training_data_x2: n += np.dot(w1,i) x1 = n/len(training_data_x2) #开始测试集测试,计算准确率 right = 0 test_labels = [] for i in test_data: test_i = np.dot(w1,i) distance_0 = abs(test_i-x0) distance_1 = abs(test_i-x1) if distance_0 >= distance_1: test_labels.append(1) else: test_labels.append(0) for i in range(len(test_data_labels)): if test_data_labels[i] == test_labels[i]: right += 1 accuracy = right/len(test_labels) print(accuracy)