kNN模型的三要素

从前面讲解的kNN模型做分类和回归任务,我们可以看出kNN有三个元素非常重要:距离度量、k的选择和分类规则。


距离度量

在选择两个实例的相似性时,一般使用用欧氏距离,可以根据具体情况选择不同的距离度量方式。一般,距离越短,相似程度越高,反之,相似程度越低。

常用的距离度量:

闵可夫斯基距离:一类距离的定义

对于对于n维空间中的两个点X(ncnn模型在线转换 knn模型_ci,ncnn模型在线转换 knn模型_ncnn模型在线转换_02,...,ncnn模型在线转换 knn模型_距离度量_03)和Y(ncnn模型在线转换 knn模型_距离度量_04,ncnn模型在线转换 knn模型_ci_05,...,ncnn模型在线转换 knn模型_机器学习_06),x和y之间的闵可夫斯基距离可表示为:ncnn模型在线转换 knn模型_ncnn模型在线转换_07=

ncnn模型在线转换 knn模型_数组_08

其中,p是一个可变参数:

当p=1时,被称为曼哈顿距离;

当p=2时,被称为欧式距离

当p=∞时,被称为切比雪夫距离


k的选择

如果k值较小,相当于在一个较小的领域中进行预测,预测结果对邻近点十分敏感,容易产生过拟合;如果k值过大,相当于在一个较大的邻域中进行预测,与预测实例不相似的点也会对预测结果产生影响,容易产生欠拟合。

k最好选择奇数,因为后续进行归类的策略是少数服从多数,防止平局。

所以,在应用中,k一般采用交叉验证来选取最优的k值,代码~

# 导包
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV # 网格搜索
from sklearn.model_selection import train_test_split # 将数据集分为训练集和测试集

#加载数据
iris = datasets.load_iris()
x = iris.data
y = iris.target

#切分数据
train_x,test_x,train_y,test_y = train_test_split(x,y,test_size=0.2,random_state=42)

parameters = {'n_neighbors':[1,3,5,7,9,11,13,15]}
knn = KNeighborsClassifier()

clf = GridSearchCV(knn,parameters,cv=5)
clf.fit(train_x,train_y)

print('最终最佳准确率:%.2f'%clf.best_score_,'最终最佳的k值',clf.best_params_)

结果:

ncnn模型在线转换 knn模型_距离度量_09


分类规则

少数服从多数

from collections import Counter # 投票,注意只能用于interger类型的数据的投票
def classify0(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]#查看矩阵的维度
    diffMat = tile(inX,(dataSetSize,1)) - dataSet
    #tile(数组,(在行上重复次数,在列上重复次数))
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    #sum默认axis=0,是普通的相加,axis=1是将一个矩阵的每一行向量相加
    sortedDistIndicies = distances.argsort()
    #sort函数按照数组值从小到大排序
    #argsort函数返回的是数组值从小到大的索引值
    '''
    classCount={}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
        #get(key,k),当字典dic中不存在key时,返回默认值k;存在时返回key对应的值
    sortedClassCount = sorted(classCount.items(),
           key=operator.itemgetter(1),reverse=True)
    #python2中用iteritems,python3中用items代替;operator.itemgetter(k),返回第k个域的值
    return sortedClassCount[0][0]
    
    '''
    # 简化上面计数的代码
    index = sortedDistIndicies[:k]
    count = Counter(labels[index])
    return count.most_common()[0][0] # 少数服从多数

总结

kNN算法收尾~

欢迎交流~