基于留一法的快速KNN代码

89 篇文章 27 订阅
18 篇文章 25 订阅

本文共885个字,预计阅读时间需要3分钟。

留一法交叉验证(LOOCV)

留一法即Leave-One-Out Cross Validation。这种方法比较简单易懂,就是把一个大的数据集分为k个小数据集,其中k-1个作为训练集,剩下的一个作为测试集,然后选择下一个作为测试集,剩下的k-1个作为训练集,以此类推。其主要目的是为了防止过拟合,评估模型的泛化能力。计算时间较长。

适用场景

数据集少,如果像正常一样划分训练集和验证集进行训练,那么可以用于训练的数据本来就少,还被划分出去一部分,这样可以用来训练的数据就更少了。loocv可以充分的利用数据。

KNN算法简介与MATLAB实现:https://www.omegaxyz.com/2018/03/24/knn_matlab/

快速留一法KNN

因为LOOCV需要划分N次,产生N批数据,所以在一轮训练中,要训练出N个模型,这样训练时间就大大增加。为了解决这样的问题,根据留一法的特性,我们可以提前计算出不同样本之间的距离(或者距离的中间值),存储起来。使用LOOCV时直接从索引中取出即可。下面的代码以特征选择为Demo,验证快速KNN留一法。

其中FSKNN1是普通KNN,FSKNN2是快速KNN

主函数main.m

clc
[train_F,train_L,test_F,test_L] = divide_dlbcl();
dim = size(train_F,2);
individual = rand(1,dim);
global choice
choice = 0.5;
global knnIndex
[knnIndex] = preKNN(individual,train_F);
for i = 1:100
    [error,fs] = FSKNN1(individual,train_F,train_L);
    [error2,fs2] = FSKNN2(individual,train_F,train_L);
end

数据集划分divide_dlbcl.m

function [train_F,train_L,test_F,test_L] = divide_dlbcl()
load DLBCL.mat;
dataMat=ins;
len=size(dataMat,1);
%归一化
 
maxV = max(dataMat);
minV = min(dataMat);
range = maxV-minV;
newdataMat = (dataMat-repmat(minV,[len,1]))./(repmat(range,[len,1]));
 
Indices   =  crossvalind('Kfold', length(lab), 10);
site = find(Indices==1|Indices==2|Indices==3);
test_F = newdataMat(site,:);
test_L = lab(site);
site2 = find(Indices~=1&Indices~=2&Indices~=3);
train_F = newdataMat(site2,:);
train_L =lab(site2);
end

简单KNN

FSKNN1.m

function [error,fs] = FSKNN1(x,train_F,train_L)
global choice
inmodel = x>choice;%%%%%设定恰当的阈值选择特征
 
 
k=1;
train_f=train_F(:,inmodel);
train_length = size(train_F,1);
flag = logical(ones(train_length,1));
 
 
error=0;
for j=1:train_length
    flag(j) = 0;
    CtrainF = train_f(flag,:);
    CtrainL = train_L(flag);
    CtestF = train_f(~flag,:);
    CtestL = train_L(~flag);
    classifyresult= KNN1(CtestF,CtrainF,CtrainL,k);
    if (CtestL~=classifyresult)
        error=error+1;
    end
 
    flag(j) = 1;
end
  error=error/train_length;
  fs = sum(inmodel);
 
end

KNN1.m

function relustLabel = KNN1(inx,data,labels,k)
%% 
 
%   inx 为 输入测试数据,data为样本数据,labels为样本标签 k值自定1~3
 
%%
 
 
[datarow , datacol] = size(data);
diffMat = repmat(inx,[datarow,1]) - data ;
distanceMat = sqrt(sum(diffMat.^2,2));
[B , IX] = sort(distanceMat,'ascend');
len = min(k,length(B));
relustLabel = mode(labels(IX(1:len)));
 
end

快速KNN

preKNN.m

function [knnIndex] = preKNN(x,train_F)
    inmodel = x > 0;
    train_f=train_F(:,inmodel);
    train_length = size(train_F,1);
    flag = logical(ones(train_length,1));
    knnIndex = cell(train_length,1);
    for j=1:train_length
        flag(j) = 0;
        CtrainF = train_f(flag,:);
        CtestF = train_f(~flag,:);
        [datarow , ~] = size(CtrainF);
        diffMat = repmat(CtestF,[datarow,1]) - CtrainF ;
        diffMat = diffMat.^2;
        knnIndex{j,1} = diffMat;
        flag(j) = 1;
    end
end

FSKNN2.m

function [error,fs] = FSKNN2(x,train_F,train_L)
global choice
inmodel = x>choice;%%%%%设定恰当的阈值选择特征
global knnIndex
k=1;
train_length = size(train_F,1);
flag = logical(ones(train_length,1));
 
 
error=0;
for j=1:train_length
    flag(j) = 0;
    CtrainL = train_L(flag);
    CtestL = train_L(~flag);
    classifyresult= KNN2(CtrainL,k,knnIndex{j}(:,inmodel));
    if(CtestL~=classifyresult)
        error=error+1;
    end
    flag(j) = 1;
end
  error=error/train_length;
  fs = sum(inmodel);
end

KNN2.m

function relustLabel = KNN2(labels,k,diffMat)
 
distanceMat = sqrt(sum(diffMat,2));
[B , IX] = sort(distanceMat,'ascend');
len = min(k,length(B));
relustLabel = mode(labels(IX(1:len)));
 
end

数据集:https://github.com/xyjigsaw/Dataset 下载DLBCL.mat即可。

结果

在这里插入图片描述
可以看到FSKNN2+preKNN的时间比FSKNN1要少很多。

更多内容访问 omegaxyz.com
网站所有代码采用Apache 2.0授权
网站文章采用知识共享许可协议BY-NC-SA4.0授权
© 2020 • OmegaXYZ-版权所有 转载请注明出处

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值