查看原文
其他

分类算法之knn

2015-12-10 刘顺祥 每天进步一点点2015

knn概念

本文从机器学习中的分类算法knn开始讲起,knn即k邻近算法,该算法就是将未分类的样本归为最相似的已分类样本中,而且该算法简单有效,对数据的分布不作任何要求。其核心思想是:通过计算未分类样本到已分类样本的距离,根据最近的k个距离,使用投票法,将未分类样本进行分类。


模型数据条件

已知该算法是基于距离来衡量邻近概念,这就对数据的要求比较严格,具体满足如下:

1)训练集和测试集中不能含有缺失值,如果原始数据含有缺失值,可以考虑删除缺失记录或是进行多重插补,具体可以查看公众号中的缺失值处理方法一文;

2)对于名义变量(如姓名,学历等)需要进行哑变量处理,如性别处理为0,1,学历初中、高中、大学处理为两个哑变量,分别用0,1表示;

3)变量之间如存在较大的量纲,如一个变量的范围是1~10,另一个变量的范围是-1000~1000,需考虑标准化处理。


k值选取

knn为k邻近算法,需要解决的一个问题是选择合适的k值,k值过小或过大都会影响模型的准确性,一般考虑将k值设为3~10,或是将k值设为训练集样本数量的平方根。还有一种选择k值的方法是结合训练集和测试集,循环k值,直到挑选出使测试集的误差率最小的k值,具体可参见下文的R脚本。


算法函数讲解

关于K最邻近算法的实现可以使用class包中的knn()函数。knn()函数的语法和参数如下:

knn(train, test, cl, k = 1, l = 0, prob = FALSE, use.all = TRUE)

train指定训练样本集;

test指定测试样本集;

cl指定训练样本集中分类变量;

k指定最邻近的k个已知分类样本点,默认为1;

l指定待判样本点属于某类的最少已知分类样本数,默认为0;

prob设为TRUE时,可以得到待判样本点属于某类的概率,默认为FALSE;

use.all控制节点的处理办法,即如果有多个第K近的点与待判样本点的距离相等,默认情况下将这些点都纳入判别样本点,当该参数设为FALSE时,则随机挑选一个样本点作为第K近的判别点。


案例应用

本案例使用UCI机器学习数据仓库的“威斯康星乳腺癌诊断”数据集,数据可从http://archive.ics.uci.edu/ml下载,该数据集包含569个样本和32个变量,具体数据可参见后文链接。


#数据读取

cancer <- read.table(file = file.choose(), header = FALSE,

sep = ',')

#编辑变量名

names(cancer) <- c('ID','Diagnosis','radius_mean','radius_sd','radius_worst',

'texture_mean','texture_sd','texture_worst',

'perimeter_mean','perimeter_sd','perimeter_worst',

'area_mean','area_sd','area_worst',

'smoothness_mean','smoothness_sd','smoothness_worst',

'compactness_mean','compactness_sd','compactness_worst',

'concavity_mean','concavity_sd','concavity_worst',

'concavepoints_mean','concavepoints_sd','concavepoints_worst',

'symmetry_mean','symmetry_sd','symmetry_worst',

'fractaldimension_mean','fractaldimension_sd','fractaldimension_worst')


#数据探索

dim(cancer)

[1] 569 32

发现数据集中含有569个样本和32个变量

str(cancer)

summary(cancer)

从汇总情况来看,数据集中不含有缺失值,除Diagnosis变量外,其余变量均为数值型变量,ID变量为编号,没有任何意义,故在建模过程中将删除该变量。发现各个变量间存在明显的量纲大小,需要进一步对原始数据进行标准化。


#构建标准化函数

standard <- function(x) {

(x-min(x))/(max(x)-min(x))

}

#将该函数应用到数据框cancer中的每一列(除Diagnosis变量)

cancer_standard <- sapply(X = cancer[,3:32], FUN = standard)

summary(cancer_standard)

此时数据框中的所有变量值范围落在0~1之间


#将数据框cancer中的Diagnosis变量合并到cancer_standard中

cancer_standard <- as.data.frame(cbind(cancer$Diagnosis,cancer_standard))

names(cancer_standard)[1] <- 'Diagnosis'

#构建训练集、测试集和验证集

set.seed(1234)

index <- sample(x = 1:3,size = nrow(cancer_standard), replace = TRUE, prob = c(0.7,0.2,0.1))

train <- cancer_standard[index == 1,]

test <- cancer_standard[index == 2,]

valid <- cancer_standard[index == 3,]

#查看三类样本的容量

dim(train);dim(test);dim(valid)

[1] 392 31

[1] 112 31

[1] 65 31


#构建模型,以循环的方式选择knn算法中的k值

library(class)

for (i in 1:round(sqrt(dim(train)[1]))){

model <- knn(train = train[,-1], test = test[,-1], cl = train$Diagnosis, k = i)

Freq <- table(test[,1], model)

print(1-sum(diag(Freq))/sum(Freq))

}


#发现k=16时,对应的分类误差率最低,为0.027,故取k=16

fit <- knn(train = train[,-1], test = valid[,-1], cl = train$Diagnosis, k = 16)

#查看模型预测与实际类别的列联表

Freq <- table(valid[,1], fit)

Freq


#预判正确率

sum(diag(Freq))/sum(Freq)

[1] 0.9692308

可见模型的正确分类率达到96%以上。


数据集和脚本下载

文中涉及到的数据集和脚本可到下方链接中下载:

http://yunpan.cn/c3kTUwpjMeagD 访问密码 56d1


参考资料

机器学习与R语言

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存