EDA365电子论坛网
标题:
基于留一法的快速KNN代码
[打印本页]
作者:
ubeautqq
时间:
2021-7-12 14:14
标题:
基于留一法的快速KNN代码
留一法交叉验证(LOOCV)
' B8 e& F0 U7 g3 H( Q7 p# Y
留一法即Leave-One-Out Cross Validation。这种方法比较简单易懂,就是把一个大的数据集分为k个小数据集,其中k-1个作为训练集,剩下的一个作为测试集,然后选择下一个作为测试集,剩下的k-1个作为训练集,以此类推。其主要目的是为了防止过拟合,评估模型的泛化能力。计算时间较长。
) z4 P s9 m6 H8 E- |
( |$ k$ D4 T2 I7 N
适用场景:
j+ ]1 l% x( C' F
/ a7 m0 {/ A0 I; S- s+ [& D) s
数据集少,如果像正常一样划分训练集和验证集进行训练,那么可以用于训练的数据本来就少,还被划分出去一部分,这样可以用来训练的数据就更少了。loocv可以充分的利用数据。
9 H3 K& I6 \: |3 f g
6 r% \5 D9 b9 s
, u2 W2 k% B+ M4 T
快速留一法KNN
- g5 v: A' Q2 U" D; o8 J* M' b
3 u( m3 F$ l" P
因为LOOCV需要划分N次,产生N批数据,所以在一轮训练中,要训练出N个模型,这样训练时间就大大增加。为了解决这样的问题,根据留一法的特性,我们可以提前计算出不同样本之间的距离(或者距离的中间值),存储起来。使用LOOCV时直接从索引中取出即可。下面的代码以特征选择为Demo,验证快速KNN留一法。
+ E# V2 ?1 x/ r2 U6 |, }# d+ _
4 `! o# b; B( U. r/ G& N
其中FSKNN1是普通KNN,FSKNN2是快速KNN
5 z2 ~) x& U* t, [
# G4 T8 i/ j2 r, P
主函数main.m
& f$ T- N: `7 Q
. ?' l( K" M1 b- L I, ?# k
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
! N) c( }. A' Z; I0 F9 c( o
$ J2 o+ e( W7 b. F3 @
- E( y6 a8 Q. R# j! e9 n
数据集划分divide_dlbcl.m
2 r" V- S9 H% D
7 o( x/ t7 g% ]' \; b
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
% Q3 N* J0 p2 j$ ^, C M
: v4 R' w$ n' U
$ p3 P; W! E5 R7 |6 O! \+ c
简单KNN
0 k4 Y- b% ^0 \
% H3 g4 Z& o9 [; B5 D& n/ w2 b) O
FSKNN1.m
0 N( H* T$ L! v
6 {5 ]. g5 C4 s2 v. _+ I
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
K" U, j/ s0 M* I" j9 {
K* m: W, J0 _5 z1 w
2 f6 L+ t9 q3 K# O
KNN1.m
. g. T' l9 V6 O; @: N. G, H
a: T1 C- Z' N0 @1 m' Z% q
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
' Q. ]1 r: k/ a* a3 c
" X: r& A5 c: U) c8 e
8 c* V, }$ j0 B9 U7 K7 T2 o) j% T9 l) l9 o
快速KNN
. ]: `; y, w, k: } Q' C! v
9 ?/ G4 r; N4 }. q# t
preKNN.m
: N. T$ E( y b! v4 J" V; u# {# d8 I
! T: l2 @$ j) e3 r$ D; o8 l6 l
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
6 \/ B% V7 V9 i. a% ]' j
% w0 L0 _* m) t! k2 N6 R! }
: c; }. O. J8 M2 C
FSKNN2.m
* O" f6 p6 o' K5 C5 ]& J+ z- ^- U
8 q' n5 s+ e/ U: l. Y
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
* o) R! P! N/ |/ C
8 t! N% H$ a+ `8 z3 m) ]
7 P5 W N0 u3 T( Q
KNN2.m
- h9 s% o2 ]4 M# A% d/ {% E
6 ^$ m7 S' n+ A4 @ q( b! a/ f& I
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
* L& d2 l: U) m7 q" F
8 ^, C$ h o% Z; a( o* r; L
# g& L' D: M* }8 s/ K6 P
结果
2 t2 r9 B- o1 K: S9 D5 d
4 S0 y3 F8 ]+ n) _% W
8.png
(55.34 KB, 下载次数: 5)
下载附件
保存到相册
2021-7-12 14:08 上传
2 P/ W2 |$ b/ h5 M
: q# T3 \! F! q
可以看到FSKNN2+preKNN的时间比FSKNN1要少很多。
, j. ?4 i# }* e
作者:
ExxNEN
时间:
2021-7-12 15:08
基于留一法的快速KNN代码
作者:
smileqq
时间:
2021-7-12 15:10
基于留一法的快速KNN代码
作者:
SsaaM7
时间:
2021-7-12 15:10
基于留一法的快速KNN代码
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2