KNN算法概述
kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成反比。
对于分类问题:输出为实例的类别。分类时,对于新的实例,根据其k个最近邻的训练的实例类别,通过多数表决等方式进行预测
对于回归问题:输出为实例的值。回归时,对于新的实例,取其k个最近邻的训练实例的平均值作为与预测值
KNN算法原理
KNN是通过测量不同特征值之间的距离进行分类。它的的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
在KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,在这里距离一般使用欧氏距离或曼哈顿距离:
同时,KNN通过依据k个对象中占优的类别进行决策,而不是单一的对象类别决策。这两点就是KNN算法的优势。
KNN算法具体描述
就是在训练集中数据和标签已知的情况下,输入测试数据,将测试数据的特征与训练集中对应的特征进行相互比较,找到训练集中与之最为相似的前K个数据,则该测试数据对应的类别就是K个数据中出现次数最多的那个分类,其算法的描述为:
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。
KNN算法的优缺点
优点
思想简单,能做分类和回归
惰性学习,无需训练(蛮力法),KD树的话,则需要建树
对异常点不敏感
缺点
计算量大、速度慢
样本不平衡的时候,对稀有类别的预测准确率低
KD树,球树之类的模型建立需要大量的内存
相比决策树模型,KNN模型可解释性不强
KNN算法中的超参数
KNN分类KNeighborsClassifier
n_neighbors:指定的k的值(整数,python默认是5)
weights:字符串或者可调用的对象,指定投票权重类型。即这些邻居投票权可以相同或者不同。
‘uniform’:本节点所有邻居姐点的投票权重都相等(python默认weights=’uniform’)
‘distance’:本节点的所有邻居节点的投票权重与距离成反比。即越近的距离权重越大。
algorithm:一个字符串,指定计算最近邻的算法,可以选择如下:
‘ball_tree’:使用BallTree算法
‘kd_tree’:使用KDTree算法
‘brute’:使用暴力搜索法
‘auto’:自动决定最合适的算法
Leaf_size:一个整数,指定BallTree 或者KDTree叶节点规模。他影响树的构建和查询。
metric:一个字符串,指定距离度量。默认为‘minkowski’距离
p:指数值,指定在’Minkowski’度量上的指数。如果p=1,对应曼哈顿距离;如果p=2对应欧氏距离
n_jobs:并行性,默认为-1,表示派发任务到所有计算机的CPU上
方法:
fit(X,y):训练模型
predict(X):使用模型来预测,返回预测样本的标记
score(X,y):返回在(X,y)上预测的准确率
predict_proba(X):返回样本为每种标记的概率
kneighbors([X,n_neighbors,return_distance]):返回样本点的k紧邻点。如果return_distance=True,同时返回到这些紧邻点的距离
kneighbors_graph([X,n_neighbors,mode]):返回样本点的连接图
KNN回归KNeighborsRegressor
n_neighbors:指定的k的值(整数,python默认是5)
weights:字符串或者可调用的对象,指定投票权重类型。即这些邻居投票权可以相同或者不同。
‘uniform’:本节点所有邻居姐点的投票权重都相等(python默认weights=’uniform’)
‘distance’:本节点的所有邻居节点的投票权重与距离成反比。即越近的距离权重越大。
algorithm:一个字符串,指定计算最近邻的算法,可以选择如下:
‘ball_tree’:使用BallTree算法
‘kd_tree’:使用KDTree算法
‘brute’:使用暴力搜索法
‘auto’:自动决定最合适的算法
Leaf_size:一个整数,指定BallTree 或者KDTree叶节点规模。他影响树的构建和查询。
metric:一个字符串,指定距离度量。默认为‘minkowski’距离
p:指数值,指定在’Minkowski’度量上的指数。如果p=1,对应曼哈顿距离;如果p=2对应欧氏距离
n_jobs:并行性,默认为-1,表示派发任务到所有计算机的CPU上
方法:
fit(X,y):训练模型
predict(X):使用模型来预测,返回预测样本的标记
kneighbors([X,n_neighbors,return_distance]):返回样本点的k紧邻点。如果return_distance=True,同时返回到这些紧邻点的距离
kneighbors_graph([X,n_neighbors,mode]):返回样本点的连接图
其参数意义以及实例方法与KNeighborsClassifier几乎完全相同。两者区别在于回归分析与分类决策的不同
KNeighborsClassifier将待测样本最近邻的k个训练样本点出现次数最多的分类作为带预测样本点的分类。
KNeighborsRegressor将待测样本最近邻的k个训练样本点的平均值作为待预测样本点的值
KNN算法小案例展示
※KNN模型需要进行特征标准化,目的是为了防止受到数量级大的特征的主导
等权分类
T = [[3, 104, 0],
[2, 100, 0],
[1, 81, 0],
[101, 10, 1],
[99, 5, 1],
[98, 2, 1]]
x = [18, 90]
K = 3
dis = []
from math import sqrt
for i in T:
d = sqrt((x[0]-i[0])**2 + (x[1]-i[1])**2)
dis.append([d, i[2]])
dis.sort()
print(dis)
box = [i[1] for i in dis[0:K]]
print(1 if sum(box)>K/2 else 0)
带权分类
T = [[3, 104, -1],
[2, 100, -1],
[1, 81, -1],
[101, 10, 1],
[99, 5, 1],
[98, 2, 1]]
x = [18, 90]
K = 5
dis = []
from math import sqrt
for i in T:
d = sqrt((x[0]-i[0])**2 + (x[1]-i[1])**2)
dis.append([d, i[2]])
dis.sort()
print(-1 if sum([1/i[0]*i[1] for i in dis[:K]])<0 else 1)
等权回归
T = [[3, 104, 98],
[2, 100, 93],
[1, 81, 95],
[101, 10, 16],
[99, 5, 8],
[98, 2, 7]]
x = [18, 90]
K = 5
dis = []
from math import sqrt
for i in T:
d = sqrt((x[0]-i[0])**2 + (x[1]-i[1])**2)
dis.append([d, i[2]])
dis.sort()
带权回归
T = [
[3, 104, 98],
[2, 100, 93],
[1, 81, 95],
[101, 10, 16],
[99, 5, 8],
[98, 2, 7]
]
x = [18, 90]
K = 4
dis = []
for i in T:
d = (x[0]-i[0])**2 + (x[1]-i[1])**2
dis.append([pow(d,1/2), i[2]])
dis.sort(key=lambda x:x[0])
dis = [[1/i[0],i[1]] for i in dis][0:K]
a = 1 / sum([i[0] for i in dis])
res = sum([i[0]*i[1] for i in dis])
print(res*a)