[已解决] 菜鸟请教:多分类SVM程序问题出在哪里

[复制链接]
Adel 发表于 2021-1-25 17:44:00
10 财富积分
本帖最后由 Adel 于 2021-1-26 09:46 编辑

做一个心电多分类算法,用SVM,也是查很多论文用的方法。我按照自己的思路写了一个程序,训练出来再测试,第一类正确率是1,其他类都是0,肯定是出了问题。我现在没有解决思路。来请教下,恳请指点哈,谢谢了。程序如下:(开头网址是多分类的参考文章地址,不能发链接,网址加空格了)
  1. %% https:  //zhuanlan.zhihu.com  /p/31073350
复制代码
close all
clear,clc

class = {'A_a','F', 'J', 'L', 'N', 'R', 'V'};  % 总共分为7大类
class_num = length(class);  % 7类
SVMModels = cell(class_num,1);  %  一对多,需要7个SVMModel

data_path = 'D:\Program Files\MATLAB\R2015b\bin\main_codes\ECG process\classification\SVM_zhh\character_array_files\';  % 数据总目录
training_dataset = 'training_set1_charac_array';  % 训练集特征向量文件夹名称(7个文件夹中都相同)
testing_dataset = 'testing_set1_charac_array';  % 测试集特征向量文件夹名称(7个文件夹中都相同)
file_suffix = '*.txt';  % 数据文件后缀指定为.txt

%% 训练
for class_index=1:class_num  % 训练7次,要读完7个类的数据
    class_name = char( class(class_index) );  
    file_read_path = strcat(data_path, class_name,'\',training_dataset,'\');  % 拼接成完整路径下的文件过滤器
    file_filter = strcat(file_read_path, file_suffix);  % 拼接成完整路径下的文件过滤器
    file_struct = dir(file_filter);  % 获取所有文件信息
    file_struct_len = length(file_struct);  % 文件总个数

    for i=1:file_struct_len  % 读完文件夹下的所有文件
        filename_i = file_struct(i).name;
        file_read = strcat(file_read_path, filename_i);
        charac_array = textread(file_read, '%.4f', 'headerlines', 1);
        if( length(charac_array)==67 )  % 特征向量需要满足1*67
            for j = 1:class_num  % 训练7次,一次读取7次训练,得到7个向量机
                indx = strcmp(char( class(j) ),class_name); % Create binary classes for each classifier
                SVMModels{j} = fitcsvm(charac_array',indx,'ClassNames',[false true],...
                    'KernelFunction','rbf','BoxConstraint',1);
            end
        end
    end
end

%% 保存训练模型,元胞类型,保存为mat文件
save SVMModels.mat SVMModels

% %% 测试
% load SVMModels.mat
accuracy_rate = zeros(class_num,1);
for class_index=1:class_num
    class_name = char( class(class_index) );  
    file_read_path = strcat(data_path, class_name,'\',testing_dataset,'\');  % 拼接成完整路径下的文件过滤器
    file_filter = strcat(file_read_path, file_suffix);  % 拼接成完整路径下的文件过滤器
    file_struct = dir(file_filter);  % 获取所有文件信息
    file_struct_len = length(file_struct);  % 文件总个数
    Scores = zeros(file_struct_len,class_num);
    maxScore = zeros(file_struct_len,1);
    empty_file_cnt = 0;

    for i=1:file_struct_len
        filename_i = file_struct(i).name;
        file_read = strcat(file_read_path, filename_i);
        charac_array = textread(file_read, '%.4f', 'headerlines', 1);

        if( length(charac_array)==67 )
            for j = 1:class_num
                [~,score] = predict(SVMModels{j},charac_array');
                Scores(i,j) = score(:,2); % Second column contains positive-class scores
            end         
        else
            Scores(i,j) = 0;  % 若样本不对,则分类值为0
            empty_file_cnt = empty_file_cnt + 1;
        end
    end

    [~,maxScore] = max(Scores,[],2);
    maxScore = maxScore - class_index;
    accuracy_rate(class_index) = sum( (maxScore==0) )./(file_struct_len-empty_file_cnt);   
end

zhh = 1;

主要思路如下:
1、我有七类数据的特征向量,都算好了,都是1*67的向量,存为txt文件。7个类存7个文件夹,每个文件夹下,数据又分为训练数据和测试数据两个文件夹,training_set1_charac_array和testing_set1_charac_array。
2、参考开头网址的多分类程序,是一对多规则,7类需要7个分类器。
3、因为每次都要读取7个文件夹中训练或者测试文件夹下的文件,所以我每读一个文件夹,就一个文件一个文件地去训练,或者测试,比如训练时,对于第一类,我读取training_set1_charac_array文件夹下的第一个文件,提取特征向量,然后作为正类训练svm。然后读取第二个,...,直到第一类读取完,再读取第二类文件夹的training_set1_charac_array文件夹下第一个文件,训练,再读取第二个文件,...。测试也是一样的步骤。
4、训练数据文件和测试数据文件,有些可能不是1*67的向量,则不计。

我自己的一些思考,会不会有这些问题,或者说改进思路:

1、是不是我没有归一化特征向量;
2、是不是我一个一个的训练和测试这种机制不行?
3、是不是我还没有优化模型,或者说现在的参数设置不对?

最佳答案


lyqmath 发表于 2021-2-2 11:14:08
第三类数据过少,样本不均衡

11 条回复


Adel 发表于 2021-1-26 14:22:21
自己顶下哈  没人讨论下么

Adel 发表于 2021-1-26 15:44:54
本帖最后由 Adel 于 2021-1-26 15:48 编辑

自己顶下,看起来好像有点进展,也当记录吧 等老师来 哈哈
修改了之前说一个样本一个样本的读取训练,改为训练集一次性读完,这样,还可以进行标准化——我在别的程序里看到的方法,虽然我觉得一般好像是用归一化,貌似libsvm有对应函数——暂且不管这个问题了,总之这样做了之后,训练时,又加了交叉验证。测试时,依然是一个样本一个样本的读,一个样本的特征向量也先标准化。最终测试结果,和原来大不相同了。只有一类准确率很低,其他貌似都很高了accuracy_rate =

    0.8615
    0.8586
    0.3415
    0.9814
    0.9974
    0.9257
    0.9591


——当然,其实我还是不确定这些准确率是否是这样算的。。。
先把程序贴在这里:%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 将之前一个文件一个文件操作改为整体操作,先做好总体的训练集、测试集合,做好标准化(归一化?)

close all
clear,clc

class = {'A_a','F', 'J', 'L', 'N', 'R', 'V'};  % 总共分为7大类
class_num = length(class);  % 7类

data_path = 'D:\Program Files\MATLAB\R2015b\bin\main_codes\ECG process\classification\SVM_zhh\character_array_files\';  % 数据总目录
training_dataset = 'training_set1_charac_array';  % 训练集特征向量文件夹名称(7个文件夹中都相同)
testing_dataset = 'testing_set1_charac_array';  % 测试集特征向量文件夹名称(7个文件夹中都相同)
file_suffix = '*.txt';  % 数据文件后缀指定为.txt

%% 训练
samp_cnt = 0;
for class_index_train=1:class_num  % 训练7次,要读完7个类的数据
    class_index_train
    class_name = char( class(class_index_train) );  
    file_read_path = strcat(data_path, class_name,'\',training_dataset,'\');  % 拼接成完整路径下的文件过滤器
    file_filter = strcat(file_read_path, file_suffix);  % 拼接成完整路径下的文件过滤器
    file_struct = dir(file_filter);  % 获取所有文件信息
    file_struct_len = length(file_struct);  % 文件总个数

    for i=1:file_struct_len  % 读完文件夹下的所有文件
        filename_i = file_struct(i).name;
        file_read = strcat(file_read_path, filename_i);
        charac_array = textread(file_read, '%.4f', 'headerlines', 1);
        if( length(charac_array)==67 )  % 特征向量需要满足1*67
            samp_cnt = samp_cnt+1;
            charac_array_total(samp_cnt,:) = charac_array';
            indx_arry{samp_cnt} = class_name;
%             for j = 1:class_num  % 训练7次,一次读取7次训练,得到7个向量机
% %                 indx = strcmp(char( class(j) ),class_name); % Create binary classes for each classifier
% %                 SVMModels{j} = fitcsvm(charac_array',indx,'ClassNames',[false true],'Standardize',true,...
% %                     'KernelFunction','rbf','BoxConstraint',1);
% %                 SVMModels{j} = fitcsvm(charac_array',indx,'KernelFunction','rbf','BoxConstraint',1);               
% %                 SVMModels{j} = fitcsvm(charac_array',indx,'ClassNames',[false true],...
% %                     'KernelFunction','rbf','KernelScale','auto','BoxConstraint',1);
%             end
        end
    end
end

miu = mean(charac_array_total, 1);  % 1*67  
sig = std(charac_array_total, 0, 1);  % 1*67

charac_array_total = (charac_array_total - miu) ./ sig;  % 标准差再校正一次

indx_arry = categorical(indx_arry);
indx_arry_tmp = indx_arry;
index_num_arry = zeros(size(indx_arry));

for j = 1:class_num  % 训练7次,得到7个向量机
    class_name = char( class(j) );  
    indx_arry_tmp = setcats( indx_arry, class_name );

    index_num_arry(  :,isundefined( indx_arry_tmp )  ) = 0;
    index_num_arry(  :,~isundefined( indx_arry_tmp )  ) = 1;

%     SVMModels{j} = fitcsvm(charac_array_total,idx_m,'ClassNames',[false true],'Standardize',true,...
%         'KernelFunction','rbf','BoxConstraint',1);
%      SVMModels{j} = fitcsvm(charac_array_total,idx_m,'Standardize',true,...
%         'KernelFunction','rbf','BoxConstraint',1);

    t = templateSVM('Standardize',false,'KernelFunction','rbf',...
                'KernelScale','auto');
    SVMModels{j} = fitcecoc(charac_array_total,index_num_arry','Learners',t);

    CVSVMModels{j} = crossval( SVMModels{j} );
    classLoss(j) = kfoldLoss( CVSVMModels{j} );
    CompactSVMModels{j} = CVSVMModels{j}.Trained{1}; % Extract trained, compact classifier
end
%% 保存训练模型,元胞类型,保存为mat文件
% save SVMModels.mat SVMModels

% %% 测试
% load SVMModels.mat
accuracy_rate = zeros(class_num,1);
for class_index_test=1:class_num
    class_index_test
    class_name = char( class(class_index_test) );  
    file_read_path = strcat(data_path, class_name,'\',testing_dataset,'\');  % 拼接成完整路径下的文件过滤器
    file_filter = strcat(file_read_path, file_suffix);  % 拼接成完整路径下的文件过滤器
    file_struct = dir(file_filter);  % 获取所有文件信息
    file_struct_len = length(file_struct);  % 文件总个数
    Scores = zeros(file_struct_len,class_num);
    maxScore = zeros(file_struct_len,1);
    empty_file_cnt = 0;

    for i=1:file_struct_len
        filename_i = file_struct(i).name;
        file_read = strcat(file_read_path, filename_i);
        charac_array = textread(file_read, '%.4f', 'headerlines', 1);

        if( length(charac_array)==67 )
            charac_array = charac_array';  % 1*67
            charac_array = (charac_array - miu) ./ sig;  % 标准差再校正一次
            for j = 1:class_num
%                 [~,score] = predict(SVMModels{j},charac_array');
                 [label,score] = predict(CompactSVMModels{j},charac_array);
                Scores(i,j) = score(:,2); % Second column contains positive-class scores
            end         
        else
            Scores(i,j) = 0;  % 若样本不对,则分类值为0
            empty_file_cnt = empty_file_cnt + 1;
        end
    end

    [~,maxScore] = max(Scores,[],2);
    maxScore = maxScore - class_index_test;
    accuracy_rate(class_index_test) = sum( (maxScore==0) )./(file_struct_len-empty_file_cnt);   
end


zhh = 1;



















Adel 发表于 2021-1-26 15:52:14
需要数据的可以问我要哈 有点大,留邮箱我发 包括心电信号数据库、预处理程序、特征向量计算、保存程序等 都可以分享 希望有一起交流一起进步

lyqmath 发表于 2021-1-29 14:36:24
可以发一下数据,在训练前需要归一化处理

cvdeeplearning@qq.com

Adel 发表于 2021-1-29 17:09:23
lyqmath 发表于 2021-1-29 14:36
可以发一下数据,在训练前需要归一化处理

你好 好的哦 晚点发你哈
第二次程序我应该归一化了  我自己考虑第二次测试结果,第三类准确率非常低的原因是样本太少了,此类只有41个训练和测试样本 其他类都是几百到上千.

lyqmath 发表于 2021-1-30 11:12:46
Adel 发表于 2021-1-29 17:09
你好 好的哦 晚点发你哈
第二次程序我应该归一化了  我自己考虑第二次测试结果,第三类准确率非常低的原 ...

邮件是空的,没有附件数据

Adel 发表于 2021-2-1 09:39:20
lyqmath 发表于 2021-1-30 11:12
邮件是空的,没有附件数据

哦 不好意思 我公司发不了附件  今晚回去家里试下哈 实在抱歉

Adel 发表于 2021-2-1 22:13:30
lyqmath 发表于 2021-1-30 11:12
邮件是空的,没有附件数据

数据发给你了哈 你看下  感谢指教

lyqmath 发表于 2021-2-2 11:14:08
第三类数据过少,样本不均衡
回复此楼

Adel 发表于 2021-2-2 16:29:49
lyqmath 发表于 2021-2-2 11:14
第三类数据过少,样本不均衡

谢谢这么及时回复.这样子,那,算法是用对了么 我看一些svm的博客,提到参数优化,比如网格搜索法等,还有用粒子滤波算法的,我也想程序是不是可以在这些方面改进下,你有经验或者建议么
第二,关于svm我一直纠结核函数,我一直想,是不是一些问题自己构造核函数比那几种固定的核函数要好呢?我看一些例子也有自己写核函数的,有些看不懂,可以也请教下么?

lyqmath 发表于 2021-2-3 09:21:13
程序是用的多个二分类模型,可以直接用svm的多分类模型

核函数需要多试试

另外就是直接用cnn效果更好
您需要登录后才可以回帖 登录 | 注册

本版积分规则

相关帖子
热门教程
站长推荐
快速回复 返回顶部 返回列表