1.数据划分(使用k折交叉验证)
rawrank=randperm(size(data4,1));%打乱顺序
rand_data=data4(rawrank,:);
cell_data=mat2cell(rand_data,[42 42 42 42 40]);%分为N份
for n=1:N
cell_data=circshift(cell_data,1);%移位一次
train_set=cell2mat(cell_data(1:N-1));%取N-1份做训练集
test_set=cell_data{N};%取N份做测试集
end
2.knn
我们把KNN算法写进名为knn的函数之中,便于我们训练
function out=knn(test_set,train_set,K)
[n ,~]=size(test_set);
[m,~]=size(train_set);
distance=ones(1,m);
out=ones(1,n);
for i=1:n
for j=1:m
%求欧式距离
% distance(j)=sqrt(sum((test_set(i,1:end-1)-train_set(j,1:end-1)).^2));
% 求曼哈顿距离
distance(j)=sum(abs(test_set(i,1:end-1)-train_set(j,1:end-1)));
% 求欧几里得距离
% distance(j)=sqrt(sum(abs(test_set(i,1:end-1)-train_set(j,1:end-1))));
% 求马氏距离
% distance(j)=sqrt((test_set(i,1:end-1)-train_set(j,1:end-1))'*cov([test_set(i,1:end-1)' train_set(j,1:end-1)'])*(test_set(i,1:end-1)-train_set(j,1:end-1)));
end
sum1=0;
sum2=0;
[d,index]=sort(distance,'ascend');
d1=d(1:K)./(sum(d(1:K)));
label=train_set(index(1:K),end);%按照距离大小排序
for k=1:K
if(label(k)==1)
sum1=sum1+d1(k);
else
sum2=sum2+d1(k);
end
end
if(sum2>sum1)
out(i)=2;
else
out(i)=1;
end
end
out=out';
end
knn最重要的是选择k和计算距离的算法
2.1欧几里得距离
2.2欧氏距离![1](https://i-blog.csdnimg.cn/blog_migrate/e1b67caad6bd1888bc1ae76bc89d3a1c.png#pic_center)
由上图可知我们选择k为1,准确率较高。
3.结果
3.1欧氏距离
3.2欧几里得距离
4.代码
clc;clear;
rng(1)
% 读数据
data=readtable("sonar.csv");
data1=table2array(data(:,1:60));
data2=table2array(data(:,61));
% 标签二值化
labels=ones(208,1);
for i=1:208
if(data2{i}=='R')
labels(i)=1;
else
labels(i)=2;
end
end
data4=[data1 labels];
% 设置参数
K_Max=1;%k的最大值
N=5;%K交叉验证的份数
accuracy=ones(N,1);
acc=ones(K_Max,1);
n1=0;
n2=0;
n3=0;
n4=0;
% 开始训练
for k=1:K_Max
% K交叉验证
rawrank=randperm(size(data4,1));%打乱顺序
rand_data=data4(rawrank,:);
cell_data=mat2cell(rand_data,[42 42 42 42 40]);%分为N份
for n=1:N
cell_data=circshift(cell_data,1);%移位一次
train_set=cell2mat(cell_data(1:N-1));%取N-1份做训练集
test_set=cell_data{N};%取N份做测试集
pre_label=knn(test_set,train_set,k);%KNN预测
accuracy(n)=sum(pre_label==test_set(:,end))/length(test_set(:,end));%求正确率
n1=n1+length(find(test_set(pre_label==1,end)==1));
n2=n2+length(find(test_set(pre_label==1,end)==2));
n3=n3+length(find(test_set(pre_label==2,end)==1));
n4=n4+length(find(test_set(pre_label==2,end)==2));
end
acc_average=mean(accuracy);%求平均正确率
acc(k)=acc_average;
end
% plot(acc,'k.-','Linewidth',1,'MarkerSize',10);xlabel('K');ylabel('准确率');title('交叉验证(N=5)选择K值')
ConfMat = [n1,n2;n3,n4];
ProbMat = round(ConfMat/sum(ConfMat(:))*100,2);
imagesc(ConfMat)
my=colorplus([1,3]);
colormap(my)
% 设置坐标
xticks([1,2])
xticklabels({'T','N'})
yticks([1,2])
yticklabels({'T','N'})
% 填写信息
T = 30;
g = 0.2;
text(1-g,1,{'True Neg';num2str(ConfMat(1));strcat(num2str(ProbMat(1)),'%')},...
'Color',[1,1,1]*double(ProbMat(1)>T))
text(1-g,2,{'False Pos';num2str(ConfMat(2));strcat(num2str(ProbMat(2)),'%')},...
'Color',[1,1,1]*double(ProbMat(2)>T))
text(2-g,1,{'False Neg';num2str(ConfMat(3));strcat(num2str(ProbMat(3)),'%')},...
'Color',[1,1,1]*double(ProbMat(3)>T))
text(2-g,2,{'True Pos';num2str(ConfMat(4));strcat(num2str(ProbMat(4)),'%')},...
'Color',[1,1,1]*double(ProbMat(4)>T))
set(gcf,'color',[1,1,1])
set(gca,'linewidth',1.5)
set(gca,'FontSize',12,'Fontname', 'Times New Roman');
function out=knn(test_set,train_set,K)
[n ,~]=size(test_set);
[m,~]=size(train_set);
distance=ones(1,m);
out=ones(1,n);
for i=1:n
for j=1:m
%求欧式距离
% distance(j)=sqrt(sum((test_set(i,1:end-1)-train_set(j,1:end-1)).^2));
% 求曼哈顿距离
%distance(j)=sum(abs(test_set(i,1:end-1)-train_set(j,1:end-1)));
% 求欧几里得距离
distance(j)=sqrt(sum(abs(test_set(i,1:end-1)-train_set(j,1:end-1))));
% 求马氏距离
% distance(j)=sqrt((test_set(i,1:end-1)-train_set(j,1:end-1))'*cov([test_set(i,1:end-1)' train_set(j,1:end-1)'])*(test_set(i,1:end-1)-train_set(j,1:end-1)));
end
sum1=0;
sum2=0;
[d,index]=sort(distance,'ascend');
d1=d(1:K)./(sum(d(1:K)));
label=train_set(index(1:K),end);%按照距离大小排序
for k=1:K
if(label(k)==1)
sum1=sum1+d1(k);
else
sum2=sum2+d1(k);
end
end
if(sum2>sum1)
out(i)=2;
else
out(i)=1;
end
end
out=out';
end