本文主要针对提供的两个帕金森数据。一个是Sacker帕金森数据集,共包含68名受试者,其中40名受试者数据本次实验的数据集,其中第1-20号为病患者,第21-40号为正常人。每位受试者有26组数据,每组数据有26维特征;另一个是max litter帕金森数据集,包含32名受试者,每名受试者都有多组数据,每组数据有22维特征。对两个数据集先训练模型再做分类,主要通过一下几种分类方法进行分类:支持向量机(SVM)分类,随机森林分类,K近邻分类(KNN),BP神经网络分类。
为了针对帕金森数据集实现准确的分类,本文通过matlab软件计算平台对传统的几种分类算法进行了研究对比,包括:SVM分类,随机森林分类,K近邻分类,BP神经网络分类。
1.SVM分类
支持向量机(SVM)是使用最为广泛的分类器之一。目前,SVM在数据分类任务上取得了很好的效果,尤其是引入了核方法的SVM。其中,合理的核函数选取将有效地改善分类器性能,常用的核函数主要有Lin-ear、Sigmoid、RBF、GussianRBF等。
为了用线性学习机器学习一个非线性关系,需要选择一个非线性特征集,并且将数据写成新的表达形式。建立非线性学习器分为两步:首先使用一个非线性映射将数据变换到一个特征空间,在特征空间中,维数足够大,使得原空间数据的像具有线性关系;然后在这个特征空间使用线性学习器进行分类。
2. 随机森林
随机森林(Random Forest)是Bagging的一个扩展变体。其在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机属性选择,即:传统决策树在选择划分属性时是在当前结点的属性集合中(假设共有d个结点)基于信息纯度准则等选择一个最优属性,而在随机森林中,对基决策树的每个结点,先从该结点的属性集合中随机选择一个包含k个属性的子集,再对该子集进行基于信息准则的划分属性选择;这里的k控制了随机性的引入程度;若令k=d,则基决策树的构建与传统决策树相同;若令k=1,则每次的属性选择纯属随机,与信息准则无关;一般情况下,推荐k=log2d。
随机森林对Bagging只做了小小的改动,但是与Bagging中基学习器的“多样性”仅通过样本扰动(即改变采样规则)不同,随机森林中基学习器的多样性不仅来自样本扰动,还来自属性扰动,这就使得最终集成的泛化性能可通过个体学习器之间差异度的增加而进一步提升;
随机森林的收敛性与Bagging类似,但随机森林在基学习器数量较为可观时性能会明显提升,即随着基学习器数量的增加,随机森林会收敛到更低的泛化误差。
3. K近邻分类
K近邻算法(K-NN)算法是一种简单但也很常用的分类算法,它也可以应用于回归计算。K-NN是无参数学习,这意味着它不会对底层数据的分布做出任何假设。它是基于实例,即该算法没有显式地学习模型。相反,它选择的是记忆训练实例,并在一个有监督的学习环境中使用。KNN算法的实现过程主要包括距离计算方式的选择、k值得选取以及分类的决策规则三部分。
距离计算方式的选择
选择一种距离计算方式,计算测试数据与各个训练数据之间的距离。距离计算方式一般选择欧氏距离或曼哈顿距离。
k值得选取
在计算测试数据与各个训练数据之间的距离之后,首先按照距离递增次序进行排序,然后选取距离最小的k个点。
一般会先选择较小的k值,然后进行交叉验证选取最优的k值。k值较小时,整体模型会变得复杂,且对近邻的训练数据点较为敏感,容易出现过拟合。k值较大时,模型则会趋于简单,此时较远的训练数据点也会起到预测作用,容易出现欠拟合。
分类的决策规则
常用的分类决策规则是取k个近邻训练数据中类别出现次数最多者作为输入新实例的类别。即首先确定前k个点所在类别的出现频率,对于离散分类,返回前k个点出现频率最多的类别作预测分类;对于回归则返回前k个点的加权值作为预测值。
附录(关键程序代码)
1、 SVM分类
clc;clear;
%数据集导入并处理
ParkinsonDataSet= xlsread('./数据.xlsx',1); %加载数据集1backer 2max litter
[M,N] =size(ParkinsonDataSet);
data_all =ParkinsonDataSet(:,2:end-1); %取特征
label_all =ParkinsonDataSet(:,end); %对应标签
T = 10; %次数
solution =zeros(T,1); %初始化准确率矩阵
for i = 1:T
%5折交叉法,随机取4/5作为训练集,1/5作为数据集
serial =randperm(M);
serial_1 =serial(1:M*4/5);
serial_2 =serial(M*4/5+1:end);
train_data =data_all(serial_1,:);
train_label =label_all(serial_1,:);
test_data =data_all(serial_2,:);
test_label =label_all(serial_2,:);
% SVM分类器训练
SVMStruct =fitcsvm(train_data,train_label,'Standardize',true,'KernelFunction','rbf',...
'KernelScale','auto');
% SVM分类器预测
predict_label = predict(SVMStruct, test_data);
%统计每次准确率
solution(i) =sum(predict_label==test_label)/M*5;
end
%平均准确率结果
right_rate = mean(solution);
solution'
2、 随机森林分类
clc;clear;
%数据集导入并处理
ParkinsonDataSet= xlsread('./数据.xlsx',1); %加载数据集1backer 2max litter
[M,N] =size(ParkinsonDataSet);
data_all =ParkinsonDataSet(:,2:end-1);%取特征
label_all =ParkinsonDataSet(:,end);%对应标签
solution =zeros(10,1);%初始化准确率矩阵
for i = 1:10
%5折交叉法,随机取4/5作为训练集,1/5作为数据集
serial =randperm(M);
serial_1 =serial(1:M*4/5);
serial_2 =serial(M*4/5+1:end);
train_data =data_all(serial_1,:);
train_label =label_all(serial_1,:);
test_data =data_all(serial_2,:);
test_label =label_all(serial_2,:);
% 随机森林分类器训练
nTree = 25;
B =TreeBagger(nTree,train_data,train_label);
% 随机森林分类器预测
predict_label =predict(B,test_data);
% 输出的字符型转为double型数组
predict_label1= zeros(size(test_label));
for j =1:length(predict_label1)
predict_label1(j) =str2num(predict_label{j,1});
end
%统计每次准确率
solution(i) =sum(predict_label1==test_label)/M*5;
end
%平均准确率结果
right_rate =mean(solution);
solution'
3、 KNN分类
clc;clear;
%数据集导入并处理
ParkinsonDataSet= xlsread('./数据.xlsx',1); %加载数据集1backer 2max litter
[M,N] =size(ParkinsonDataSet);
data_all =ParkinsonDataSet(:,2:end-1); %取特征
label_all =ParkinsonDataSet(:,end); %对应标签
solution =zeros(10,1); %初始化准确率矩阵
for i = 1:10
%5折交叉法,随机取4/5作为训练集,1/5作为数据集
serial =randperm(M);
serial_1 =serial(1:M*4/5);
serial_2 =serial(M*4/5+1:end);
train_data =data_all(serial_1,:);
train_label =label_all(serial_1,:);
test_data =data_all(serial_2,:);
test_label =label_all(serial_2,:);
% KNN分类器训练
mdl =fitcknn(train_data,train_label,'NumNeighbors',1);
% KNN分类器预测
predict_label =predict(mdl, test_data);
%统计每次准确率
solution(i) =sum(predict_label==test_label)/M*5;
end
%平均准确率结果
right_rate =mean(solution);
solution'
4、 BP神经网络分类
clc;clear;
%% 导入数据
tic;
data_all =xlsread('./数据.xlsx', 1); %加载数据集 1backer 2max litter
data_init =data_all(:,2:end);
data_data =data_init(:,1:end-1);
%% 数据归一化
Data_re =mapminmax(data_data,0,1);
data_data =Data_re;%归一化后的数据
data0 =data_data((data_init(:,end) == 0),:);%标签为0的为健康人
data1 =data_data((data_init(:,end) == 1),:);%标签为1的是帕金森
label_0 =zeros(size(data0,1),1);
label_1 =ones(size(data1,1),1);
data0 = [data0label_0];%加标签后的健康数据
data1 = [data1label_1];%加标签后的帕金森
%% 把数据打乱并分集
LOOP = 10;%循环次数
result = [];
K = 0.8;
for i = 1:LOOP
Health = data0(randperm(size(data0,1))',:);%打乱后的无病数据
Parkinson =data1(randperm(size(data1,1))',:);%打乱后的有病数据
train_data0 = Health(1:round(K *size(Health,1)),:);%取十分之六作为训练集
test_data0 = Health(round(K * size(Health,1))+ 1:size(Health,1),:);%取剩余十分之四作为测试集
train_data1 = Parkinson(1:round(K *size(Parkinson,1)),:);%取十分之六作为训练集
test_data1 = Parkinson(round(K *size(Parkinson,1)) + 1:size(Parkinson,1),:);%取十分之四作为测试集
train_all = [train_data0;train_data1];%所有训练数据
test_all = [test_data0;test_data1];%所有测试数据
train_data = train_all(:,1:end-1);%训练数据特征
train_label = train_all(:,end);%训练数据标签
test_data = test_all(:,1:end-1);%测试数据特征
test_label = test_all(:,end);%测试数据标签
%% BP网络训练
% %初始化网络结构
net=newff(train_data',train_label',15,{'tansig','purelin'});%隐含层节点数设置为20
%可以调节这个隐含层个数,准确率会有提高。
net.trainParam.epochs=200;%迭代次数
net.trainParam.lr=0.001;%学习率
net.trainParam.goal=0.001;%训练目标
%网络训练
net=train(net,train_data',train_label');
%net预测标签输出
%y=sim(net,x);net表示已训练好的网络,x表示输入数据,y表示网络预测数据。表示用训练好的网络预测输出函数
y=sim(net,test_data');
%根据网络输出获得预测类别的种类
y((y<0.5))=0;
y((y>0.5))=1;
result =[result;y];
end
%% 统计结果
[M,~] =size(test_data0);
[N,~] =size(test_label);
for i = 1:LOOP
TN(i) = length(find(result(i,1:M)==0));
FP(i) = length(find(result(i,1:M)==1));
FN(i) = length(find(result(i,M+1:N)==0));
TP(i) = length(find(result(i,M+1:N)==1));
end
CorrectRate=(TP+TN)./(TP+TN+FN+FP);% TP+TN为所有判断正确的,除以所有的就是准确度
Sensitivity=TP./(TP+FN); % 正常人中判断正确的除以所有正常人是灵敏度
Specificity=TN./(FP+TN); % 非正常人中判断正确的除以所有非正常人是特异度
CorrectRate_mean= mean(CorrectRate);
Sensitivity_mean= mean(Sensitivity);
Specificity_mean= mean(Specificity);
CorrectRate_std= std(CorrectRate);
Sensitivity_std= std(Sensitivity);
Specificity_std= std(Specificity);
fprintf('准确度平均值±标准差: %0.4f±%0.4f\n', CorrectRate_mean,CorrectRate_std);
fprintf('灵敏度平均值±标准差: %0.4f±%0.4f\n', Sensitivity_mean,Sensitivity_std);
fprintf('特异度平均值±标准差: %0.4f±%0.4f\n', Specificity_mean,Specificity_std);
toc;