机器学习实战 学习心得 kNN

实验内容 1 K-近邻算法概述
实验程序代码(含详细注释):

实验结果(展示实验细节):
1、使用Python导入数据;

 # 导入数据函数
def createDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])         #  数组中,前两个是接近1的数据集,后两个是接近0的数据集
    labels = ['A','A','B','B']      # 标签表示接近1的是A类,接近0的是B类
    return group, labels    # 将数据集和分类标签返回

在这里插入图片描述
2、实施kNN分类算法;

  # K邻近法则算法
    def classify0(inX, dataSet, labels, k):     #inX为输入向量,dataSet为训练数据集,labels为标签,k为最近邻居的数目
        dataSetSize = dataSet.shape[0]     #读取dataset矩阵第一维度的长度 即矩阵第一行的数据个数
        diffMat = tile(inX, (dataSetSize,1)) - dataSet      #tile(inX, (dataSetSize,1))表示向下复制dataSetSize次数的inX,这里计算输入向量与训练集中每个点的差
        sqDiffMat = diffMat**2      #这个差值取平方
        sqDistances = sqDiffMat.sum(axis=1)     # 横向相加所有差值平方得出欧式距离的平方
        distances = sqDistances**0.5    #取开放得出欧式距离
        sortedDistIndicies = distances.argsort()     #将distance从小到大排序,取出排序后该数据在distance中的索引值形成新的数组
        classCount={}          
        for i in range(k):      #循环k次
            voteIlabel = labels[sortedDistIndicies[i]]      #将改索引值在labels中对应的标签取出
            classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1   #该标签:出现次数 放入classCount字典中
        sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)     #根据出现次数排序
        return sortedClassCount[0][0]   #返回频率最高的“键”,即标签

在这里插入图片描述
3、如何测试分类器?简述其基本思想。

书上说的是错误率是常用的评估方法,主要用于评估分类器在某个数据集上的执行效果,完美分类器的错误率为0,最差的分类器错误率为1。
经过各方面查资料,评估分类器的方法除了错误率,还有,准确率、召回率、由准确率和召回率曲线构成的面积AUC的值。准确率是:在分类器中,预测为正类的所有值中,真正为正类的值与预测为正类的比值。召回率是:在分类器中预测为正类与所有数据中为正类的比值。AUC:假正例率与真正例率形成的图,若学习器A曲线能完全包住学习器B,那么学习器A就比B更加好。

实验内容 2 使用k-近邻算法改进约会网站的配对效果
1、 从文本文件中解析数据;
实验程序(含详细注释):

   # 读取datingTestSet.txt中的数据
    # 数据为约会网站的数据,每列分别是每年获得的飞行常客里程数,玩视频游戏所消耗时间百分比,每周雄安飞的冰淇淋公升数
    # 并返回给numpy矩阵
    def file2matrix(filename):
        fr = open(filename)     #打开文件
        numberOfLines = len(fr.readlines())         #读取文件行数
        returnMat = zeros((numberOfLines,3))        #构造文件行数,3列的矩阵,矩阵所有元素都是0
        classLabelVector = []                       #每行数据存储标签用的列表
        fr = open(filename)
        index = 0   #index作为returnMat矩阵的索引值
        for line in fr.readlines():     # 按照行读取文件内容
            line = line.strip()     # 去掉所有的回车
            listFromLine = line.split('\t')     # 将\t作为切割标志,将每行数据切分成列表
            returnMat[index,:] = listFromLine[0:3]      #将每行数据构成的列表中的元素,给矩阵returnMat
            classLabelVector.append(float(listFromLine[-1]))    #将最后一列喜欢程度值,给classLabelVector列表
            index += 1      #给矩阵下一行添加数据
        return returnMat,classLabelVector       #将 returnMat 矩阵和、classLabelVector喜欢程度 返回

实验结果(展示实验细节)
在这里插入图片描述
2、使用Matplotlib创建散点图;

实验程序(含详细注释):

from numpy import *
import kNN
import matplotlib.pyplot as plt
fig = plt.figure()      # 创建一个640*480的窗体
ax = fig.add_subplot(111)   # 创建子图,将画布分为一行一列,ax在从左往右从上往下数第一个子图
datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')      #调用kNN模块中的file2matrix函数读取数据
#ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), array(datingLabels))
#x轴为完视频游戏所消耗时间百分比,y轴每周所消费的冰淇淋的公升数,
# 第三个参数形参为s,表示点的权重大小,第四个参数形参为c,如果传入的向量,那么会根据向量中的标签将不同类别的颜色分开
# 其中大的黄色的点表示特别喜欢,绿色中等大小的点表示一般喜欢,紫色很小的点表示不喜欢

ax.axis([-2,25,-0.2,2.0])
plt.xlabel('Percentage of Time Spent Playing Video Games')      #x轴坐标名称  玩游戏时间
plt.ylabel('Liters of Ice Cream Consumed Per Week')     #y轴坐标名称     多少公升冰淇淋
plt.show()      #显示图像

实验结果(展示实验细节):
对于ax.scatter这个函数更改参数发现图不一样,其中发现形参s表示点的大小,形参c传入的是向量的话,会根据不同列表标记不同的颜色,下图是,s和c都没有传入参数、传入s参数、传入s和c参数的不同效果的图,最后一个图几乎将不同类别的人已经区分的比较明显了,轮廓也非常明显。
在这里插入图片描述

最后散点图
在这里插入图片描述

样本数据集的分布情况(每年飞的里程数与身上纹身面积的规律)
实验程序(含详细注释):

from numpy import *
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle


n = 1000 #number of points to create
xcord1 = []; ycord1 = []    #不喜欢类 xcord1飞行里数 ycord1电玩玩的时间
xcord2 = []; ycord2 = []    #一般喜欢类
xcord3 = []; ycord3 = []    #非常喜欢类
markers =[]
colors =[]
fw = open('testSet.txt','w')        #用写入的方式打开testSet.txt文件
for i in range(n):      #循环一千次
    [r0,r1] = random.standard_normal(2)     # 创建一行二列的随机数列表
    myClass = random.uniform(0,1)       # 创建一个0-1之间的均匀分布浮点随机数
    if (myClass <= 0.16):   #如果这个myClass随机数小于0.16
        fFlyer = random.uniform(22000, 60000)   #创建一个22000,60000之间的均匀分布浮点随机数给fFlyer
        tats = 3 + 1.6*r1
        markers.append(20)      #把myClass <= 0.16的markers标记成20
        colors.append(2.1)      #这个类的颜色数值为2.1
        classLabel = 1 #'didntLike'
        xcord1.append(fFlyer); ycord1.append(tats)
    elif ((myClass > 0.16) and (myClass <= 0.33)):  #如果这个myClass随机数在0.16-0.33之间
        fFlyer = 6000*r0 + 70000
        tats = 10 + 3*r1 + 2*r0
        markers.append(20)      #把myClass 在0.16-0.33之间的markers标记成20
        colors.append(1.1)      #这个类的颜色数值为1.1
        classLabel = 1 #'didntLike'
        if (tats < 0): tats =0
        if (fFlyer < 0): fFlyer =0
        xcord1.append(fFlyer); ycord1.append(tats)
    elif ((myClass > 0.33) and (myClass <= 0.66)):  #如果这个myClass随机数在0.33-0.66之间
        fFlyer = 5000*r0 + 10000
        tats = 3 + 2.8*r1
        markers.append(30)      #把myClass 在0.33-0.66之间的markers标记成30
        colors.append(1.1)      #这个类的颜色数值为1.1
        classLabel = 2 #'smallDoses'
        if (tats < 0): tats =0
        if (fFlyer < 0): fFlyer =0
        xcord2.append(fFlyer); ycord2.append(tats)
    else:       #如果这个myClass随机数大于0.66
        fFlyer = 10000*r0 + 35000
        tats = 10 + 2.0*r1
        markers.append(50)      #把myClass 大于0.66的markers标记成50
        colors.append(0.1)      #这个类的颜色数值为0.1
        classLabel = 3 #'largeDoses'
        if (tats < 0): tats =0
        if (fFlyer < 0): fFlyer =0
        xcord3.append(fFlyer); ycord3.append(tats)    
fw.close()
fig = plt.figure()
ax = fig.add_subplot(111)
#ax.scatter(xcord,ycord, c=colors, s=markers)
type1 = ax.scatter(xcord1, ycord1, s=20, c='red')       # x坐标为xcord1,y坐标ycord1,点大小为20,颜色为红色
type2 = ax.scatter(xcord2, ycord2, s=30, c='green')     # x坐标为xcord2,y坐标ycord2,点大小为30,颜色为绿色
type3 = ax.scatter(xcord3, ycord3, s=50, c='blue')      # x坐标为xcord3,y坐标ycord3,点大小为50,颜色为蓝色
ax.legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)   #图像小标题
ax.axis([-5000,100000,-2,25])
plt.xlabel('Frequent Flyier Miles Earned Per Year')     #横坐标名称
plt.ylabel('Percentage of Time Spent Playing Video Games')      #纵坐标名称
plt.show()

实验结果(展示实验细节):
在这里插入图片描述
样本数据集的分布情况(每年飞的里程数与华仔电玩游戏的时间之间的规律)

# coding=utf-8

'''
Created on Oct 6, 2010

@author: Peter
'''
from numpy import *
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle


n = 1000 #number of points to create
xcord = zeros((n))      #创建一个1*1000的矩阵,矩阵中数值都是0
ycord = zeros((n))      #创建一个1*1000的矩阵,矩阵中数值都是0
markers =[]     # 用于散点图点大小的列表
colors =[]      #散点图的颜色
fw = open('testSet.txt','w')        #用写入的方式打开testSet.txt文件
for i in range(n):      #循环一千次
    [r0,r1] = random.standard_normal(2)     # 取两个随机数
    myClass = random.uniform(0,1)       #取0-1之间的随机数
    if (myClass <= 0.16):
        fFlyer = random.uniform(22000, 60000)       #取22000-60000随机数
        tats = 3 + 1.6*r1
        markers.append(20)      # 小于0.16的点大小为20
        colors.append(2.1)      # 小于0.16的点颜色值为2.1
        classLabel = 1 #'didntLike'
        # print ("%d, %f, class1") % (fFlyer, tats)
        print(fFlyer, tats, "class1")
    elif ((myClass > 0.16) and (myClass <= 0.33)):
        fFlyer = 6000*r0 + 70000
        tats = 10 + 3*r1 + 2*r0
        markers.append(20)      # 大于0.16小于0.33点大小为20
        colors.append(1.1)      # 大于0.16小于0.33点颜色值为1.1
        classLabel = 1 #'didntLike'
        print(fFlyer, tats, "class1")
    elif ((myClass > 0.33) and (myClass <= 0.66)):
        fFlyer = 5000*r0 + 10000
        tats = 3 + 2.8*r1
        markers.append(30)      # 大于0.33小于0.66的点大小为30
        colors.append(1.1)      # 大于0.33小于0.66的点颜色值为1.1
        print(fFlyer,tats,"class2")
    else:
        fFlyer = 10000*r0 + 35000
        tats = 10 + 2.0*r1
        markers.append(50)      # 大于0.66的点大小为50
        colors.append(0.1)      # 大于0.66的点颜色值为0.1
        classLabel = 3 #'largeDoses'
        print(fFlyer, tats, "class3")
    if (tats < 0): tats =0
    if (fFlyer < 0): fFlyer =0
    xcord[i] = fFlyer; ycord[i]=tats
    fw.write("%d\t%f\t%f\t%d\n" % (fFlyer, tats, random.uniform(0.0, 1.7), classLabel))

fw.close()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord,ycord, c=colors, s=markers)
type1 = ax.scatter([-10], [-10], s=20, c='red')
type2 = ax.scatter([-10], [-15], s=30, c='green')
type3 = ax.scatter([-10], [-20], s=50, c='blue')
ax.legend([type1, type2, type3], ["Class 1", "Class 2", "Class 3"], loc=2)
#ax.axis([-5000,100000,-2,25])
plt.xlabel('Frequent Flyier Miles Earned Per Year')
plt.ylabel('Percentage of Body Covered By Tatoos')
plt.show()

在这里插入图片描述

测试算法

def autoNorm(dataSet):
      minVals = dataSet.min(0)    #取数据集最小值
      maxVals = dataSet.max(0)    #取数据集最大值
      ranges = maxVals - minVals      #取最大值和最小值的差值
      normDataSet = zeros(shape(dataSet)) #建立一个都是0的行列数与数据集一样的矩阵
      m = dataSet.shape[0]    #读取数据集的行数
      normDataSet = dataSet - tile(minVals, (m,1))    # 数据集减去最小值矩阵
      normDataSet = normDataSet/tile(ranges, (m,1))   # 归一化处理
      return normDataSet, ranges, minVals

# 数据测试
def datingClassTest():
    hoRatio = 0.50
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #读取datingTestSet2.txt文件中的数据
    normMat, ranges, minVals = autoNorm(datingDataMat)      #数据归一化
    m = normMat.shape[0]    #获取数据矩阵行数
    numTestVecs = int(m*hoRatio)    # 获取测试集数据行数
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        #执行classify0分类器,将分类结果给classifierResult
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        # 如果分类器的结果和标签不一样,就errorCount+1
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print(errorCount)#打印出错误率

在这里插入图片描述
使用算法构建完整系统

实验内容 3 手写识别系统

实验程序(含详细注释):

def img2vector(filename):
    returnVect = zeros((1,1024))    #创建一个1*1024的一维向量
    fr = open(filename)     #打开文件
    for i in range(32):     #嵌套循环,将图像按照行读出,一共32行
        lineStr = fr.readline()
        for j in range(32):     # 将图像每行的数据一个个读出,每行一共32个数据
            returnVect[0,32*i+j] = int(lineStr[j])      #将每行的每个数据依次存到一维向量中
    return returnVect       # 返回处理好的向量,这个时候就把图像装欢为一维向量了

实验结果(展示实验细节):
在这里插入图片描述

 
def handwritingClassTest():
    hwLabels = []       # 构建空的测试集的标签列表
    trainingFileList = listdir('trainingDigits')           #读取文件夹trainingDigits列表
    m = len(trainingFileList)       #返回文件夹个数
    trainingMat = zeros((m,1024))   #构建元素都是0的,训练数据个数*1024大小的矩阵,每行存一个图像
    for i in range(m):
        fileNameStr = trainingFileList[i]       #获取文件的名字
        fileStr = fileNameStr.split('.')[0]     #获取文件名,把后缀名去掉
        classNumStr = int(fileStr.split('_')[0])    #从文件名中获取类名
        hwLabels.append(classNumStr)        # 将获得的类别标签添加到hwLabels列表中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)       #将每个文件的1*1024数据存储到这个文件trainingDigits/fileNameStr中
    testFileList = listdir('testDigits')        #iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)       #测试数据的个数
    #将文件名中的类名取出,并进行分类测试
    for i in range(mTest):
        fileNameStr = testFileList[i]   #获取文件的名字
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)#获得测试集的向量
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) # 获得预测结果
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0     #如果预测结果和真实结果不符合,错误数+1
    print("\nthe total number of errors is: %d" % errorCount)
    print("\nthe total error rate is: %f" % (errorCount/float(mTest)))


 

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值