机械学习与R语言- 懒惰的KNN 算法

本次需要使用到《机械学习与R语言》中的数据包‘wisc_bc_data.csv’。可以到网上自行搜索下载or到我github里下载:https://github.com/HAI2018/MLwR/   到第二版第三章,点进wisc_bc_data.csv -> 再点击 raw -> 右键另存为 

本文代码多来源于《MACHINE LEARNING WITH R》- Brett Lantz

1.临近分类法(KNN)

KNN 算法是一个原理极其简单的算法,但是却在机械学习中广泛应用。所谓的算法,无非是一些通过实际从业者or研究人员思考出来以解决实际问题的方法,当这些方法被数学证明同时又被实践认同后,便会成为我们的流行的算法。算法并不是越复杂越好(即使很多时候它们内在的计算较为复杂or对于细节的取舍需求经验),实际上(在我看来)大道至简才是最好的算法和应用。 今天要聊到的KNN算法便是一个大道至简而应用较广的算法。

KNN(k-nearest-neighbor)只服务于数值型变量(也能服务character类型,但是需要做出相应调整),基本理念是,样本距离哪一类近,那么就会被归为哪一类。(我稍微解释一下吧...如果还不清楚建议google)如下图(来源网络):


我们已经有了正方形和三角形很多样本,他们分布于空间之中,那么中间的圆如果要分类,那到底属于三角形还是正方形呢?KNN算法,如果把K取1,那么我们就只考虑和它最近的数据是哪一个类型(显然三角形近),这样子圆形最后会被算法判断为三角形。这个取值显然并不合理,这样子的分类会被极端值影响。 那如果K取2,我们会让最接近的两个数据进行投票(显然,最近的两个数据都是三角形,圆会被归类为三角形);同理,k=3,那么左边那个正方形会被归进来投票(unfortunately,1:2,圆形还是会被归类为三角形),以此类推。一般我们倾向于设为 sqrt(n),n是样本量。

2.KNN的距离算法

我们说了取最近,但是最近该怎么定义?

a.Euclidean distance(欧几里得距离): 最常用且很容易理解的距离算法,我们很早很早以前便接触过:

(不多做解释)

b. Mahanttan distance: 也很容易理解,具体去google。 概念如下图(红、蓝、黄都是,绿色是欧式距离):


无非是坐标之差的绝对值之和。

c. many others :不多做介绍,还有很多类型,有兴趣?dist 去R里面了解。

3.KNN 在R里的实现(实战)

A. 数据的预处理

既然是距离,那就不能有a. characters b. NA  c.NULL 含有以上值的话,距离不精确,那边毫无意义。

我们先读取开头提到的数据,该数据是根据癌细胞的各种特征,来判断病人是否得乳腺癌的依据以及结果,第一列是ID,没有用,第二列是诊断结果,B为 benign, M为malignant。 其余列都是数值型数据,为判断依据。

# import the CSV file
wbcd <- read.csv("wisc_bc_data.csv", stringsAsFactors = FALSE)

# drop the id feature
wbcd <- wbcd[-1]          #ID 没有意义

# recode diagnosis as a factor
wbcd$diagnosis <- factor(wbcd$diagnosis, levels = c("B", "M"),
                         labels = c("Benign", "Malignant"))                      #factor化

# table or proportions with more informative labels
round(prop.table(table(wbcd$diagnosis)) * 100, digits = 1)   #了解阴性阳性结果的大致情况

summary(wbcd)  #看看情况

which(complete.cases(wbcd)==F)  #没有缺失值

dim(wbcd)    #看看情况
head(wbcd)   #看看情况
tail(wbcd)   #看看情况

我们跑完上面codes之后,可以发现没有缺失值,且数据都是数值型(excellent!),唯一的问题是每一个column的数据的range不一样。想象一下,range不一样意味着尺码不一样,我们把蚂蚁和大象做比较有意义吗?所以我们应该先做的就是 数据的标准化

B. 数据标准化

我只介绍一种很常用的方法,rescale(): min-max标准化

大致是 (x-min(x))/(max(x)-min(x))这个算法会把最小的值化为0,而最大的值化为1. 所有的数据按照这种算法标准化后便会形成range一样的数据,在这种处理后的距离比较才是有意义的。我们开始吧:

#安装包:scales

library(scales)

wbcd_n<- as.data.frame(lapply(wbcd[,c(2:31)],rescale)) #数据标准化,都转换成0-1之间

C. 建立train 和 test data

wbcd_train <- wbcd_n[1:469, ]
wbcd_test <- wbcd_n[470:569, ]  #这里的做法很简单,我个人建议使用sample function来建立train & test data

D. KNN算法的应用

我们建立预处理完了数据,那么开始吧:

# load the "class" library
library(class)
wbcd_train_labels <- wbcd[1:469, 1]
wbcd_test_labels <- wbcd[470:569, 1]

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test,
                      cl = wbcd_train_labels, k = 21)  #得到了预测结果
class(wbcd_test_pred)   #factor

解释一下, cl的意思就是class,这里即我们的诊断结果(should be factor type)。 而k之所以设为21,是根据 sqrt(n)来选择的。得到的 变量就是预测结果,返回的是factor。class包里knn算法所采用的距离是欧氏距离,如果需要更高效or其他种类的knn算法,去CRAN 里找knn了解。

E. 模型结果评估(evaluation)

table(wbcd_test_labels,wbcd_test_pred) 

                wbcd_test_pred
wbcd_test_labels Benign Malignant
       Benign        61         0
       Malignant      2        37

得到的结果,在一百个test data里面,只有两个预测错误(False Negative),我们预测正确了98个。 然而,这两个预测错误是很致命的,因为它将本是阳性的结果预测为了阴性(可能导致病人没有及时发现病情),这并不是我们想要的。 优化的方法有很多,我不做讨论(因为真的讨论不完)。但是,我们必须知道,很多时候涉及到了增强算法精确度与成本之间的tradeoff, 当算法越来越精确的时候,成本也越来越高,而此时的边际收益很低(有时会为了增加1%的精确度而使成本翻倍)。然而在很多领域(尤其是医疗、精算等),精确度的要求极其高,这也部分解释了为什么有些医疗仪器价格如此高昂。 当然,在一些其他领域(如仅仅是智能判断一个普通样本的类别),那么这种程度的错误率是可以被包容的。


ALL in ALL

几行代码,knn算法便可以达到>95%的准确率来判断癌细胞的肿块属于B还是M。算法很简单但却能处理复杂的任务,和其他算法一样,knn依然高度依赖于数据的精确,癌细胞的各个特征必须被精确测量和量化(如果数据源本身都不精确,模型还有什么意义,这就是‘中国估计学’梗的来源)

猜你喜欢

转载自blog.csdn.net/clintlong/article/details/80986016