机器学习笔记1(K-近邻算法)

人生苦短,我用Python

K-近邻算法:简单来说,K-近邻算法就是采用测量不同特征值之间的距离方法进行分类

  • 优点:精度高、对异常值不敏感、无数据输入假定
  • 缺点:计算复杂度高、空间复杂度高
  • 适用范围:数值型、标称型

工作原理:

存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似的数据(最近邻)的分类标签。一般来说,我们只选择样本集中前K个最相似的数据,这就是K-近邻算法中K的出处,通常K是不大于20的整数。最后,选择K个最相似数据中出现次数最多的分类,作为新数据的分类。

K-近邻算法的一般流程:

  1. 收集数据:可以使用任何方法。
  2. 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
  3. 分析数据:可以使用任何方法。
  4. 训练算法:此步骤不适用于K-近邻算法。
  5. 测试算法:计算错误率。
  6. 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

实施KNN分类算法--伪代码

对未知类别属性的数据集中的每个点依次执行以下操作:

  1. 计算已知类别数据集中的点与当前点之间的距离;
  2. 按照距离递增次序排序;
  3. 选取与当前点距离最小的K个点;
  4. 确定前K个点所在类别的出现频率;
  5. 返回前K个点出现频率最高的类别作为当前点的预测分类;

计算两个向量点之间的距离公式--欧式距离公式:

例如:点(0,0)与(1,2)之间的距离计算为:

sqrt((1-0)**2+(2-0)**2)

代码实现:

import numpy as np
import operator
"""
def CreateDataSet():
    group=np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group,labels
print(CreateDataSet())
"""
"""
inX--用于分类的输入向量
dataSet--输入的训练样本集
labels--标签向量
k--用于选择最近邻居的数目
其中标签向量的元素数目和矩阵dataSet的行数相同
"""
def classify(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]    #获得训练样本集的行数

    #将输入向量在列方向重复一次,在行方向上dataSize次,并与训练样本集dataSet相减
    diffMat=np.tile(inX,(dataSetSize,1))-dataSet
    print("diffMat:")
    print(diffMat)
    #将相减后的集合进行平方运算
    sqDiffMat=diffMat**2
    print("sqDiffMat:")
    print(sqDiffMat)
    #对平方后的集合进行相加运算--按行相加
    sqDistances=sqDiffMat.sum(axis=1)
    print("sqDistances:")
    print(sqDistances)
    #对相加后的数据开平方,得到输入向量与每个训练样本集之间的距离值
    distances=np.sqrt(sqDistances)
    print("distances")
    print(distances)
    #返回数组从小到大的索引值--排序
    sortedDistIndicies=np.argsort(distances)
    print("sortedDistIndicies")
    print(sortedDistIndicies)
    classCount={}

    for i in range(k):
        voteIlabel=labels[sortedDistIndicies[i]]
        print("voteIlabel"+str(i))
        print(voteIlabel)
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
        print("classCount"+str(i))
        print(classCount)
    sortedClassCount=sorted(classCount.items(),
                            key=operator.itemgetter(1),reverse=True)
    print("sortedClassCount:")
    print(sortedClassCount)
    return sortedClassCount[0][0]

if __name__=='__main__':
    #训练样本集
    group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])

    #标签向量
    labels = ['A', 'A', 'B', 'B']

    #输入向量
    inX=[0,0]

    #用于选择最近邻居的数目
    k=3
    result=classify(inX,group,labels,k)
    print(result)


"""
输出值:
diffMat:
[[-1.  -1.1]
 [-1.  -1. ]
 [ 0.   0. ]
 [ 0.  -0.1]]
sqDiffMat:
[[ 1.    1.21]
 [ 1.    1.  ]
 [ 0.    0.  ]
 [ 0.    0.01]]
sqDistances:
[ 2.21  2.    0.    0.01]
distances
[ 1.48660687  1.41421356  0.          0.1       ]
sortedDistIndicies
[2 3 1 0]
voteIlabel0
B
classCount0
{'B': 1}
voteIlabel1
B
classCount1
{'B': 2}
voteIlabel2
A
classCount2
{'B': 2, 'A': 1}
sortedClassCount:
[('B', 2), ('A', 1)]
B

Process finished with exit code 0
"""复制代码

测试结果:

输入[0,0],经过测试后,返回的结果是B,也就是说[0,0]这个输入向量通过K-近邻算法分类后归为B类


示例:使用K-近邻算法改进约会网站的配对效果

  1. 收集数据:提供文本文件
  2. 准备数据:使用Python解析文本文件
  3. 分析数据:使用Matplotlib画二维扩散图
  4. 训练算法:此步骤不适用与K-近邻算法
  5. 测试算法:使用海伦提供的部分数据作为测试样本
  6. 测试样本和非测试的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
  7. 使用算法:产生简单的命令行程序,然后可以输入一些特征数据以判断对方是否是自己喜欢的类型

准备数据:从文本文件中解析数据

文本样本数据特征:

  • 每年获得的飞行常客里程数
  • 玩视频游戏所耗时间的百分比
  • 每周消费的冰淇淋公升数

将文本记录转换为numpy数据的解析程序:

def file2matrix(filename):
    # 打开文件
    fr = open(filename, 'r', encoding='utf-8')

    # 按行读取数据
    arrayOLines = fr.readlines()

    # 获取数据的行数
    numberOfLines = len(arrayOLines)
    # 创建以0填充的矩阵
    returnMat = np.zeros((numberOfLines, 3))
    print(returnMat)
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        print(line)
        # 截取掉所有回车字符
        line = line.strip()
        print(line)
        # 以'\t'将line分割成一个元素列表
        listFromLine = line.split('\t')
        # 选取前三个元素,存储到特征矩阵中
        returnMat[index, :] = listFromLine[0:3]
        # 选取最后一个元素存储到标签向量中
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector
datingDataMat,datingLabels=file2matrix('D:\liuguojiang_Python\city_58\city_58\datingTestSet2.txt')
fig=plt.figure()
plt.title('K-')
plt.xlabel('fly')
plt.ylabel('consume')
ax=fig.add_subplot(111)

ax.scatter(datingDataMat[:,0],datingDataMat[:,1],
           15.0*np.array(datingLabels),15.0*np.array(datingLabels))
plt.show()复制代码

特别说明:代码中的资源文件可以在此处下载:LiuGuoJiang/machinelearninginaction

解析文本数据并用散点图展示:


准备数据:归一化数值

任选样本数据中一行数据,计算距离时,因为飞行常客里程数比较大,所以对最后计算结果影响过大,所以需要对数据做归一化处理。如将取值范围处理为0~1或者-1~1之间。下面的公式可以将任意取值范围的特征值转化为0~1区间内的值:

newValue=(oldValue-min)/(max-min)

  • 其中min和max分别是数据集中的最小特征值和最大特征值。

归一化特征值函数:

def autoNorm(dataSet):
    #选取列的最小值
    minVals=dataSet.min(0)
    #选取列的最大值
    maxVals=dataSet.max(0)
    #列的最大值与最小值做减法
    ranges=maxVals-minVals
    #
    normDataSet=np.zeros([dataSet.shape[0],dataSet.shape[1]])
    print(normDataSet)
    #取出dataSet的行数
    m=dataSet.shape[0]
    #np.tile(minVals,(m,1))将minVals在 列上重复一次,在行上重复m次
    normDataSet=dataSet-np.tile(minVals,(m,1))  #(oldValue-min)
    normDataSet=normDataSet/np.tile(ranges,(m,1))   #(oldValue-min)/(max-min)
    return normDataSet,ranges,minVals

normDataSet,ranges,minVals=autoNorm(datingDataMat)
print(normDataSet)复制代码

测试算法:机器学习算法一个很重要的工作就是评估算法的正确率,通常我们只提供已有数据的90%作为训练样本来训练分类器,而使用其余的10%数据去测试分类器,检测分类器的正确率。10%数据应该是随机选择的。

分类器的测试代码:

def datingClassUnitTest():
    hoRatio=0.10
    datingDataMat, datingLabels = file2matrix('D:\liuguojiang_Python\city_58\city_58\datingTestSet2.txt')
    print(datingDataMat)
    normDataSet, ranges, minVals = autoNorm(datingDataMat)
    print(normDataSet)
    m=normDataSet.shape[0]
    numTestVecs=int(m*hoRatio)
    print("numTestVecs")
    print(numTestVecs)
    errorCount=0.0
    for i in range(numTestVecs):
        classifierResult=classify(normDataSet[i,:],normDataSet[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print("the classfier came back with:{},the real answer is:{}".format(classifierResult,datingLabels[i]))
        if (classifierResult!=datingLabels[i]):errorCount+=1.0
    print("the total error rate is:{}".format(errorCount/float(numTestVecs)))


the classfier came back with:3,the real answer is:3
the classfier came back with:2,the real answer is:2
the classfier came back with:1,the real answer is:1
.........
the classfier came back with:1,the real answer is:1
the classfier came back with:3,the real answer is:3
the classfier came back with:3,the real answer is:3
the classfier came back with:2,the real answer is:2
the classfier came back with:1,the real answer is:1
the classfier came back with:3,the real answer is:1
the total error rate is:0.05复制代码

分类器处理数据集的错误率是5%,即代表此分类器可以帮助对象判定分类。

编写可以让用户输入自己需要判断的输入向量,通过该分类器帮助用户判断属于哪一分类:

def classifyPerson():
    resultList = ['not at all', 'in small doses', 'in large doses']
    percentTats = float(input( \
        "percentage of time spent playing video games?"))
    ffMiles = float(input("frequent flier miles earned per year?"))
    iceCream = float(input("liters of ice cream consumed per year?"))
    datingDataMat, datingLabels = file2matrix('D:\liuguojiang_Python\city_58\city_58\datingTestSet2.txt')
    normDataSet, ranges, minVals = autoNorm(datingDataMat)
    inArr = np.array([ffMiles, percentTats, iceCream, ])
    classifierResult = classify((inArr - \
                                  minVals) / ranges, normDataSet, datingLabels, 3)
    print("You will probably like this person: {}".format(resultList[classifierResult - 1]))
if __name__=='__main__':
    classifyPerson()

"""
return:
percentage of time spent playing video games?10
frequent flier miles earned per year?10000
liters of ice cream consumed per year?0.5
You will probably like this person: in small doses
"""复制代码

总结:

  1. 定义K-近邻算法程序。
  2. 定义将文本数据集处理成二维数组的函数,便于处理。
  3. 为消除某一特征数值过大对结果判定的影响,定义归一化数值函数,公式:(oldValue-min)/(max-min)
  4. 定义测试算法函数,用于测试分类器的错误率是否满足使用要求。
  5. 定义可以让用户输入的代码,输入输入向量,用于判定分类


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>