play with knn
- 1. 什么是knn
- 1.1. 什么是knn
- 1.2. knn适用范围
- 2. knn实验前的准备
- 2.1. knn的实验要点
- 3. knn的matlab实验【使用UCI数据集】
- 3.0. KNN函数自带用例
- 3.1. UCI数据集
- 3.2. knn实验计划
- 3.3. 数据集筛选
- 3.4. play with knn
- 4. 总结
1. 什么是knn
1.1. 什么是knn
来了一个无标签的样本,找它的周围邻居(有标签)投票。
1.2. knn适用范围
优点:
1、KNN算法是一个非常简单的算法,理论成熟,思想简单,既可以用来做分类也可以用来做回归
2、天然解决多分类问题,也可用于回归问题
3、和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感
4、KNN在训练过程中实质上不需要做任何事情,所以训练本身不产生任何时间上的消耗
5、由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合
缺点:
1、计算量大,效率低。即使优化算法,效率也不高。
2、高度数据相关,样本不平衡的时候,对稀有类别的预测准确率低
3、相比决策树模型,KNN模型可解释性不强
4、维度灾难:随着维度的增加,“看似相近”的两个点之间的距离越来越大,而knn非常依赖距离
2. knn实验前的准备
2.1. knn的实验要点
- 数据预处理的时候,要先划分数据集;把测试集丢入训练集的处理模式。而不是测试集重开。
- knn是懒惰学习的代表。测试集丢进去才学
3. knn的matlab实验【使用UCI数据集】
3.0. KNN函数自带用例
load fisheriris
X = meas;
Y = species;
这个时候有
对照数据集描述,也就是有n = 150的样本,和m = 4的特征
mdl = fitcknn(X,Y,'NumNeighbors',5,'Standardize',1);
这里Standardize是标准化的意思。X并没有标准化
直接丢进去建模
Xnew = [min(X);mean(X);max(X)];
[label,score,cost] = predict(mdl,Xnew)
可以得到结果
- 这里比较简单,测试集是和了下训练集的数据就丢进去的。
- score的每行有三个元素,是对应三个标签的概率。一行是一个样本。每行最大的元素所在位置,就是标签label
3.1. UCI数据集
手头有别人整理好的开源的数据集。因为重点是比较各个算法的优劣程度,所以偷懒把训练集/验证集/测试集一起数据归一化/标准化。。。严格来说不该这么做。
3.2. knn实验计划
- 数据集全部标准化
- 划分训练集,验证集,测试集并进行保存
- 训练集,测试集丢入knn
- 保留效果有提升空间的数据集
3.3. 数据集筛选
- arrhythmia
- congressional-voting
- cylinder-bands
- dermatology
- hill-valley(test)
- statlog-heart
- wine
3.4. play with knn
%%
%目前情况
%结果正常的。特点:数据集本身已标准化,关掉模型的标准化【不关掉也没影响】
load('E:\work\playground\database\wine\归一化数据\zscore_Set_wine.mat')
X = TrainSet_zscore(:,2:14);
Y = TrainSet_zscore(:,1);
Xt = TestSet_zscore(:,2:14);
Yt = TestSet_zscore(:,1);
mdl = fitcknn(X,Y,'NumNeighbors',5);%,
CVKNNMdl = crossval(mdl);
classError = kfoldLoss(CVKNNMdl)
label = predict(mdl,Xt);
accr = length(find(label~=Yt))/length(Yt)
%%
%{
%结果不正常
%特点:1.使用预处理数据(未标准化)
clear
load('E:\work\playground\database\wine\预处理完成\wine.mat')
[numSample,numFea] = size(DataSet);
X = DataSet(:,2:numFea);
Y = DataSet(:,1);
numFea = numFea - 1;
CVKNNMdl2 = fitcknn(X,Y,'NumNeighbors',5,'KFold',3);%,'Standardize',1 关掉标准化,会发现wine异常敏感
classError2 = kfoldLoss(CVKNNMdl2)%到这里是正常的
[accr,list,classError] = splitnoval(DataSet,120);%在这里不正常
accr
classError
%}
。。。其实都可以,说不正常是因为
- 当时缓存没清
- splitnoval(捂脸)
- 有说法是算法一起比较的话,标准化/归一化并不是绝对必要的
function [accr,list,classError] = splitnoval(zscore_normalization,trainsplit)
%playknn 此处显示有关此函数的摘要
% 此处显示详细说明
[numSample,numFea] = size(zscore_normalization);
X = zscore_normalization(:,2:numFea);
numFea = numFea - 1;
Y = zscore_normalization(:,1);
list = randperm(numSample);
Xtrain = X(list(1:trainsplit),:);
Xtest = X(list(1+trainsplit:numSample),:);
Ytrain = Y(list(1:trainsplit));
Ytest = Y(list(1+trainsplit:numSample));
mdl = fitcknn(Xtrain,Ytrain,'NumNeighbors',5);%,'Standardize',1
CVKNNMdl = crossval(mdl);
classError = kfoldLoss(CVKNNMdl);%在这里正常【即使使用测试集建模也没有问题,是正常的】
label = predict(mdl,Xtest);%这里有问题!
accr = length(find(label~=Ytest))/length(Ytest);
end
虽然注释标注有问题,但其实当时运行了其他的,缓存没清
4. 总结
- 对knn使用CV可以检查问题
- 标准化/归一化并不是绝对绝对必须按流程走的