1. K-近邻算法简介
1.K-近邻(KNearestNeighbor,KNN)算法简介 :对于一个未知的样本,我们可以根据离它最近的k个样本的类别来判断它的类别。
以下图为例,对于一个未知样本绿色小圆,我们可以选取离它最近的3的样本,其中包含了2个红色三角形,1个蓝色正方形,那么我们可以判断绿色小圆属于红色三角形这一类。
我们也可以选取离它最近的5个样本,其中包含了3个蓝色正方形,2个红色三角形,那么我们可以判断绿色小圆属于蓝色正方形这一类。
3.API文档
下面我们来对KNN算法中的参数项做一个解释说明:
'n_neighbors':选取的参考对象的个数(邻居个数),默认值为5,也可以自己指定数值,但不是n_neighbors的值越大分类效果越好,最佳值需要我们做一个验证。
'weights': 距离的权重参数,默认uniform。
'uniform': 均匀的权重,所有的点在每一个类别中的权重是一样的。简单的说,就是每个点的重要性都是一样的。
'distance':权重与距离的倒数成正比,距离近的点重要性更高,对于结果的影响也更大。
'algorithm':运算方法,默认auto。
'auto':根绝模型fit的数据自动选择最合适的运算方法。
'ball_tree':树模型算法BallTree
'kd_tree':树模型算法KDTree
'brute':暴力算法
'leaf_size':叶子的尺寸,默认30。只有当algorithm = 'ball_tree' or 'kd_tree',这个参数需要设定。
'p':闵可斯基距离,当p = 1时,选择曼哈顿距离;当p = 2时,选择欧式距离。
n_jobs:使用计算机处理器数目,默认为1。当n=-1时,使用所有的处理器进行运算。
4.应用案例演示
下面以Sklearn库中自带的数据集--手写数字识别数据集为例,来测试下kNN算法。上一章,我们简单的介绍了机器学习的一般步骤:加载数据集 - 训练模型 - 结果预测 - 保存模型。这一章我们还是按照这个步骤来执行。
[手写数字识别数据集] https://scikit-learn.org/stable/moles/generated/sklearn.datasets.load_digits.html#sklearn.datasets.load_digits
5.模型的方法
每一种模型都有一些它独有的属性方法(模型的技能,能做些什么事),下面我们来了解下knn算法常用的的属性方法。
6.knn算法的优缺点
优点:
简单,效果还不错,适合多分类问题
缺点:
效率低(因为要计算预测样本距离每个样本点的距离,然后排序),效率会随着样本量的增加而降低。
2. 使用Node.js如何实现K最近邻分类算法
源于数据挖掘的一个作业, 这里用Node.js技术来实现一下这个机器学习中最简单的算法之一k-nearest-neighbor算法(k最近邻分类法)。
k-nearest-neighbor-classifier
还是先严谨的介绍下。急切学习法(eager learner)是在接受待分类的新元组之前就构造了分类模型,学习后的模型已经就绪,急着对未知的元组进行分类,所以称为急切学习法,诸如决策树归纳,贝叶斯分类等都是急切学习法的例子。惰性学习法(lazy learner)正好与其相反,直到给定一个待接受分类的新元组之后,才开始根据训练元组构建分类模型,在此之前只是存储着训练元组,所以称为惰性学习法,惰性学习法在分类进行时做更多的工作。
本文的knn算法就是一种惰性学习法,它被广泛应用于模式识别。knn基于类比学习,将未知的新元组与训练元组进行对比,搜索模式空间,找出最接近未知元组的k个训练元组,这里的k即是knn中的k。这k个训练元祖就是待预测元组的k个最近邻。
balabala了这么多,是不是某些同学想大喊一声..speak Chinese! 还是来通俗的解释下,然后再来看上面的理论应该会明白很多。小时候妈妈会指着各种各样的东西教我们,这是小鸭子,这个红的是苹果等等,那我们哼哧哼哧的看着应答着,多次被教后再看到的时候我们自己就能认出来这些事物了。主要是因为我们在脑海像给这个苹果贴了很多标签一样,不只是颜色这一个标签,可能还有苹果的形状大小等等。这些标签让我们看到苹果的时候不会误认为是橘子。其实这些标签就对应于机器学习中的特征这一重要概念,而训练我们识别的过程就对应于泛化这一概念。一台iphone戴了一个壳或者屏幕上有一道划痕,我们还是能认得出来它,这对于我们人来说非常简单,但蠢计算机就不知道怎么做了,需要我们好好调教它,当然也不能过度调教2333,过度调教它要把其他手机也认成iphone那就不好了,其实这就叫过度泛化。
所以特征就是提取对象的信息,泛化就是学习到隐含在这些特征背后的规律,并对新的输入给出合理的判断。
我们可以看上图,绿色的圆代表未知样本,我们选取距离其最近的k个几何图形,这k个几何图形就是未知类型样本的邻居,如果k=3,我们可以看到有两个红色的三角形,有一个蓝色的三正方形,由于红色三角形所占比例高,所以我们可以判断未知样本类型为红色三角形。扩展到一般情况时,这里的距离就是我们根据样本的特征所计算出来的数值,再找出距离未知类型样本最近的K个样本,即可预测样本类型。那么求距离其实不同情况适合不同的方法,我们这里采用欧式距离。
综上所述knn分类的关键点就是k的选取和距离的计算。
2. 实现
我的数据是一个xls文件,那么我去npm搜了一下选了一个叫node-xlrd的包直接拿来用。
// node.js用来读取xls文件的包
var xls = require('node-xlrd');
然后直接看文档实例即可,把数据解析后插入到自己的数据结构里。
var data = [];// 将文件中的数据映射到样本的属性var map = ['a','b','c','d','e','f','g','h','i','j','k'];// 读取文件
xls.open('data.xls', function(err,bk){
if(err) {console.log(err.name, err.message); return;}
var shtCount = bk.sheet.count;
for(var sIdx = 0; sIdx < shtCount; sIdx++ ){
var sht = bk.sheets[sIdx],
rCount = sht.row.count,
cCount = sht.column.count;
for(var rIdx = 0; rIdx < rCount; rIdx++){
var item = {};
for(var cIdx = 0; cIdx < cCount; cIdx++){
item[map[cIdx]] = sht.cell(rIdx,cIdx);
}
data.push(item);
}
}
// 等文件读取完毕后 执行测试
run();
});
然后定义一个构造函数Sample表示一个样本,这里是把刚生成的数据结构里的对象传入,生成一个新的样本。
// Sample表示一个样本
var Sample = function (object) {
// 把传过来的对象上的属性克隆到新创建的样本上
for (var key in object)
{
// 检验属性是否属于对象自身
if (object.hasOwnProperty(key)) {
this[key] = object[key];
}
}
}
再定义一个样本集的构造函数
// SampleSet管理所有样本 参数k表示KNN中的kvar SampleSet = function(k) {
this.samples = [];
this.k = k;
};
// 将样本加入样本数组
SampleSet.prototype.add = function(sample) {
this.samples.push(sample);
}
然后我们会在样本的原型上定义很多方法,这样每个样本都可以用这些方法。
// 计算样本间距离 采用欧式距离
Sample.prototype.measureDistances = function(a, b, c, d, e, f, g, h, i, j, k) {
for (var i in this.neighbors)
{
var neighbor = this.neighbors[i];
var a = neighbor.a - this.a;
var b = neighbor.b - this.b;
var c = neighbor.c - this.c;
var d = neighbor.d - this.d;
var e = neighbor.e - this.e;
var f = neighbor.f - this.f;
var g = neighbor.g - this.g;
var h = neighbor.h - this.h;
var i = neighbor.i - this.i;
var j = neighbor.j - this.j;
var k = neighbor.k - this.k;
// 计算欧式距离
neighbor.distance = Math.sqrt(a*a + b*b + c*c + d*d + e*e + f*f + g*g + h*h + i*i + j*j + k*k);
}
};
// 将邻居样本根据与预测样本间距离排序
Sample.prototype.sortByDistance = function() {
this.neighbors.sort(function (a, b) {
return a.distance - b.distance;
});
};
// 判断被预测样本类别
Sample.prototype.guessType = function(k) {
// 有两种类别 1和-1
var types = { '1': 0, '-1': 0 };
// 根据k值截取邻居里面前k个
for (var i in this.neighbors.slice(0, k))
{
var neighbor = this.neighbors[i];
types[neighbor.trueType] += 1;
}
// 判断邻居里哪个样本类型多
if(types['1']>types['-1']){
this.type = '1';
} else {
this.type = '-1';
}
}
注意到我这里的数据有a-k共11个属性,样本有1和-1两种类型,使用truetype和type来预测样本类型和对比判断是否分类成功。
最后是样本集的原型上定义一个方法,该方法可以在整个样本集里寻找未知类型的样本,并生成他们的邻居集,调用未知样本原型上的方法来计算邻居到它的距离,把所有邻居按距离排序,最后猜测类型。
// 构建总样本数组,包含未知类型样本
SampleSet.prototype.determineUnknown = function() {
for (var i in this.samples)
{
// 如果发现没有类型的样本
if ( ! this.samples[i].type)
{
// 初始化未知样本的邻居
this.samples[i].neighbors = [];
// 生成邻居集
for (var j in this.samples)
{
// 如果碰到未知样本 跳过
if ( ! this.samples[j].type)
continue;
this.samples[i].neighbors.push( new Sample(this.samples[j]) );
}
// 计算所有邻居与预测样本的距离
this.samples[i].measureDistances(this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h, this.k);
// 把所有邻居按距离排序
this.samples[i].sortByDistance();
// 猜测预测样本类型
this.samples[i].guessType(this.k);
}
}
};
最后分别计算10倍交叉验证和留一法交叉验证的精度。
留一法就是每次只留下一个样本做测试集,其它样本做训练集。
K倍交叉验证将所有样本分成K份,一般均分。取一份作为测试样本,剩余K-1份作为训练样本。这个过程重复K次,最后的平均测试结果可以衡量模型的性能。
k倍验证时定义了个方法先把数组打乱随机摆放。
// helper函数 将数组里的元素随机摆放
function ruffle(array) {
array.sort(function (a, b) {
return Math.random() - 0.5;
})
}
剩余测试代码好写,这里就不贴了。
测试结果为
用余弦距离等计算方式可能精度会更高。
3. 总结
knn算法非常简单,但却能在很多关键的地方发挥作用并且效果非常好。缺点就是进行分类时要扫描所有训练样本得到距离,训练集大的话会很慢。
可以用这个最简单的分类算法来入高大上的ML的门,会有点小小的成就感。
3. R语言-KNN算法
1、K最近邻(k-NearestNeighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
2、KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
3、KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成正比。
简言之,就是将未标记的案例归类为与它们最近相似的、带有标记的案例所在的类 。
原理及举例
工作原理:我们知道样本集中每一个数据与所属分类的对应关系,输入没有标签的新数据后,将新数据与训练集的数据对应特征进行比较,找出“距离”最近的k(通常k<20)数据,选择这k个数据中出现最多的分类作为新数据的分类。
算法描述
1、计算已知数据集中的点与当前点的距离
2、按距离递增次序排序
3、选取与当前数据点距离最近的K个点
4、确定前K个点所在类别出现的频率
5、返回频率最高的类别作为当前类别的预测
距离计算方法有"euclidean"(欧氏距离),”minkowski”(明科夫斯基距离), "maximum"(切比雪夫距离), "manhattan"(绝对值距离),"canberra"(兰式距离), 或 "minkowski"(马氏距离)等
Usage
knn(train, test, cl, k = 1, l = 0, prob =FALSE, use.all = TRUE)
Arguments
train
matrix or data frame of training set cases.
test
matrix or data frame of test set cases. A vector will be interpreted as a row vector for a single case.
cl
factor of true classifications of training set
k
number of neighbours considered.
l
minimum vote for definite decision, otherwisedoubt. (More precisely, less thank-ldissenting votes are allowed, even
ifkis increased by ties.)
prob
If this is true, the proportion of the votes for the
winning class are returned as attributeprob.
use.all
controls handling of ties. If true, all distances equal
to thekth largest are
included. If false, a random selection of distances equal to thekth is chosen to use exactlykneighbours.
kknn(formula = formula(train), train, test, na.action = na.omit(), k = 7, distance = 2, kernel = "optimal", ykernel = NULL, scale=TRUE, contrasts = c('unordered' = "contr.mmy", ordered = "contr.ordinal"))
参数:
formula A formula object.
train Matrix or data frame of training set cases.
test Matrix or data frame of test set cases.
na.action A function which indicates what should happen when the data contain ’NA’s.
k Number of neighbors considered.
distance Parameter of Minkowski distance.
kernel Kernel to use. Possible choices are "rectangular" (which is standard unweighted knn), "triangular", "epanechnikov" (or beta(2,2)), "biweight" (or beta(3,3)), "triweight" (or beta(4,4)), "cos", "inv", "gaussian", "rank" and "optimal".
ykernel Window width of an y-kernel, especially for prediction of ordinal classes.
scale Logical, scale variable to have equal sd.
contrasts A vector containing the ’unordered’ and ’ordered’ contrasts to use
kknn的返回值如下:
fitted.values Vector of predictions.
CL Matrix of classes of the k nearest neighbors.
W Matrix of weights of the k nearest neighbors.
D Matrix of distances of the k nearest neighbors.
C Matrix of indices of the k nearest neighbors.
prob Matrix of predicted class probabilities.
response Type of response variable, one of continuous, nominal or ordinal.
distance Parameter of Minkowski distance.
call The matched call.
terms The ’terms’ object used.
iris%>%ggvis(~Length,~Sepal.Width,fill=~Species)
library(kknn)
data(iris)
dim(iris)
m<-(dim(iris))[1]
val<-sample(1:m,size=round(m/3),replace=FALSE,prob=rep(1/m,m))
建立训练数据集
data.train<-iris[-val,]
建立测试数据集
data.test<-iris[val,]
调用kknn 之前首先定义公式
formula : Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width
iris.kknn<-kknn(Species~.,iris.train,iris.test,distance=1,kernel="triangular")
summary(iris.kknn)
# 获取fitted.values
fit <- fitted(iris.kknn)
# 建立表格检验判类准确性
table(iris.valid$Species, fit)
# 绘画散点图,k-nearest neighbor用红色高亮显示
pcol <- as.character(as.numeric(iris.valid$Species))
pairs(iris.valid[1:4], pch = pcol, col = c("green3", "red")[(iris.valid$Species != fit)+1]
二、R语言knn算法
install.packages("class")
library(class)
对于新的测试样例基于距离相似度的法则,确定其K个最近的邻居,在K个邻居中少数服从多数
确定新测试样例的类别
1、获得数据
2、理解数据
对数据进行探索性分析,散点图
如上例
3、确定问题类型,分类数据分析
4、机器学习算法knn
5、数据处理,归一化数据处理
normalize <- function(x){
num <- x - min(x)
denom <- max(x) - min(x)
return(num/denom)
}
iris_norm <-as.data.frame(lapply(iris[,1:4], normalize))
summary(iris_norm)
6、训练集与测试集选取
一般按照3:1的比例选取
方法一、set.seed(1234)
ind <- sample(2,nrow(iris), replace=TRUE, prob=c(0.67, 0.33))
iris_train <-iris[ind==1, 1:4]
iris_test <-iris[ind==2, 1:4]
train_label <-iris[ind==1, 5]
test_label <-iris[ind==2, 5]
方法二、
ind<-sample(1:150,50)
iris_train<-iris[-ind,]
iris_test<-iris[ind,1:4]
iris_train<-iris[-ind,1:4]
train_label<-iris[-ind,5]
test_label<-iris[ind,5]
7、构建KNN模型
iris_pred<-knn(train=iris_train,test=iris_test,cl=train_label,k=3)
8、模型评价
交叉列联表法
table(test_label,iris_pred)
实例二
数据集
http://archive.ics.uci.e/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data
导入数据
dir <-'http://archive.ics.uci.e/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data'wdbc.data <-read.csv(dir,header = F)
names(wdbc.data) <- c('ID','Diagnosis','radius_mean','texture_mean','perimeter_mean','area_mean','smoothness_mean','compactness_mean','concavity_mean','concave points_mean','symmetry_mean','fractal dimension_mean','radius_sd','texture_sd','perimeter_sd','area_sd','smoothness_sd','compactness_sd','concavity_sd','concave points_sd','symmetry_sd','fractal dimension_sd','radius_max_mean','texture_max_mean','perimeter_max_mean','area_max_mean','smoothness_max_mean','compactness_max_mean','concavity_max_mean','concave points_max_mean','symmetry_max_mean','fractal dimension_max_mean')
table(wdbc.data$Diagnosis)## M = malignant, B = benign
wdbc.data$Diagnosis <- factor(wdbc.data$Diagnosis,levels =c('B','M'),labels = c(B ='benign',M ='malignant'))
4. KNN 算法-理论篇-如何给电影进行分类
KNN 算法 的全称是 K-Nearest Neighbor ,中文为 K 近邻 算法,它是基于 距离 的一种算法,简单有效。
KNN 算法 即可用于分类问题,也可用于回归问题。
假如我们统计了一些 电影数据,包括电影名称,打斗次数,接吻次数,电影类型 ,如下:
可以看到,电影分成了两类,分别是动作片和爱情片。
如果现在有一部新的电影A,它的打斗和接吻次数分别是80 和7,那如何用KNN 算法对齐进行分类呢?
我们可以将打斗次数作为 X 轴 ,接吻次数作为 Y 轴 ,将上述电影数据画在一个坐标系中,如下:
通过上图可以直观的看出,动作电影与爱情电影的分布范围是不同的。
KNN 算法 基于距离,它的原理是: 选择与待分类数据最近的K 个点,这K 个点属于哪个分类最多,那么待分类数据就属于哪个分类 。
所以,要判断电影A 属于哪一类电影,就要从已知的电影样本中,选出距离电影A 最近的K 个点:
比如,我们从样本中选出三个点(即 K 为 3),那么距离电影A 最近的三个点是《功夫》,《黑客帝国》和《战狼》,而这三部电影都是动作电影。因此,可以判断电影A 也是动作电影。
另外,我们还要处理两个问题:
关于点之间的距离判断,可以参考文章 《计算机如何理解事物的相关性》 。
至于K 值的选择,K 值较大或者较小都会对模型的训练造成负面影响,K 值较小会造成 过拟合 ,K 值较大 欠拟合 。
因此,K 值的选择,一般采用 交叉验证 的方式。
交叉验证的思路是,把样本集中的大部分样本作为训练集,剩余部分用于预测,来验证分类模型的准确度。一般会把 K 值选取在较小范围内,逐一尝试K 的值,当模型准确度最高时,就是最合适的K 值。
可以总结出, KNN 算法 用于分类问题时,一般的步骤是:
如果,我们现在有一部电影B,知道该电影属于动作电影,并且知道该电影的接吻次数是 7 ,现在想预测该电影的打斗次数是多少?
这个问题就属于 回归问题 。
首先看下,根据已知数据,如何判断出距离电影B 最近的K 个点。
我们依然设置K 为3,已知数据为:
根据已知数据可以画出下图:
图中我画出了一条水平线,这条线代表所有接吻次数是7 的电影,接下来就是要找到距离 这条线 最近的三部(K 为 3)动作电影。
可以看到,距离这条水平线最近的三部动作电影是《功夫》,《黑客帝国》和《战狼》,那么这三部电影的打斗次数的平均值,就是我们预测的电影B 的打斗次数。
所以,电影B 的打斗次数是:
本篇文章主要介绍了 KNN 算法 的基本原理,它简单易懂,即可处理分类问题,又可处理回归问题。
KNN 算法 是基于 距离 的一种机器学习算法,需要计算测试点与样本点之间的距离。因此,当数据量大的时候,计算量就会非常庞大,需要大量的存储空间和计算时间。
另外,如果样本数据分类不均衡,比如有些分类的样本非常少,那么该类别的分类准确率就会很低。因此,在实际应用中,要特别注意这一点。
(本节完。)
推荐阅读:
决策树算法-理论篇-如何计算信息纯度
决策树算法-实战篇-鸢尾花及波士顿房价预测
朴素贝叶斯分类-理论篇-如何通过概率解决分类问题
朴素贝叶斯分类-实战篇-如何进行文本分类
计算机如何理解事物的相关性-文档的相似度判断
5. 大数据算法:分类算法
KNN算法,即K近邻(K Nearest Neighbour)算法,是一种基本的分类算法。其主要原理是:对于一个需要分类的数据,将其和一组已经分类标注好的样本集合进行比较,得到距离最近的K个样本,K个样本最多归属的类别,就是这个需要分类数据的类别。下面我给你画了一个KNN算法的原理图。
图中,红蓝绿三种颜色的点为样本数据,分属三种类别 、 、 。对于待分类点 ,计算和它距离最近的5个点(即K为5),这5个点最多归属的类别为 (4个点归属 ,1个点归属 ),那么 的类别被分类为 。
KNN的算法流程也非常简单,请看下面的流程图。
KNN算法是一种非常简单实用的分类算法,可用于各种分类的场景,比如新闻分类、商品分类等,甚至可用于简单的文字识别。对于新闻分类,可以提前对若干新闻进行人工标注,标好新闻类别,计算好特征向量。对于一篇未分类的新闻,计算其特征向量后,跟所有已标注新闻进行距离计算,然后进一步利用KNN算法进行自动分类。
读到这你肯定会问,如何计算数据的距离呢?如何获得新闻的特征向量呢?
KNN算法的关键是要比较需要分类的数据与样本数据之间的距离,这在机器学习中通常的做法是:提取数据的特征值,根据特征值组成一个n维实数向量空间(这个空间也被称作特征空间),然后计算向量之间的空间距离。空间之间的距离计算方法有很多种,常用的有欧氏距离、余弦距离等。
对于数据 和 ,若其特征空间为n维实数向量空间 ,即 , ,则其欧氏距离计算公式为
这个欧式距离公式其实我们在初中的时候就学过,平面几何和立体几何里两个点之间的距离,也是用这个公式计算出来的,只是平面几何(二维几何)里的n=2,立体几何(三维几何)里的n=3,而机器学习需要面对的每个数据都可能有n维的维度,即每个数据有n个特征值。但是不管特征值n是多少,两个数据之间的空间距离的计算公式还是这个欧氏计算公式。大多数机器学习算法都需要计算数据之间的距离,因此掌握数据的距离计算公式是掌握机器学习算法的基础。
欧氏距离是最常用的数据计算公式,但是在文本数据以及用户评价数据的机器学习中,更常用的距离计算方法是余弦相似度。
余弦相似度的值越接近1表示其越相似,越接近0表示其差异越大,使用余弦相似度可以消除数据的某些冗余信息,某些情况下更贴近数据的本质。我举个简单的例子,比如两篇文章的特征值都是:“大数据”“机器学习”和“极客时间”,A文章的特征向量为(3, 3, 3),即这三个词出现次数都是3;B文章的特征向量为(6, 6, 6),即这三个词出现次数都是6。如果光看特征向量,这两个向量差别很大,如果用欧氏距离计算确实也很大,但是这两篇文章其实非常相似,只是篇幅不同而已,它们的余弦相似度为1,表示非常相似。
余弦相似度其实是计算向量的夹角,而欧氏距离公式是计算空间距离。余弦相似度更关注数据的相似性,比如两个用户给两件商品的打分分别是(3, 3)和(4, 4),那么两个用户对两件商品的喜好是相似的,这种情况下,余弦相似度比欧氏距离更合理。
我们知道了机器学习的算法需要计算距离,而计算距离需要还知道数据的特征向量,因此提取数据的特征向量是机器学习工程师们的重要工作,有时候甚至是最重要的工作。不同的数据以及不同的应用场景需要提取不同的特征值,我们以比较常见的文本数据为例,看看如何提取文本特征向量。
文本数据的特征值就是提取文本关键词,TF-IDF算法是比较常用且直观的一种文本关键词提取算法。这种算法是由TF和IDF两部分构成。
TF是词频(Term Frequency),表示某个单词在文档中出现的频率,一个单词在一个文档中出现的越频繁,TF值越高。
词频:
IDF是逆文档频率(Inverse Document Frequency),表示这个单词在所有文档中的稀缺程度,越少文档出现这个词,IDF值越高。
逆文档频率:
TF与IDF的乘积就是TF-IDF。
所以如果一个词在某一个文档中频繁出现,但在所有文档中却很少出现,那么这个词很可能就是这个文档的关键词。比如一篇关于原子能的技术文章,“核裂变”“放射性”“半衰期”等词汇会在这篇文档中频繁出现,即TF很高;但是在所有文档中出现的频率却比较低,即IDF也比较高。因此这几个词的TF-IDF值就会很高,就可能是这篇文档的关键词。如果这是一篇关于中国原子能的文章,也许“中国”这个词也会频繁出现,即TF也很高,但是“中国”也在很多文档中出现,那么IDF就会比较低,最后“中国”这个词的TF-IDF就很低,不会成为这个文档的关键词。
提取出关键词以后,就可以利用关键词的词频构造特征向量,比如上面例子关于原子能的文章,“核裂变”“放射性”“半衰期”这三个词是特征值,分别出现次数为12、9、4。那么这篇文章的特征向量就是(12, 9, 4),再利用前面提到的空间距离计算公式计算与其他文档的距离,结合KNN算法就可以实现文档的自动分类。
贝叶斯公式是一种基于条件概率的分类算法,如果我们已经知道A和B的发生概率,并且知道了B发生情况下A发生的概率,可以用贝叶斯公式计算A发生的情况下B发生的概率。事实上,我们可以根据A的情况,即输入数据,判断B的概率,即B的可能性,进而进行分类。
举个例子:假设一所学校里男生占60%,女生占40%。男生总是穿长裤,女生则一半穿长裤一半穿裙子。假设你走在校园中,迎面走来一个穿长裤的学生,你能够推断出这个穿长裤学生是男生的概率是多少吗?
答案是75%,具体算法是:
这个算法就利用了贝叶斯公式,贝叶斯公式的写法是:
意思是A发生的条件下B发生的概率,等于B发生的条件下A发生的概率,乘以B发生的概率,除以A发生的概率。还是上面这个例子,如果我问你迎面走来穿裙子的学生是女生的概率是多少。同样带入贝叶斯公式,可以计算出是女生的概率为100%。其实这个结果我们根据常识也能推断出来,但是很多时候,常识受各种因素的干扰,会出现偏差。比如有人看到一篇博士生给初中学历老板打工的新闻,就感叹读书无用。事实上,只是少见多怪,样本量太少而已。而大量数据的统计规律则能准确反映事物的分类概率。
贝叶斯分类的一个典型的应用场合是垃圾邮件分类,通过对样本邮件的统计,我们知道每个词在邮件中出现的概率 ,我们也知道正常邮件概率 和垃圾邮件的概率 ,还可以统计出垃圾邮件中各个词的出现概率 ,那么现在一封新邮件到来,我们就可以根据邮件中出现的词,计算 ,即得到这些词出现情况下,邮件为垃圾邮件的概率,进而判断邮件是否为垃圾邮件。
现实中,贝叶斯公式等号右边的概率,我们可以通过对大数据的统计获得,当有新的数据到来的时候,我们就可以带入上面的贝叶斯公式计算其概率。而如果我们设定概率超过某个值就认为其会发生,那么我们就对这个数据进行了分类和预测,具体过程如下图所示。
训练样本就是我们的原始数据,有时候原始数据并不包含我们想要计算的维度数据,比如我们想用贝叶斯公式自动分类垃圾邮件,那么首先要对原始邮件进行标注,需要标注哪些邮件是正常邮件、哪些邮件是垃圾邮件。这一类需要对数据进行标注才能进行的机器学习训练也叫作有监督的机器学习。
6. 01 KNN算法 - 概述
KNN算法 全称是K近邻算法 (K-nearst neighbors,KNN)
KNN是一种基本的机器学习算法,所谓K近邻,就是k个最近的邻居。即每个样本都可以用和它 最接近的k个邻近位置的样本 来代替。
KNN是个相对比较简单的算法,比起之前提过的回归算法和分类算法更容易。如果一个人从来没有接触过机器学习的算法,拿到数据后最容易想到的分类方式就是K近邻。打个比方:你们想了解我是个怎样的人,然后你们发现我的身边关系最密切的朋友是一群逗逼,所以你们可以默认我也是一个逗逼。
KNN算法即可以应用于 分类算法 中,也可以应用于 回归算法 中。
KNN在做回归和分类的主要区别,在于最后做预测时候的决策不同。在分类预测时,一般采用 多数表决法 。在做回归预测时,一般使用 平均值法 。
多数表决法: 分类时,哪些样本离我的目标样本比较近,即目标样本离哪个分类的样本更接近。
平均值法: 预测一个样本的平均身高,观察目标样本周围的其他样本的平均身高,我们认为平均身高是目标样本的身高。
再举个例子:
分别根据甜度和脆度两个特征来判断食物的种类。
根据样本我们普遍发现:
比较甜,比较脆的食物都是水果。
不甜,不太脆的食物是蛋白质。
不甜,比较脆的食物是蔬菜。
于是根据目标的样本甜度和脆度两个特征,我们可以对其进行分类了。
k值的选择:
先选一个较小的值,然后通过交叉验证选择一个合适的最终值。
k越小,即使用较小的领域中的样本进行预测,训练误差会减小,但模型会很复杂,以至于过拟合。
k越大,即使用交大的领域中的样本进行预测,训练误差会增大,模型会变得简单,容易导致欠拟合。
距离的度量:
使用欧几里得距离:欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。
决策规划:
分类:多数表决法、加权多数表决法。
回归:平均值法、加权平均值法。
加权多数表决法:
平均值法和加权平均值法:
同样看上面的图,上方的三个样本值为3,下面两个样本值为2,预测?的值。
如果不考虑加权,直接计算平均值:
(3 * 3 + 2 * 2) / 5 = 2.6
加权平均值:权重分别为1/7和2/7。计算加权平均值:
(3 * 3* 1/7 + 2 * 2 * 2/7) / 5 = 2.43
1、蛮力实现(brute):
计算预测样本到所有训练集样本的距离,然后选择最小的k个距离,即可得到k个最邻近点。
缺点:当特征数多、样本数多时,算法的效率比较低。
2、KD树 (kd_tree):
首先对训练数据进行建模,构建KD树,然后根据建好的模型来获取邻近样本数据。
后续内容会介绍KD树搜索最小值的方式,让大家直观感受到KD树比蛮力实现要少检索多少数据。
7. KNN算法-4-算法优化-KD树
KNN算法的重要步骤是对所有的实例点进行快速k近邻搜索。如果采用线性扫描(linear scan),要计算输入点与每一个点的距离,时间复杂度非常高。因此在查询操作时,可以使用kd树对查询操作进行优化。
Kd-树是K-dimension tree的缩写,是对数据点在k维空间(如二维(x,y),三维(x,y,z),k维(x1,y,z..))中划分的一种数据结构,主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。本质上说,Kd-树就是一种平衡二叉树。
k-d tree是每个节点均为k维样本点的二叉树,其上的每个样本点代表一个超平面,该超平面垂直于当前划分维度的坐标轴,并在该维度上将空间划分为两部分,一部分在其左子树,另一部分在其右子树。即若当前节点的划分维度为d,其左子树上所有点在d维的坐标值均小于当前值,右子树上所有点在d维的坐标值均大于等于当前值,本定义对其任意子节点均成立。
必须搞清楚的是,k-d树是一种空间划分树,说白了,就是把整个空间划分为特定的几个部分,然后在特定空间的部分内进行相关搜索操作。想象一个三维(多维有点为难你的想象力了)空间,kd树按照一定的划分规则把这个三维空间划分了多个空间,如下图所示:
首先,边框为红色的竖直平面将整个空间划分为两部分,此两部分又分别被边框为绿色的水平平面划分为上下两部分。最后此4个子空间又分别被边框为蓝色的竖直平面分割为两部分,变为8个子空间,此8个子空间即为叶子节点。
常规的k-d tree的构建过程为:
对于构建过程,有两个优化点:
例子:采用常规的构建方式,以二维平面点(x,y)的集合(2,3),(5,4),(9,6),(4,7),(8,1),(7,2) 为例结合下图来说明k-d tree的构建过程:
如上算法所述,kd树的构建是一个递归过程,我们对左子空间和右子空间内的数据重复根节点的过程就可以得到一级子节点(5,4)和(9,6),同时将空间和数据集进一步细分,如此往复直到空间中只包含一个数据点。
如之前所述,kd树中,kd代表k-dimension,每个节点即为一个k维的点。每个非叶节点可以想象为一个分割超平面,用垂直于坐标轴的超平面将空间分为两个部分,这样递归的从根节点不停的划分,直到没有实例为止。经典的构造k-d tree的规则如下:
kd树的检索是KNN算法至关重要的一步,给定点p,查询数据集中与其距离最近点的过程即为最近邻搜索。
如在构建好的k-d tree上搜索(3,5)的最近邻时,对二维空间的最近邻搜索过程作分析。
首先从根节点(7,2)出发,将当前最近邻设为(7,2),对该k-d tree作深度优先遍历。
以(3,5)为圆心,其到(7,2)的距离为半径画圆(多维空间为超球面),可以看出(8,1)右侧的区域与该圆不相交,所以(8,1)的右子树全部忽略。
接着走到(7,2)左子树根节点(5,4),与原最近邻对比距离后,更新当前最近邻为(5,4)。
以(3,5)为圆心,其到(5,4)的距离为半径画圆,发现(7,2)右侧的区域与该圆不相交,忽略该侧所有节点,这样(7,2)的整个右子树被标记为已忽略。
遍历完(5,4)的左右叶子节点,发现与当前最优距离相等,不更新最近邻。所以(3,5)的最近邻为(5,4)。
举例:查询点(2.1,3.1)
星号表示要查询的点(2.1,3.1)。通过二叉搜索,顺着搜索路径很快就能找到最邻近的近似点,也就是叶子节点(2,3)。而找到的叶子节点并不一定就是最邻近的,最邻近肯定距离查询点更近,应该位于以查询点为圆心且通过叶子节点的圆域内。为了找到真正的最近邻,还需要进行相关的‘回溯'操作。也就是说,算法首先沿搜索路径反向查找是否有距离查询点更近的数据点。
举例:查询点(2,4.5)
一个复杂点了例子如查找点为(2,4.5),具体步骤依次如下:
上述两次实例表明,当查询点的邻域与分割超平面两侧空间交割时,需要查找另一侧子空间,导致检索过程复杂,效率下降。
一般来讲,最临近搜索只需要检测几个叶子结点即可,如下图所示:
但是,如果当实例点的分布比较糟糕时,几乎要遍历所有的结点,如下所示:
研究表明N个节点的K维k-d树搜索过程时间复杂度为: 。
同时,以上为了介绍方便,讨论的是二维或三维情形。但在实际的应用中,如SIFT特征矢量128维,SURF特征矢量64维,维度都比较大,直接利用k-d树快速检索(维数不超过20)的性能急剧下降,几乎接近贪婪线性扫描。假设数据集的维数为D,一般来说要求数据的规模N满足N»2D,才能达到高效的搜索。
Sklearn中有KDTree的实现,仅构建了一个二维空间的k-d tree,然后对其作k近邻搜索及指定半径的范围搜索。多维空间的检索,调用方式与此例相差无多。