一、k-近邻算法原理
为了判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数的投票法则,将未知样本与K个最邻近样本中所属类别占比较多的归为一类。
KNN的原理就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别。
二、点距离的计算
通常使用的距离函数有:欧氏距离、余弦距离、汉明距离、曼哈顿距离等,一般选欧氏距离作为距离度量,但是这是只适用于连续变量。
![]()
这里的p值是一个变量,
当p=1的时候就得到了 曼哈顿距离 ;
当p=2的时候就得到了欧氏距离。
三、k值的选择
如果 K 值比较小,就相当于未分类物体与它的邻居非常接近才行。这样产生的一个问题就是,如果邻居点是个噪声点,那么未分类物体的分类也会产生误差,这样 KNN 分类就会产生过拟合。
如果 K 值比较大,相当于距离过远的点也会对未知物体的分类产生影响,虽然这种情况的好处是鲁棒性强,但是不足也很明显,会产生欠拟合情况,也就是没有把未分类物体真正分类出来。一般采用交叉验证的方式选取 K 值。交叉验证的思路就是,把样本集中的大部分样本作为训练集,剩余的小部分样本用于预测,来验证分类模型的准确性。
四、举例
此案例参考b站上一位博主的讲解~~~~~
预测打斗100次,接吻5次的电影是什么电影类型
代码实现
import operator import numpy as np #设计knn算法,利用欧拉公式计算最短距离 def knn(trainDate, testData, labels, k): # print(trainDate) # print(testData) # 将测试数据转为和训练集相同形状,tile函数的作用使矩阵行数和列上复制相应的份额,是倍数的关系 testData=np.tile(testData,(trainDate.shape[0],1)) # 利用欧拉公式计算距离 tempData=(testData-trainDate)**2 # 将计算的矩阵跨列相加 tempData=tempData.sum(axis=1) tempData=tempData**0.5 print(tempData) # 对距离进行从小到大排序,返回的是数组的索引值 sortData=np.argsort(tempData) # 统计前k个的类型数量 count={} for i in range(k): # 取出下标对应的类型 vote=labels[sortData[i]] # 字典中 的get方法返回指定键的值,如果键不在字典中返回默认值0 count[vote]=count.get(vote,0)+1 # 按照字典中对象的第二个元素降序排列,返回list sortNewData=sorted(count.items(),key=operator.itemgetter(1),reverse=True) return sortNewData[0][0] # 训练数据 trainData = np.array([ [115, 6], [109, 8], [120, 9], [5, 78], [6, 60], [8, 69] ]) # 训练数据对用的标签 labels = np.array(['动作片', '动作片', '动作片', '爱情片', '爱情片', '爱情片']) # 测试数据 testData = np.array([100, 5]) print(knn(trainData, testData, labels, 3))
五、预测毕业生的薪资等级
自定义的数据集,可能会存在一些问题,有错误请多多包涵~~~~
professional:专业编号;gender:性别(1:男;0:女);age:年龄;socialSkill:社交能力;professionalSkill:专业能力;
isJob:薪资等级标签
csv中各个属性的直方图表示
import operator import numpy as np import pandas as pd from matplotlib import pyplot as plt from sklearn import preprocessing from sklearn.model_selection import train_test_split from sklearn import metrics def knn(trainDate, testData, labels, k): # print(trainDate) # print(testData) # 将测试数据转为和训练集相同形状,tile函数的作用使矩阵行数和列上复制相应的份额,是倍数的关系 testData = np.tile(testData, (trainDate.shape[0], 1)) # 利用欧拉公式计算距离 tempData = (testData - trainDate) ** 2 # 将计算的矩阵跨列相加 tempData = tempData.sum(axis=1) tempData = tempData ** 0.5 # print(tempData) # 对距离进行从小到大排序,返回的是数组的索引值 sortData = np.argsort(tempData) # 统计前k个的类型数量 count = {} for i in range(k): # 取出下标对应的类型 vote = labels[sortData[i]] # 字典中 的get方法返回指定键的值,如果键不在字典中返回默认值0 count[vote] = count.get(vote, 0) + 1 # 按照字典中对象的第二个元素降序排列,返回list sortNewData = sorted(count.items(), key=operator.itemgetter(1), reverse=True) return sortNewData[0][0] data = pd.read_csv('movie.csv') # 将 Pandas 数据框转换为 Numpy 数组 X = data[['professional', 'gender', 'age', 'socialSkill', 'professionalSkill']].values print(X[0:5]) # 标签 y = data['isJob'].values print(y[0:5]) # 标准化数据,利用到了sklearn库函数标准化的方法 X = preprocessing.StandardScaler().fit_transform(X.astype(float)) print(X[0:5]) # 利用到了sklearn库函数标准化的方法,划分数据集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=4) print('Train set:', X_train.shape, y_train.shape) print('Test set:', X_test.shape, y_test.shape) # 绘制直方图 data.hist(bins=100) plt.show() x_predict = [] for item in X_test: temp = knn(X_train, item, y_train, 1) x_predict.append(temp) print(y_test) print(x_predict) print("Train set Accuracy: ", metrics.accuracy_score(y_test, x_predict)) # print("Test set Accuracy: ", metrics.accuracy_score(y_test, ))
k=2
k=3
k=4
k=5
k=6
k的大小取值对精准率的影响不大,可能存在的原因是样本的自己制作的样本出现了一些不准确。在绘制样本的时候采用了excel的随机函数,比较不利于比较精确率。