题目来源于2020年中国研究生数学建模竞赛C题——面向康复工程的脑电信号分析和判别模型。
2 涉及内容在本次实战的数据分析过程中,涉及以下技术内容:
(1)分类模型的训练与评价
(2)数据标准化
(3)带通滤波
(4)重采样(数据增强)
(5)模型在新数据集上预测
我先将字符矩阵的标识符、行/列的标识符存在两个矩阵里,并保存为 C_HWB_2020.mat,便于后续程序随时调用。
矩阵BiaoShiFu_all如下,
矩阵HangLie_BSF_all如下,
LJ_train_data='附件1-P300脑机接口数据S1S1_train_data.xlsx'; LJ_train_event='附件1-P300脑机接口数据S1S1_train_event.xlsx'; sheets_1=sheetnames(LJ_train_data); sheets_2=sheetnames(LJ_train_event);3.3 数据标准化
有些算法对标准化敏感,有些则不敏感。但因为后边我们要对未知字符进行预测,这些字符中有些字符在训练集中未出现过,为了使训练模型在新数据有较好的预测性能,我采用了数据标准化。而且这种标准化是将12个sheet的数据放到一块组成matrix1_all,然后对其每一列进行标准化,并保留标准化的输出物ps,用ps来对训练集(测试集)数据以及新数据进行标准化,这样便统一了标准化的标准。
matrix1_all=[]; for i=1:length(sheets_1) table_tem1=readtable(LJ_train_data,'Sheet',sheets_1(i)); matrix_1=table_tem1{:,:}; matrix1_all=[matrix1_all;matrix_1]; end3.4 带通滤波
因为P300信号的频率在0.1~20Hz之间,此处我编写了带通滤波函数,滤去该频率区间外的波进行带通滤波,
for k=1:size(matrix1_all,2) matrix1_all(:,k)=bandfilter(matrix1_all(:,k)); end %标准化 [~,ps]=mapstd(matrix1_all'); matrix1_all=[];
滤波函数如下,
function y=bandfilter(x) filorder = 20; %滤波器阶数 cutf1 =0.001; %滤波频率1 cutf2 = 23; %滤波频率2 samplerate=250; %采样频率 d = designfilt('bandpassfir','FilterOrder',filorder, ... 'CutoffFrequency1',cutf1,'CutoffFrequency2',cutf2, ... 'SampleRate',samplerate); y = filtfilt(d,x); end3.5 取出训练集数据
P300信号位于刺激发生后的600ms内,因为采样频率是250Hz,所以P300信号也就是位于150个采样点内。注意每个训练样本是150×20的矩阵,需要将其拉成一行,
warning('off'); Xdata =[]; Ydata=[]; for i=1:length(sheets_1) table_tem1=readtable(LJ_train_data,'Sheet',sheets_1(i)); table_tem2=readtable(LJ_train_event,'Sheet',sheets_2(i)); matrix_1=table_tem1{:,:}; matrix_2=table_tem2{:,:}; % %进行带通滤波 for k=1:size(matrix_1,2) matrix_1(:,k)=bandfilter(matrix_1(:,k)); end % %标准化 bz=mapstd('apply',matrix_1',ps); matrix_1=bz'; for j=1:length(sel_index) start_index=matrix_2(sel_index(j),2); sel_data=matrix_1(start_index:(start_index+150),:); %拉成一行 Xdata = [Xdata;reshape(sel_data,1,[])]; hangxie=HangLie_BSF_all(BiaoShiFu_all==matrix_2(1,1),:); Ydata=[Ydata;categorical(ismember(matrix_2(sel_index(j),1),hangxie))]; end end3.6 训练集数据增强
因为正样本(包含P300信号)只有120个,而负样本有600个,正负样本不均衡,需要对正样本进行重采样,使其数据和负样本相当。此处我采用随机抽取两个正样本数据求平均值的方式,来增加正样本数量。这样既使得正负样本比例达到平衡,又增加了新的正样本数据,相对于通过重复采样来增加正样本的方法来说, 这种方法对后续识别新的字符更有利。
d_Ydata=double(Ydata); hang_2=find(d_Ydata==2); Xdata_chong =Xdata; Ydata_chong =Ydata; rng(1); for k=1:480 r = randi([1,length(hang_2)],2,1); Xdata_chong =[Xdata_chong;mean(Xdata(hang_2(r),:))]; Ydata_chong =[Ydata_chong;Ydata(hang_2(r(1)),:)]; end3.7 划分训练集和测试集
直接参考help文档里关于划分训练集和测试集的代码,
%合并特征数据与目标数据 Table_data_S1=array2table(Xdata_chong); Table_data_S1.Ydata=Ydata_chong; %划分训练集和测试集 rng(1); % For reproducibility of the data partition c = cvpartition(Ydata_chong,'Holdout',0.2); trainingIdx = training(c); % Training set indices S1Train = Table_data_S1(trainingIdx,:); testIdx = test(c); % Test set indices S1Test = Table_data_S1(testIdx,:);3.8 训练模型选择
通过分类学习Classification Learner app,对S1Train进行分类,比对下各种分类器的效果,见下图,
发现线性模型、SVM、KNN和集成模型精确度超多80%,接下来我们在S1数据上使用fitcauto函数对这四种分别进行训练,来详细比对各学习器的性能,
线性模型训练结果如下,
%训练分类模型 options = struct('UseParallel',true); Mdl = fitcauto(S1Train,'Ydata','HyperparameterOptimizationOptions',options,"Learners",'linear'); %评估分类模型性能 testAccuracy = 1 - loss(Mdl,S1Test,'Ydata') confusionchart(S1Test.Ydata,predict(Mdl,S1Test))
SVM训练结果如下,
%训练分类模型 options = struct('UseParallel',true); Mdl = fitcauto(S1Train,'Ydata','HyperparameterOptimizationOptions',options,"Learners",'svm'); %评估分类模型性能 testAccuracy = 1 - loss(Mdl,S1Test,'Ydata') confusionchart(S1Test.Ydata,predict(Mdl,S1Test))
KNN训练结果如下,
%训练分类模型 options = struct('UseParallel',true); Mdl = fitcauto(S1Train,'Ydata','HyperparameterOptimizationOptions',options,"Learners",'knn'); %评估分类模型性能 testAccuracy = 1 - loss(Mdl,S1Test,'Ydata') confusionchart(S1Test.Ydata,predict(Mdl,S1Test))
集成模型如下,
%训练分类模型 options = struct('UseParallel',true); Mdl = fitcauto(S1Train,'Ydata','HyperparameterOptimizationOptions',options,"Learners",'knn'); %评估分类模型性能 testAccuracy = 1 - loss(Mdl,S1Test,'Ydata') confusionchart(S1Test.Ydata,predict(Mdl,S1Test))
对比发现,SVM性能最好。
使用训练的SVM模型分别对S1~S5的新数据进行预测,
LJ_test_data='附件1-P300脑机接口数据S1S1_test_data.xlsx'; LJ_test_event='附件1-P300脑机接口数据S1S1_test_event.xlsx'; %取出每个文件里包含sheet的名称 sheets_1=sheetnames(LJ_test_data); sheets_2=sheetnames(LJ_test_event); %预测新字符 warning('off'); varname=Table_data_S1.Properties.VariableNames; cell_predict={};%存储每个被试的预测结果 for i=1:length(sheets_1) %取出每个被试的data和event数据 Xdata =[]; Y_BiaoQian=[]; table_tem1=readtable(LJ_test_data,'Sheet',sheets_1(i)); table_tem2=readtable(LJ_test_event,'Sheet',sheets_2(i)); matrix_1=table_tem1{:,:}; matrix_2=table_tem2{:,:}; % %进行带通滤波 for k=1:size(matrix_1,2) matrix_1(:,k)=bandfilter(matrix_1(:,k)); end % %按训练数据进行标准化 bz=mapstd('apply',matrix_1',ps); matrix_1=bz'; %取出每次闪烁对应的数据矩阵,并拉直成一行 for j=1:length(sel_index) start_index=matrix_2(sel_index(j),2); sel_data=matrix_1(start_index:(start_index+150),:); Xdata = [Xdata;reshape(sel_data,1,[])]; %Y_BiaoQian存储每次闪烁对应的行/列的标识符 Y_BiaoQian=[Y_BiaoQian;matrix_2(sel_index(j),1)]; end %求出预测结果为"true"对应的行/列的标识符 Table_predict=array2table(Xdata); Table_predict.Properties.VariableNames=varname(1:end-1); Y_predict=predict(Mdl,Table_predict); cell_predict{i}=Y_BiaoQian(Y_predict==categorical("true")); end
将每个被试对待识别字符的识别结果汇总(被试S2和S3只有前9个字符的数据),分别取行标识符里频率最高和列标识符里频率最高的标识符,由两者来确定待识别字符。
第一个待识别字符的行/列的标识符汇总频率表如下,最高频率的是3和7,对应字符“M”。
第二个待识别字符的行/列的标识符汇总频率表如下,最高频率的是1和12,对应字符“F”。
第三个待识别字符的行/列的标识符汇总频率表如下,最高频率的是6和7,对应字符“5”。
第四个待识别字符的行/列的标识符汇总频率表如下,最高频率的是5和10,对应字符“2”。
第五个待识别字符的行/列的标识符汇总频率表如下,最高频率的是2和9,对应字符“I”。
第六个待识别字符的行/列的标识符汇总频率表如下,最高频率的是4和8,对应字符“T”。
第七个待识别字符的行/列的标识符汇总频率表如下,最高频率的是2和11,对应字符“K”。
第八个待识别字符的行/列的标识符汇总频率表如下,最高频率的是4和12,对应字符“X”。
第九个待识别字符的行/列的标识符汇总频率表如下,最高频率的是1和7,对应字符“A”。
第十个待识别字符的行/列的标识符汇总频率表如下,最高频率的是6和12,对应字符“0”。
问题二:对于每个被试,可使用NCA算法求出151×20个特征的重要度,在使用reshape重新排成151×20的矩阵,按行求和,即得出每个通道的重要度得分。
问题三:使用一半数据作为有标签数据,另一半作为无标签数据,然后首先使用有标签数据训练一个模型SVMModel,使用如下函数去预测无标签数据,
[label,score] = predict(SVMModel,X)
每个无标签数据都有一个得分score(score为两列,正值所在的那一列即为预测的类别),我们把得分最高的那个无标签数据赋上类别标签,加入到训练集中,重新训练模型SVMModel,反复使用这种方法,就可以使用少量的有标签数据,逐渐给无标签数据打上标签。
问题四:最后一问是上述三问所得方法的实践题,不再赘述。
(1)训练的模型较好,但放到新数据上预测时变得很差,大概率是没使用训练集数据的标准化方法来标准化新数据。否则,那就是新数据和训练数据有结构性的重要差异,训练得到的经验无法推广到差异性太大的新数据上。
(2)滤波对提升模型的性能有一定的功效。
(3)数据增强时,生成新数据比重复采样的方法要好一些。