机器学习实战--K近邻算法实现(二)

                        实例:使用K近邻算法改进约会网站

从文本文件中解析数据

数据样本存放在txt类型文件中,每个样本占一行,总共有1000行,每行样本都包含的特征为:

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

将上述特征输入到分类器之前,需要将待处理的数据格式设置为分类器可以接收的数据,为此创建file2matrx的函数,该函数输入为文件名字符串,输出为训练样本矩阵和类标签向量。相关源码为:

def file2matrix(filename):
    fr = open(filename)
    #得到行列表
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)
    #zeros函数缺省第一个参数,默认值为0,第二个参数为规模大小的元组
    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

readlines()函数返回一个行列表,zeros()函数创建以0填充的矩阵,其大小为numberOfLines(行)*3(列)。然后遍历行列表,将每一行按制表符分割得到每个样本对应的特征,前三个特征值作为属性保存到训练矩阵中,训练矩阵相当于二维数组,每一行对应一个样本,每一列对应一个属性类型,index作为每一行的索引标示。最后一个特征就是标签,将其添加到标签列表之中。最后将训练集矩阵和标签列表作为函数值返回。

归一化数据

欧氏距离中差值范围越大的元素对计算结果影响越大,因此倘若三个特征都同样重要,就要有相同的权值。通常采用的方法是数据归一化,下面的公式将任意取值范围的特征值转化为0-1之间的数。

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

创建函数autoNorm(dataSet):

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals-minVals
    #normDataSet初始化为dataSet规模的零矩阵,引入的目的是充当dataset的副本
    #确保不破坏dataset训练集的原始结构
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet-tile(minVals,(m,1))
    normDataSet = normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals

min和max的参数均取0,得到一个1*3的行向量,每个元素都是该列上最小或最大的元素,相减得到的ranges是一个表示范围也就是公式上分母对应的元素。通过zeros函数初始化一个与dataSet矩阵同规模的零矩阵,值得注意的是,矩阵的除法是矩阵上对应行列的各个元素的除法。最后得到归一后的训练集矩阵。

测试算法

机器学习算法的一个重要工作就是测试算法的正确率,通常只提供已有数据的90%作为训练样本来训练数据,10%的数据去测试分类器。错误率就是分类器给出的错误结果次数除以测试数据的总数。创建datingClassTest函数测试。

def datingClassTest():
    hoRatio = 0.10
    #得到训练集与结果集的矩阵表示
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    #将训练集的特征值归一化处理
    normMat,ranges,minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    #得到要测试的样本的个数,该样本为总体的一部分
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        #测试集为前numTestVecs个样本,训练集和结果集为剩下的样本
        classfierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],\
                                    datingLabels[numTestVecs:m],5)
        print("the classifer came back with:%d,the real answer is %d"\
              % (classfierResult,datingLabels[i]))
        #判断实际值与预估值是否相等,不等则错误个数加一
        if (classfierResult!=datingLabels[i]):
           errorCount+=1.0
    print("the total error rate is:%f" % (errorCount/float(numTestVecs)))

norMat[i,:]是第i个样本的特征行向量,作为测试集中的一个样本。normMat[numTestVecs:m,:]是将剩下的样本作为训练样本,注意序列切片法的使用。将返回的预估值与实际值进行比较,不等的话则错误计数累加,最后输出错误率。

构建完整可用系统

加入交互,使用户在提示下自己输入特征值,最后给出判断的结果,更加的人性化。

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 filler miles earned per year?"))
    iceCream = float(input("liters of icecream consumed per year?"))
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals = autoNorm(datingDataMat)
    #测试值
    inArr = array([ffMiles,percentTats,iceCream])
    classiferResult = classify0(inArr,normMat,datingLabels,3)
    print("you will probablly like this person:",resultList[classiferResult-1])

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值