版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/keyue123/article/details/82876055
K近邻 (kNN) 算法是一种基本分类与回归方法,通俗的理解为给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的 k 个实例,这 k 个实例的多数属于某个类,就把该输入实例分为这个类。
-
经典描述
如下图,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形。如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。因此也说明了KNN算法的结果很大程度取决于K如何选择 -
原理
在KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,一般使用欧氏距离或曼哈顿距离:
欧氏距离:
曼哈顿距离:
假设有一个带有标签的样本数据集,其中包含每条数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,求 k 个数据中出现次数最多的分类标签作为新数据的分类。
-
开发流程
- 计算新数据与样本数据集中每条数据的距离。
- 对求得的所有距离进行排序(从小到大,越小表示越相似)。
- 取前 k (k <= 20 ) 个样本数据对应的分类标签。
-
约会经典案例
海伦使用约会网站寻找约会对象。经过一段时间之后,她发现曾交往过三种类型的人: 不喜欢的人,魅力一般的人,极具魅力的人
她希望: 1. 工作日与魅力一般的人约会 2. 周末与极具魅力的人约会 3. 不喜欢的人则直接排除掉
- 搜集数据
海伦把这些约会对象的数据存放在文本文件 datingTestSet2.txt 中,总共有 1000 行。海伦约会的对象主要包含以下 3 种特征:
每年获得的飞行常客里程数
玩视频游戏所耗时间百分比
每周消费的冰淇淋公升数
文本文件数据格式如下:
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
38344 1.669788 0.134296 1
- 准备数据
def file2matrix(filename):
fr = open(filename) #打开数据集
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines) #获取数据集行数
returnMat = zeros((numberOfLines, 3)) #创建空矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t') #获取每列的属性数据
returnMat[index, :] = listFromLine[0: 3] #将前三列数据存入矩阵中
classLabelVector.append(int(listFromLine[-1])) #获取最后一列数据
index += 1
return returnMat, classLabelVector
- 数据归一化
归一化特征值就是要把需要处理的数据经过处理后限制在一定范围内,主要是为了消除特征之间量级不同导致的影响。我们一般使用最大最小值规格化的方法:
例:某公司工资水平在12000~98000之间,映射到(0, 1),某员工工资为73600,则:
def autoNorm(dataSet):
minVals = dataSet.min(0) #返回矩阵每一列的最小值
maxVals = dataSet.max(0) #返回矩阵每一列的最大值
ranges = maxVals - minVals #获取范围
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m, 1)) #生成与最小值之差组成的矩阵
normDataSet = normDataSet/tile(ranges, (m, 1)) #归一化
return normDataSet, ranges, minVals
- KNN算法
对于数据集中的数据:
1. 计算目标的数据与该数据的距离
2. 距离排序:从小到大
3. 选取前K个最短距离
4. 选取这K个中最多的类别
5. 返回该类别来作为目标数据点的预测值
def classify(input, dataSet, label, k):
#1. 计算目标的数据与该数据的距离
dataSize = dataSet.shape[0]
diff = tile(input, (dataSize, 1)) - dataSet
sqdiff = diff ** 2
squareDist = sum(sqdiff, axis=1) #行向量分别相加
dist = squareDist ** 0.5 #计算欧式距离
#2. 排序
sortedDistIndex = argsort(dist)
#3. 选取前K个最短距离
classCount = {}
for i in range(k):
voteLabel = label[sortedDistIndex[i]]
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1 #选取前K个最小距离
#4. 选取这K个中最多的类别
maxCount = 0
for key, value in classCount.items(): #选取出现的类别次数最多的类别
if value > maxCount:
maxCount = value
classes = key
#5. 返回该类别来作为目标数据点的预测值
return classes
- 测试与结果
if __name__ == '__main__':
resultList = [u'不喜欢', u'魅力一般', u'极具魅力']
percentTats = float(input(u"玩视频游戏所耗时间百分比:"))
ffMiles = float(input(u"每年获得的飞行常客里程数:"))
iceCream = float(input(u"每周消费的冰淇淋公升数:"))
datingDataMat, datingLabels = file2matrix('C:\\Users\\John\\Desktop\\DataBooks\\MachineLearning\\Ch02\\datingTestSet2.txt')#导入并处理数据
normMat, ranges, minVals = autoNorm(datingDataMat) #数据归一化
inArr = array([ffMiles, percentTats, iceCream])
classifierResult = classify((inArr-minVals)/ranges, normMat, datingLabels, 3) #分类
print("对此人感觉: ", resultList[classifierResult - 1])
海伦最后能根据输入的条件来预测对这个约会对象的感觉,从而决定是否或者何时约会。这就是一个完整的KNN流程。
4. 代码分析
K近邻代码分析