社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  机器学习算法

机器学习实战之KNN算法

Python中文社区 • 5 年前 • 461 次点击  

本系列教程为《机器学习实战》的读书笔记。首先,讲讲写本系列教程的原因:第一,《机器学习实战》的代码由Python2编写,有些代码在Python3上运行已会报错,本教程基于Python3进行代码的修订;第二:之前看了一些机器学习的书籍,没有进行记录,很快就忘记掉了,通过编写教程也是一种复习的过程;第三,机器学习相对于爬虫和数据分析而言,学习难度更大,希望通过本系列文字教程,让读者在学习机器学习的路上少走弯路。

本系列教程特点:

  • 基于《机器学习实战》

  • 尽量避免讲太多数学公式,通过简单直白的方式讲解各算法的原理

  • 对于算法实现的代码进行详细讲解

哪些读者可以食用:

  • 了解机器学习的基本术语

  • 会Python语言

  • 会numpy和pandas库的使用

k-近邻算法(KNN)原理

KNN算法为分类算法。一句老话来描述KNN算法:“近朱者赤,近墨者黑”。 算法原理:计算测试样本与每个训练样本的距离(距离计算方法见下文),取前k个距离最小的训练样本,最后选择这k个样本中出现最多的分类,作为测试样本的分类。 如图所示,绿色的为测试样本,当k取3时,该样本就属于红色类;当k取5时,就属于蓝色类了。所以k值的选择很大程度影响着该算法的结果,通常k的取值不大于20。

KNN算法原理

介绍完原理后,看看KNN算法的伪代码流程:

  1. 计算测试样本与所有训练样本的距离

  2. 对距离进行升序排序,取前k个

  3. 计算k个样本中最多的分类

KNN之约会对象分类

问题描述与数据情况

海伦使用约会网站寻找约会对象。经过一段时间之后,她发现曾交往过三种类型的人:

  • 不喜欢的人

  • 魅力一般的人

  • 极具魅力的人

这里海伦收集了1000行数据,有三个特征:每年获得的飞行常客里程数;玩视频游戏所耗时间百分比;每周消费的冰淇淋公升数。以及对象的类型标签,如图所示。

数据情况

解析数据

  1. import numpy as np

  2. import operator

  3. def file2matrix(filename):

  4.    fr = open(filename)

  5.    arrayOLines = fr.readlines()

  6.    numberOflines = len(arrayOLines)

  7.    returnMat = np.zeros((numberOflines, 3))

  8.    classLabelVector = []

  9.    index = 0

  10.    for line in arrayOLines:

  11.        line = line.strip()

  12.        listFromLine = line.split('\t')

  13.        returnMat[index, :] = listFromLine[0:3]

  14.        classLabelVector.append(int(listFromLine[-1]))

  15.        index = index + 1

  16.    return returnMat, classLabelVector

定义解析数据的函数:4-9行:读取文件,并获取文件行数,创建一个文件行数(1000行)和3列的Numpy全0数组,创建用于存放类标签的classLabelVector列表。 10-17行:对文件进行循环遍历,对前三列数据存放到returnMat数组中,最后一列存放到classLabelVector列表中。结果如图所示。

解析数据

上面的代码为书中所写,其实用pandas读取数据后再出来是很方便了,代码如下:

  1. import numpy as np

  2. import operator

  3. import pandas as pd

  4. def file2matrix(filename):

  5.    data = pd.read_table(open(filename), sep='\t', header=None)

  6.    returnMat = data[[0,1,2]].values

  7.    classLabelVector = data[3].values

  8.    return returnMat, classLabelVector

归一化

由于特征间的数值差别太大,在计算距离时,数值大的属性会对结果产生更大的影响,这里需要对数据进行归一化:new = (old-min)/(max-min)。代码如下:

  1. def autoNorm(dataSet):

  2.    minval = dataSet.min(0)

  3.    maxval = dataSet.max(0 )

  4.    ranges = maxval - minval

  5.    normDataSet = np.zeros(np.shape(dataSet))

  6.    m = dataSet.shape[0]

  7.    normDataSet = dataSet - np.tile(minval, (m,1))

  8.    normDataSet = normDataSet/np.tile(ranges, (m,1))

  9.    return normDataSet, ranges, minval

传入的参数为测试数据(就是returnMat);首先按0轴(也就是按列)进行min和max的计算,如图所示进行简单的示例;然后构造和数据(normDataSet)一样大小的0矩阵; tile函数的用法读者可以自行百度,这里看下使用后的案例,作用就是让一维数组重复m行,如图所示,这样就可以进行数据归一化的计算。

示例

示例

结果

KNN算法

这里使用的距离为欧式距离,公式为:

欧式距离

  1. def classify(inX, dataSet, labels, k):

  2.    dataSize = dataSet.shape[0]

  3.    diffMat = np.tile(inX, (dataSize,1)) -dataSet

  4.    sqdiffMat = diffMat ** 2

  5.    sqDistance = sqdiffMat.sum(axis = 1)

  6.    distances = sqDistance ** 0.5

  7.    sortedDist = distances.argsort()

  8.    classCount ={}

  9.    for i in range(k):

  10.        voteIlable = labels[sortedDist[i]]

  11.        classCount[voteIlable] = classCount.get(voteIlable, 0) + 1

  12.    sortedClassCount = sorted(classCount.items(),

  13.                             key=operator.itemgetter(1), reverse=True)

  14.    return sortedClassCount[0][0]

inX为训练数据;dataSet为测试数据,labels为类别标签;k为取值; 2-6行:计算欧式距离; 7-最后:对计算的距离进行索引排序(argsort),然后对字典进行排序,获取值最多的分类。

对分类器进行测试

这里选择前10%数据做为测试样本,进行分类器的测试。

  1. def test():

  2.    r = 0.1

  3.    X, y = file2matrix('数据/datingTestSet2.txt')

  4.    new_X, ranges, minval = autoNorm(X)

  5.    m = new_X.shape[0]

  6.    numTestVecs = int(m*r)

  7.    error = 0.0

  8.    for i in range(numTestVecs):

  9.        result = classify(new_X[i, :],new_X[numTestVecs:m, :], y[numTestVecs:m], 3)

  10.        print('分类结果: %d, 真实数据: %d' %(result, y[i]))

  11.        if (result != y[i]):

  12.            error = error + 1.0

  13.    print('错误率: %f' % (error/float(numTestVecs)))

结果

测试系统

最后,编写一个简单的测试系统,该代码通过人为的输入三个属性特征,可以自动得到该约会对象的分类标签。

  1. def system():

  2.    style = ['不喜欢', '一般', '喜欢']

  3.    ffmile = float(input('飞行里程'))

  4.    game = float(input('游戏'))

  5.    ice = float(input('冰淇淋'))

  6.    X, y = file2matrix('数据/datingTestSet2.txt')

  7.    new_X, ranges, minval = autoNorm(X)

  8.    inArr = np.array([ffmile, game, ice])

  9.    result = classify((inArr - minval)/ranges, new_X, y, 3)

  10.    print('这个人', style[result - 1])

结果

算法优缺点

  • 优点:精度高,对异常值不敏感

  • 缺点:计算复杂(想想每个测试样本都要与训练样本继续距离计算)

作者罗罗攀,Python中文社区专栏作者,《从零开始学网络爬虫》图书作者。专栏地址: http://www.jianshu.com/u/9104ebf5e177




Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以公安部、工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼ 点击下方阅读原文免费成为社区会员


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/GPzQ2furNc
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/13284
 
461 次点击