版权所有,可以转载,禁止修改。转载请注明作者以及原文链接。

一、KNN算法概述

KNN是Machine Learning领域一个简单又实用的算法,与之前讨论过的算法主要存在两点不同:

  1. 它是一种非参方法。即不必像线性回归、逻辑回归等算法一样有固定格式的模型,也不需要去拟合参数。
  2. 它既可用于分类,又可应用于回归。

KNN的基本思想有点类似“物以类聚,人以群分”,打个通俗的比方就是“如果你要了解一个人,可以从他最亲近的几个朋友去推测他是什么样的人”。

在分类领域,对于一个未知点,选取K个距离(可以是欧氏距离,也可以是其他相似度度量指标)最近的点,然后统计这K个点,在这K个点中频数最多的那一类就作为分类结果。比如下图,若令K=4,则?处应分成红色三角形;若令K=6,则?处应分类蓝色正方形。

在回归(简单起见,这里讨论一元回归)领域,如果只知道某点的预测变量,要回归响应变量,只需要在横坐标轴上(因为不知道纵坐标的值,所以没法计算欧氏距离)选取K个最近的点,然后平均(也可以加权平均)这些点的响应值,作为该点的响应值即可。比如下图中,已知前5个点的横纵坐标值,求时,为多少?若令K=2,则距6.5最近的2个点是(5.1, 8)和(4, 27),把这两个点的纵坐标平均值17.5就可以当作回归结果,认为

KNN具体的算法步骤可参考延伸阅读文献1。

二、KNN性能讨论

KNN的基本思想与计算过程很简单,你只需要考虑两件事:

  1. K预设值取多少?
  2. 如何定义距离?

其中如何定义距离这个需要结合具体的业务应用背景,本文不细致讨论,距离计算方法可参看延伸阅读文献2。这里只讨论K取值时对算法性能的影响。

在上图中,紫色虚线是贝叶斯决策边界线,也是最理想的分类边界,黑色实线是KNN的分类边界。

可以发现:K越小,分类边界曲线越光滑,偏差越小,方差越大;K越大,分类边界曲线越平坦,偏差越大,方差越小。

所以即使简单如KNN,同样要考虑偏差和方差的权衡问题,表现为K的选取。

KNN的优点就是简单直观,无需拟合参数,在样本本身区分度较高的时候效果会很不错;但缺点是当样本量大的时候,找出K个最邻近点的计算代价会很大,会导致算法很慢,此外KNN的可解释性较差。

KNN的一些其他问题的思考可参看延伸阅读文献3。

三、实战案例

1、KNN在保险业中挖掘潜在用户的应用

这里应用ISLR包里的Caravan数据集,先大致浏览一下:

> library(ISLR)
> str(Caravan)
'data.frame': 5822 obs. of 86 variables:
$ Purchase: Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
> table(Caravan$Purchase)/sum(as.numeric(table(Caravan$Purchase)))
No Yes
0.94022673 0.05977327

5822行观测,86个变量,其中只有Purchase是分类型变量,其他全是数值型变量。Purchase两个水平,NoYes分别表示不买或买保险。可见到有约6%的人买了保险。

由于KNN算法要计算距离,这85个数值型变量量纲不同,相同两个点在不同特征变量上的距离差值可能非常大。因此要归一化,这是Machine Learning的常识。这里直接用scale()函数将各连续型变量进行正态标准化,即转化为服从均值为0,标准差为1的正态分布。

> standardized.X=scale(Caravan[,-86])
> mean(standardized.X[,sample(1:85,1)])
[1] -2.047306e-18
> var(standardized.X[,sample(1:85,1)])
[1] 1
> mean(standardized.X[,sample(1:85,1)])
[1] 1.182732e-17
> var(standardized.X[,sample(1:85,1)])
[1] 1
> mean(standardized.X[,sample(1:85,1)])
[1] -3.331466e-17
> var(standardized.X[,sample(1:85,1)])
[1] 1

可见随机抽取一个标准化后的变量,基本都是均值约为0,标准差为1。

> #前1000观测作为测试集,其他当训练集
> test <- 1:1000
> train.X <- standardized.X[-test,]
> test.X <- standardized.X[test,]
> train.Y <- Caravan$Purchase[-test]
> test.Y <- Caravan$Purchase[test]
> knn.pred <- knn(train.X,test.X,train.Y,k=)
> mean(test.Y!=knn.pred)
[1] 0.117
> mean(test.Y!="No")
[1] 0.059

当K=1时,KNN总体的分类结果在测试集上的错误率约为12%。由于大部分的人都不买保险(先验概率只有6%),那么如果模型预测不买保险的准确率应当很高,纠结于预测不买保险实际上却买保险的样本没有意义,同样的也不必考虑整体的准确率(Accuracy)。作为保险销售人员,只需要关心在模型预测下会买保险的人中有多少真正会买保险,这是精准营销的精确度(Precision);因此,在这样的业务背景中,应该着重分析模型的Precesion,而不是Accuracy。

> table(knn.pred,test.Y)
test.Y
knn.pred No Yes
No 874 50
Yes 67 9
> 9/(67+9)
[1] 0.1184211

可见K=1时,KNN模型的Precision约为12%,是随机猜测概率(6%)的两倍!

下面尝试K取不同的值:

> knn.pred <- knn(train.X,test.X,train.Y,k=3)
> table(knn.pred,test.Y)[2,2]/rowSums(table(knn.pred,test.Y))[2]
Yes
0.2
> knn.pred <- knn(train.X,test.X,train.Y,k=5)
> table(knn.pred,test.Y)[2,2]/rowSums(table(knn.pred,test.Y))[2]
Yes
0.2666667

可以发现当K=3时,Precision=20%;当K=5时,Precision=26.7%。

作为对比,这个案例再用逻辑回归做一次!

> glm.fit <- glm(Purchase~.,data=Caravan,family = binomial,subset = -test)
Warning message:
glm.fit:拟合機率算出来是数值零或一
> glm.probs <- predict(glm.fit,Caravan[test,],type = "response")
> glm.pred <- ifelse(glm.probs >0.5,"Yes","No")
> table(glm.pred,test.Y)
test.Y
glm.pred No Yes
No 934 59
Yes 7 0

这个分类效果就差很多,Precision竟然是0!事实上,分类概率阈值为0.5是针对等可能事件,但买不买保险显然不是等可能事件,把阈值降低到0.25再看看:

> glm.pred <- ifelse(glm.probs >0.25,"Yes","No")
> table(glm.pred,test.Y)
test.Y
glm.pred No Yes
No 919 48
Yes 22 11

这下子Precision就达到1/3了,比随机猜测的精确度高出5倍不止!

以上试验都充分表明,通过机器学习算法进行精准营销的精确度比随机猜测的效果要强好几倍!

2、KNN回归

在R中,KNN分类函数是knn(),KNN回归函数是knnreg()

> #加载数据集BloodBrain,用到向量logBBB和数据框bbbDescr
> library(caret)
> data(BloodBrain)
> class(logBBB)
[1] "numeric"
> dim(bbbDescr)
[1] 208 134
> #取约80%的观测作训练集。
> inTrain <- createDataPartition(logBBB, p = .8)[[1]]
> trainX <- bbbDescr[inTrain,]
> trainY <- logBBB[inTrain]
> testX <- bbbDescr[-inTrain,]
> testY <- logBBB[-inTrain]
> #构建KNN回归模型
> fit <- knnreg(trainX, trainY, k = 3)
> fit
3-nearest neighbor regression model
> #KNN回归模型预测测试集
> pred <- predict(fit, testX)
> #计算回归模型的MSE
> mean((pred-testY)^2)
[1] 0.5821147

这个KNN回归模型的MSE只有0.58,可见回归效果很不错,偏差很小!下面用可视化图形比较一下结果。

> #将训练集、测试集和预测值结果集中比较
> df <-data.frame(class=c(rep("trainY",length(trainY)),rep("testY",length(testY)),rep("predY",length(pred))),Yval=c(trainY,testY,pred))
> ggplot(data=df,mapping = aes(x=Yval,fill=class))+
+ geom_dotplot(alpha=0.8)

这是dotplot,横坐标才是响应变量的值,纵坐标表频率。比较相邻的红色点和绿色点在横轴上的差异,即表明测试集中预测值与实际值的差距。

> #比较测试集的预测值和实际值
> df2 <- data.frame(testY,pred)
> ggplot(data=df2,mapping = aes(x=testY,y=pred))+
+ geom_point(color="steelblue",size=3)+
+ geom_abline(slope = 1,size=1.5,linetype=2)

这张散点图则直接将测试集中的实际值和预测值进行对比,虚线是。点离这条虚线越近,表明预测值和实际值之间的差异就越小。

参考文献

Gareth James et al. An Introduction to Statistical Learning.

Wikipedia. k-nearest neighbors algorithm.

KNN for Smoothing and Prediction.

R中实现knn算法(初学)

延伸阅读

  1. xlm289348, kNN(K-Nearest Neighbor)最邻近规则分类

  2. sanqima, KNN算法中常用的距离计算公式

  3. jmydream, http://blog.csdn.net/jmydream/article/details/8644004

KNN算法在保险业精准营销中的应用的更多相关文章

  1. 机器学习笔记--KNN算法1

    前言 Hello ,everyone. 我是小花.大四毕业,留在学校有点事情,就在这里和大家吹吹我们的狐朋狗友算法---KNN算法,为什么叫狐朋狗友算法呢,在这里我先卖个关子,且听我慢慢道来. 一 K ...

  2. 机器学习回顾篇(6):KNN算法

    1 引言 本文将从算法原理出发,展开介绍KNN算法,并结合机器学习中常用的Iris数据集通过代码实例演示KNN算法用法和实现. 2 算法原理 KNN(kNN,k-NearestNeighbor)算法, ...

  3. 【StatLearn】统计学习中knn算法实验(2)

    接着统计学习中knn算法实验(1)的内容 Problem: Explore the data before classification using summary statistics or vis ...

  4. 【StatLearn】统计学习中knn算法的实验(1)

    Problem: Develop a k-NN classifier with Euclidean distance and simple voting Perform 5-fold cross va ...

  5. 理解KNN算法中的k值-knn算法中的k到底指的是什么 ?

    2019-11-09 20:11:26为方便自己收藏学习,转载博文from:https://blog.csdn.net/llhwx/article/details/102652798 knn算法是指对 ...

  6. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  7. KNN算法

    1.算法讲解 KNN算法是一个最基本.最简单的有监督算法,基本思路就是给定一个样本,先通过距离计算,得到这个样本最近的topK个样本,然后根据这topK个样本的标签,投票决定给定样本的标签: 训练过程 ...

  8. kNN算法python实现和简单数字识别

    kNN算法 算法优缺点: 优点:精度高.对异常值不敏感.无输入数据假定 缺点:时间复杂度和空间复杂度都很高 适用数据范围:数值型和标称型 算法的思路: KNN算法(全称K最近邻算法),算法的思想很简单 ...

  9. 什么是 kNN 算法?

    学习 machine learning 的最低要求是什么?  我发觉要求可以很低,甚至初中程度已经可以.  首先要学习一点 Python 编程,譬如这两本小孩子用的书:[1][2]便可.   数学方面 ...

随机推荐

  1. [干货分享]一篇可能会让你爱上MVVM与ReactiveCocoa的文章

    概要 在此工程中,本文将讨论将MVC改造为MVVM需要的一些基本方法,同时会适当穿插部分关于MVVM概念性的讨论!本文最大的意义在于,提供了一种读者可以复现的方式,逐步引出从MVC向MVVM尽可能平滑 ...

  2. 泉五培训Day4

    T1 收果子 题目 [题目描述] 有一个果园,有n棵果树依次排成一排,其中已知第 i 棵果树上结了ai个果子.现在要按照果树编号顺序依次收果子,对于一个能装v个果树的果篮,收果子从第1棵果树开始,如果 ...

  3. Hibernate无法提取结果集

    原因:表结构错误或 与 映射文件不一致 org.springframework.dao.InvalidDataAccessResourceUsageException: could not extra ...

  4. float元素浮动后高度不一致导致错位的解决办方法

    换行开始的第一个元素clear:left;即可 例如  四列时应该时第5个,9个...加clear:left; .row .col-lg-3:nth-child(4n+1),.row .col-md- ...

  5. dts--tests(四)

    unit_tests.py """ DPDK Test suite. This TestSuite runs the unit tests included in DPD ...

  6. @ApiModelProperty用法

    @ApiModelProperty()用于方法,字段: 表示对model属性的说明或者数据操作更改 value–字段说明 name–重写属性名字 dataType–重写属性类型 required–是否 ...

  7. [回文树][BZOJ2160][国家集训队]拉拉队排练

    题面 Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助篮 ...

  8. python,多线程

    多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离,同时,又要小心死锁的发生. Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核.多线程的并发在Python中就是一个美丽的梦. ...

  9. CSS计数器(自定义列表)Demo

    html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  10. 编译IOS下 libpcap1.7.2

    1.修改build-libpcap.sh libpcap版本号 2.执行脚本编译 出现问题: 2.发现configure过后,Makefile存在问题 实际configure的-arch armv7s ...