1. 问题描述
帕金森数据集分类
帕金森病是一种慢性进展性疾病,具有高度异质性,不同病人疾病进展的速度不同。帕金森病平均发病年龄为60岁左右,且患病率随着年龄的增长而升高。近年来,全球的帕金森患者大约有600 万,其中我国的帕金森病患者约占世界帕金森病患者人数的50%。帕金森病最主要的病理改变是中脑黑质多巴胺能神经元的变性死亡,由此而引起纹状体DA含量显著性减少而致病。
当前,对于帕金森病的发病机理尚未完全了解,因此只能采取控制病情的治疗方式来延缓帕金森疾病的持续恶化,却无法从根本上治愈疾病。导致这一病理改变的确切病因目前仍不清楚,遗传因素、环境因素、年龄老化、氧化应激等均可能参与PD多巴胺能神经元的变性死亡过程。对于该病的诊断较多地依赖于临床经验,这种诊断方法存在一定的误诊率。基于语音障碍的帕金森病诊断不仅成本低,而且能够对患者实行远程诊断,有利于提高帕金森病诊断效果。目前的相关研究主要涉及到语音特征学习、分类器设计等环节。
2. 分类算法
为了针对帕金森数据集实现准确的分类,本文通过MATLAB软件计算平台对传统的几种分类算法进行了研究对比,包括:SVM分类,随机森林分类,K近邻分类,BP神经网络分类。
2.1 SVM分类
支持向量机(SVM)是使用最为广泛的分类器之一。目前,SVM在数据分类任务上取得了很好的效果,尤其是引入了核方法的SVM。其中,合理的核函数选取将有效地改善分类器性能,常用的核函数主要有Linear、Sigmoid、RBF、GussianRBF等。
为了用线性学习机器学习一个非线性关系,需要选择一个非线性特征集,并且将数据写成新的表达形式。建立非线性学习器分为两步:首先使用一个非线性映射将数据变换到一个特征空间,在特征空间中,维数足够大,使得原空间数据的像具有线性关系;然后在这个特征空间使用线性学习器进行分类。
2.2 随机森林
随机森林(Random Forest)是Bagging的一个扩展变体。其在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机属性选择,即:传统决策树在选择划分属性时是在当前结点的属性集合中(假设共有d个结点)基于信息纯度准则等选择一个最优属性,而在随机森林中,对基决策树的每个结点,先从该结点的属性集合中随机选择一个包含k个属性的子集,再对该子集进行基于信息准则的划分属性选择;这里的k控制了随机性的引入程度;若令k=d,则基决策树的构建与传统决策树相同;若令k=1,则每次的属性选择纯属随机,与信息准则无关;一般情况下,推荐k=log2d。
随机森林对Bagging只做了小小的改动,但是与Bagging中基学习器的“多样性”仅通过样本扰动(即改变采样规则)不同,随机森林中基学习器的多样性不仅来自样本扰动,还来自属性扰动,这就使得最终集成的泛化性能可通过个体学习器之间差异度的增加而进一步提升;
随机森林的收敛性与Bagging类似,但随机森林在基学习器数量较为可观时性能会明显提升,即随着基学习器数量的增加,随机森林会收敛到更低的泛化误差。
2.3 K近邻分类
K近邻算法(K-NN)算法是一种简单但也很常用的分类算法,它也可以应用于回归计算。K-NN是无参数学习,这意味着它不会对底层数据的分布做出任何假设。它是基于实例,即该算法没有显式地学习模型。相反,它选择的是记忆训练实例,并在一个有监督的学习环境中使用。KNN算法的实现过程主要包括距离计算方式的选择、k值得选取以及分类的决策规则三部分。
2.3.1 距离计算方式的选择
选择一种距离计算方式,计算测试数据与各个训练数据之间的距离。距离计算方式一般选择欧氏距离或曼哈顿距离。
2.3.2 k值得选取
在计算测试数据与各个训练数据之间的距离之后,首先按照距离递增次序进行排序,然后选取距离最小的k个点。
一般会先选择较小的k值,然后进行交叉验证选取最优的k值。k值较小时,整体模型会变得复杂,且对近邻的训练数据点较为敏感,容易出现过拟合。k值较大时,模型则会趋于简单,此时较远的训练数据点也会起到预测作用,容易出现欠拟合。
2.3.3 k值得选取
常用的分类决策规则是取k个近邻训练数据中类别出现次数最多者作为输入新实例的类别。即首先确定前k个点所在类别的出现频率,对于离散分类,返回前k个点出现频率最多的类别作预测分类;对于回归则返回前k个点的加权值作为预测值。
3.实验与结果
3.1 实验环境
本设计使用MATLAB软件进行算法仿真。
3.2 实验流程
第一步:将数据分成训练集、测试集;
在研究对比不同算法的泛化性能时,我们用测试集的判别效果来估计模型中实际使用时的泛化能力,而把训练数据另外划分为训练集和验证集,基于验证集上的性能来进行模型选择和调参。
根据实验要求,实验结果除样本准确率(195个样本的准确率)外还要有人的准确率(32个人的准确率),因此将32个受试者每个受试者6个或7个样本序号提取保存;将2-23总共22种的受试者的特征及第24列是否犯病的标签数据保存,等待下一步使用。实验局部数据如图1所示。
第二步:使用训练集训练多个分类器,如二分类支持向量机(SVM)、K近邻分类、随机森林分类及BP神经网络等;
第三步:用验证集对训练得到的分类器进行测试,得到验证集的预测输出;
训练集用于创建分类器,验证集用于优化或调整分类器的参数,而测试集用于计算优化的分类器的误差率。
第四步:分类器构造完成后,使用测试集对所选分类器进行测试,得到测试集的预测输出,并计算其分类准确率。
3.3 实验结果和分析
3.3.1 backer数据集
(1)SVM分类结果(这里截取10次的分类准确率结果)
最优一次准确率:72.6%
10次平均准确率:68.99%
(2)随机森林分类结果
最优一次准确率:74.5%
10次平均准确率:68.37%
(3)K近邻分类结果
最优一次准确率:68.27%
10次平均准确率:63.85%
(4)BP神经网络分类结果
最优一次准确率:66.83%
10次平均准确率:64.28%
由以上的分类准确率结果可知:对于第一个数据集,SVM分类算法和随机森林的分类算法要优于K近邻分类和BP神经网络分类。并且根据各算法的运行时间来说,BP神经网络的运行时间最长,其他三种算法的运行时间差别不大。因此,需要设计更优的BP神经网络才能达到更好的分类效果。
3.3.2 max litter数据集
(1)SVM分类结果(这里截取10次的分类准确率结果)
最优一次准确率:97.44%
10次平均准确率:88.46%
(2)随机森林分类结果
最优一次准确率:97.44%
10次平均准确率:90.26%
(3)K近邻分类结果
最优一次准确率:89.74%
10次平均准确率:82.82%
(4)BP神经网络分类结果
最优一次准确率:89.74%
10次平均准确率:82.05%
由以上的分类准确率结果可知:对于第二个数据集,随机森林分类的准确率最高,平均能达到90%,其次为SVM分类器,K近邻和BP神经网络分类算法的准确率最差。
总结
本文实验采用基于分类器选择的帕金森语音分类,通过使用训练集创建分类器,测试集用于计算优化的分类器的误差率。然而,有可能用于训练的数据不具代表性。比如分类器将数据分成两个类,而我们划分的测试集恰巧只包含了一个类的数据,而测试集包含了另一个类的数据,显然,这种情况下,一方面分类器有可能会过度拟合,另一方面,对于另一个类由于缺少训练而无法判断。对于这种问题,最简单的方法就是,随机划分训练集和测试集,并进行多次测试。最后将每次迭代的误差率求平均以得到最终的误差率。综合以上两个数据集我们可以得出,针对backer数据集,SVM的平均识别率为69%左右,最高能达到74%;而对于max litter 数据集,随机森林的平均识别率为90%左右,最高能达到97.44%。
附录(关键程序代码)
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 = [data0 label_0];%加标签后的健康数据
data1 = [data1 label_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;