vlambda博客
学习文章列表

R语言实现 懒惰学习——使用近邻分类

# Example: Classifying Cancer Samples ----

乳腺癌数据包括569例细胞活检案例,每个案例有32个特征。一个特征是识别号码,一个特征是癌症诊断结果,其他30个特征是数值型的实验室测量结果。癌症诊断结果用编码“M”表示恶性,用编码“B”表示良性。


## Step 1: Exploring and preparing the data ---- 

import the CSV file

wbcd <- read.csv("F:\\rwork\\Machine Learning with R (2nd Ed.)\\Chapter 03\\wisc_bc_data.csv", stringsAsFactors = FALSE)


examine the structure of the wbcd data frame

str(wbcd)


将Id特征删除

wbcd <- wbcd[-1]


table of diagnosis

table(wbcd$diagnosis)

R语言实现 懒惰学习——使用近邻分类

table的输出结果显示357个肿块是良性的,而212个肿块是恶性的


因子化数据


wbcd$diagnosis <- factor(wbcd$diagnosis, levels = c("B", "M"), labels = c("Benign", "Malignant"))


table or proportions with more informative labels

round(prop.table(table(wbcd$diagnosis)) * 100, digits = 1)

R语言实现 懒惰学习——使用近邻分类

此时,我们发现分别有62.7%的良性肿块和37.3%的恶性肿块。
其余的30个特征都是数值型的,与预期的一-样,由10个细胞核特征的3种不同测量构成。作为示例,我们这里详细地观察3个特征:


summarize three numeric features

summary(wbcd[c("radius_mean", "area_mean", "smoothness_mean")])

R语言实现 懒惰学习——使用近邻分类

纵观这些并排的特征,你注意到关于数值的一些问题吗? 回想- - -下,kNN的距离计算在很大程度上依赖于输人特征的测量尺度。由于smoothness_ mean 的范围是从0.05 ~ 0.16,而area_ mean 的范围是从143.5 ~ 2501.0, 所以在距离计算中,区域( area-mean)的影响比平滑度(smoothness-mean)的影响大很多,这可能会潜在地导致我们的分类器出现问题,所以我们应用min-max标准化方法重新调整特征的值到一个标准的范围内。


转换一min-max 标准化数值型数据

为了将这些特征min-max标准化,我们需要在R中创建一个normalize()函数,该函数输人一个数值型向量x,并且对于x中的每-一个值,减去x中的最小值再除以x中值的范围,最后,返回结果向量。该函数的代码如下:
normalize <- function(x) { return ((x - min(x)) / (max(x) - min(x)))}
现在,我们可以将normalize()函数应用于我们数据框中的数值型特征。


normalize the wbcd data

wbcd_n <- as.data.frame(lapply(wbcd[2:31], normalize))


以通俗的语言来讲,该命令把normalize()函数应用到数据框wbcd的第2~31列,把产生的结果列表转换成一个数据框,并给该数据框赋予一个名称wbcd_ n。这里使用的后缀“_ n”是作为一个提示,即wbcd中的值已经被min-max标准化了。
为了确认转换是否正确应用,让我们来看看其中一个变量的汇总统计量:
summary(wbcd_n$area_mean)

R语言实现 懒惰学习——使用近邻分类

正如预期的那样,area_ _mean 变量的原始范围是143.5 ~ 2501.0, 而现在的范围是0~1。



尽管所有的569个活检的良性或者恶性情形都已被标记,但是预测我们已经知道的结果并不是特别令人感兴趣的。此外,我们在训练期间得到的算法分类好坏的衡量指标可能是有误的,因为我们不知道数据发生过度拟合的程度。


由于缺少这样的数据,所以我们可以通过把我们的数据划分成两部分来模拟这种方案:部分是用来建立kNN模型的训练数据集;另一部分是用来估计模型预测准确性的测试数据集。我们使用前469条记录作为训练数据集,剩下的100条记录用来模拟新的病人。


create training and test data

wbcd_train <- wbcd_n[1:469, ]wbcd_test <- wbcd_n[470:569, ]


create labels for training and test data

wbcd_train_labels <- wbcd[1:469, 1]wbcd_test_labels <- wbcd[470:569, 1]
该代码使用wbcd数据框第一列的diagnosis因子,并且创建了wbcd_ train_ labels 和wbcd_ test_ labels两个向量。我们将会在下面的分类器的训练和评估步骤中使用这些向量。


## Step 2: Training a model on the data ----


library(class)
class添加包中的knn()函数提供了一个标准的kNN算法实现。对于测试数据中的每一个实例,该函数将使用欧氏距离标识k个近邻,其中k是用户指定的一个数。


由于训练数据集含有469个实例,所以我们可能会尝试k= 21,它是-一个大约等于469的平方根的奇数。使用奇数将会减少各个类票数相等这一情况发生的可能性。
wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k = 21)


## Step 3: Evaluating model performance ----


library(gmodels)


Create the cross tabulation of predicted vs. actual

CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq = FALSE)

R语言实现 懒惰学习——使用近邻分类

落在另一条对角线上的单元格包含了kNN算法与真实标签不一致的案例计数。位于左下角FN单元格的2个案例是假阴性( False Negative)的结果。在这种情况下,预测的值是良性的,但肿瘤实际上是恶性的。这个方向上的错误可能会产生极其高昂的代价,因为它们可能导致一位病人认为自已没有癌症,而实际上这种疾病可能会继续蔓延。如果右上角标记


一共有2%,即根据kNN算法,100 个肿块中,有2个是被错误分类的。虽然对于仅用几行的R代码,就得到98%的准确度似乎令人印象深刻,但是我们可以尝试一些其他的模型迭代方法来看看我们是否可以提高性能并减少错误分类值的数量,特别当错误是危险的假阴性(False Negative)结果时。


## Step 4: Improving model performance ----


对模型数据进行标准化处理

wbcd_z <- as.data.frame(scale(wbcd[-1]))


confirm that the transformation was applied correctly

summary(wbcd_z$area_mean)

R语言实现 懒惰学习——使用近邻分类


create training and test datasets

wbcd_train <- wbcd_z[1:469, ]wbcd_test <- wbcd_z[470:569, ]


re-classify test cases

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k = 21)


Create the cross tabulation of predicted vs. actual

CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq = FALSE)

之前,我们正确分类了98%的案例,而这一次我们正确分类了99%的案例,相比之下,正确率已经得到提高。


或许,我们可以做得更好,即检验应用不同的k值模型的性能。使用min-max标准化的训练数据集和测试数据集,然后用几个不同的k值来对相同的100个记录进行分类。每次迭代的假阴性(False Negative)和假阳性(False Positive)的数量如下表所示。


try several different values of k


wbcd_train <- wbcd_n[1:469, ]wbcd_test <- wbcd_n[470:569, ]
wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k=1)CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq=FALSE)

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k=5)CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq=FALSE)

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k=11)CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq=FALSE)

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k=15)CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq=FALSE)

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k=21)CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq=FALSE)

wbcd_test_pred <- knn(train = wbcd_train, test = wbcd_test, cl = wbcd_train_labels, k=27)CrossTable(x = wbcd_test_labels, y = wbcd_test_pred, prop.chisq=FALSE)

```


欢迎指正哦~

需要数据请私聊哦~

原理百度一下就有很多哦,这里就不阐述了。