机器学习 (三) k-近邻算法应用-约会网站匹配系统

前言

       目前一些姻缘网站专门给人介绍对象,也经常有人陷入介绍门中,怎么样来提高准确率降低网站带来的风险呢?其实里面有些推荐算法和匹配算法在里面,今天我们简单介绍其中一种。
       大家是否还记得在第一次注册的会员的时候,它会让你填一些年龄、性格、体貌特征选项等等,其实这些都是有用的个人特征数据,网站拿到这些数据之后会根据数据给你匹配最可能适合你的妹子,提高成功率,下面我们就来看一下它是如何给你匹配对象的,里面可能用到了k-近邻算法。

简介

       上一篇博文已经介绍过它的原理背景以及实现方式,相信大家已经了解,现在假设把喜欢的妹子归类为三种人:不喜欢的人、魅力一般的人、极具魅力的人,我们都希望找到极具魅力的人,理想的白富美,分类目标是把网站推荐给我们的人自动分到这三类中,该如何分类呢?

场景

       当我们有了这样一个业务场景或者想法之后,接下来需要考虑有没有特征项、有多少特征项、有哪些特征权重大对分类结果有帮助等,这些都是我们需要考虑的问题,俗话说“巧妇难为无米之炊”就是这个道理,有米好下锅。假设我们已经收集了三个重要特征

1.每年获得飞行常客里程数
2.玩视频游戏所耗时间百分比
3.每周消费的冰激凌公升数

数据如下:
机器学习 (三) k-近邻算法应用-约会网站匹配系统_第1张图片
上图中的第一列、二列、三列分别对应上面三个特征,最右侧为类别标签标示该样本属于哪一类,

分析步骤

收集数据

       收集数据有各种方法,如业务系统平时产生的日志数据、物理设备收集的数据等,或者使用问卷调查或其它方式,只要收集的有用的数据都是可以的。

准备数据

       在有了数据以及确定了哪些特征列之后就需要将保存在DB或者文件里面的数据处理为可以让程序读入的数据了,将数据处理为程序可以理解的格式,这里的程序可以是python也可以是其它处理程序,程序可以处理即可,一般我们会把数据处理抽象出来一个函数,如下代码是激昂上面的数据文件转为python数据对象。


def file2matrix(filename):
    '''
    从文件加载数据 返回训练集和类别标签
    :param filename:数据文件
    :return:特征训练集、列表标签
    '''
    # 打开数据文件
    fr = open(filename)
    # 获取样本个数
    arrayOLines = fr.readlines()
    # 获取样本个数
    numberOfLines = len(arrayOLines)
    # 初始化特征矩阵
    returnMat = np.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

分析数据

       分析数据是为了确保收集的数据可用、有价值,即研究数据可用性、可靠性、准确性等为目的的,而通常为了直观感受数据我们经常以图形化的形式将数据展示出来,如散点图、条形图等下面我们先拿特征数据的第二列和第三列“玩视频游戏所耗时间百分比”和“每周所消耗的冰淇淋公升数”来绘制一幅散点图,先来看看效果如何

归一化数值

       从数据集来看,第一列数据明显比其它两列值大很多,为了减少值得差异性带来的误差,需要对大值数据做一下处理,此处
采用均值法,每项的值=(当前值-最小值)/ (最大值-最小值),这样处理过的数据取值范围都在0-1之间,符合我们的预期,自动处理归一化函数如下:

def autoNorm(dataSet):
    '''
    归一化数值
    :param dataSet:待处理数据集
    :return:处理后的结果
    '''
    # 第一列的最小值 
    minVals = dataSet.min(0)
    # 第一列的最大值
    maxVals = dataSet.max(0)
    # 取值范围
    ranges = maxVals - minVals
    # 初始化全为0的矩阵
    normDataSet = np.zeros(np.shape(dataSet))
    # 获取行数
    m = dataSet.shape[0]
    # 将最小值重复m行 1列输出,相减
    normDataSet = dataSet - np.tile(minVals,(m,1))
    # 将取值范围重复m行1列输出,相除
    normDataSet = normDataSet / np.tile(ranges,(m,1))
    # 返回处理后的矩阵、取值范围、最小值
    return normDataSet,ranges,minVals


def createScatterGraph(datingDataMat,datingDataLabels):
    '''
    根据矩阵数据创建散点图
    :param datingDataMat: 矩阵
    :param datingDataLabels: 类别标签
    :return:
    '''
    # 创建一个区域显示数据
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # 加载2、3列数据
    ax.scatter(datingDataMat[:,1],datingDataMat[:,2])
    plt.show()

机器学习 (三) k-近邻算法应用-约会网站匹配系统_第2张图片

       从图中很难以分辨出来样本究竟属于哪一类,这是由于没有把类别标签加入,为了好看我们再把不同类别的样本加上不同的颜色,图下图(图片,加入颜色后)
机器学习 (三) k-近邻算法应用-约会网站匹配系统_第3张图片

       如上图所示,假如类别标签的数据已经很明显看出来是属于哪一类别,三种颜色十分明显,现在效果明显了还存在排列混乱的问题,因为我们的最终目的是为了分类不是展示数据,需要将三种分类明确的分出来,让我们来试试第一列和第二列展示数据。

    ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0 * np.array(datingDataLabels),
               15.0 * np.array(datingDataLabels))

机器学习 (三) k-近邻算法应用-约会网站匹配系统_第4张图片

测试算法

       当我们设计的一个学习分类器完成的时候,一个重要事情就是评估算法的好坏,这也决定了该算法能否上线的依据,在java开发中大家都知道有白盒测试、黑盒测试、冒烟测试等,那么在机器学习中是否一样有哪些测试方法呢?最常用的是交叉验证测试法,交叉验证又可以细分为很多种,常用的有三种,这里我们使用第一种简单方法即随机抽取90%数据作为训练集数据 10%作为测试集合数据,代码如下:

def datingClassTest():
    '''
    测试分类器的效果 错误率大小
    :return:
    '''
    # 调节测试样本集大小参数
    hoRatio = 0.10
    # 加载样本数据
    datingDataMat,datingDataLabels = file2matrix('datingTestSet2.txt')
    # 数据归一化处理
    normMat,ranges,minVals = autoNorm(datingDataMat)
    # 获取样本个数
    m = normMat.shape[0]
    # 测试集样本个数
    numTestVecs = int(m*hoRatio)
    # 保存错误的次数
    errorCount = 0.0
    # 循环错误集
    for i in range(numTestVecs):
        # 获取分类结果 参数为:待测样本向量、已经样本集、已知分类标签、k值
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingDataLabels[numTestVecs:m],3)
        print "the classifier came back with: %d,the real answer is: %d" % (classifierResult,datingDataLabels[i])
        # 统计错误次数
        if (classifierResult != datingDataLabels[i]):
            errorCount += 1.0
    # 计算错误率 错误次数/测试样本个数
    print "the total error rate is: %f" % (errorCount/float(numTestVecs))

使用算法

上面我们的算法已经测试完毕,接下来即可进入使用环节,这个环节我觉得可以提供出来一些页面或者网页供用户使用,用户输入某个人的信息然后返回给用户他是否会喜欢对方,这样对于用户体验、用户效果要好一些,为了方便这里就不绘制界面了,只是来使用下效果如何。

def classifyPerson():
    '''
    检验约会网站对象预测结果
    :return:
    '''
    # 结果
    resultList = ['不喜欢','有点喜欢','很喜欢']
    # 输入特征
    percentTats = float(raw_input("玩网游所消耗的时间比"))
    ffMiles = float(raw_input("每年获得的飞行常客里程数"))
    iceCream = float(raw_input("每年消费的冰淇淋公升数"))
    # 加载数据
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    # 归一化处理
    normMat,ranges,minVals = autoNorm(datingDataMat)
    # 生成特征向量
    inArr = np.array([ffMiles,percentTats,iceCream])
    # 预测
    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    print "you will probably like this person:",resultList[classifierResult-1]

预测我的结果如下:
机器学习 (三) k-近邻算法应用-约会网站匹配系统_第5张图片

根据结果来看我还是喜欢旅游多一点、玩网游少一点的妹子
       

概念解析

  • 错误率
    通常我们拿错误的次数除以总测试次数,作为错误率
  • 交叉验证(cross validation)
    1.k-folder cross-validation
    中文名叫做10-折交叉验证,意思是随机选取10份数据,取9份作为训练数据,10份作为测试数据,循环进行10次,每次都计算出来错误率,取平均值,此方法可以尽可能的避免由于数据不均匀分布对验证结果产生的影响,也是最常用的方法。
    2.K * 2 folder cross-validation
    此法是10-折的变体,分完10份或k份后,再二分为s0 s1 ,分别为测试数据和训练数据,此方法保证了测试集合训练数据都足够多
    3.least-one-out cross-validation(loocv)
    指每次n-1个样本训练,1个样本测试,循环进行。

总结

       knn优缺点上篇已经总结,这里说说对算法或机器学习的理解,各种机器学习算法层出不穷如何才能学好各种算法呢,这是值得思考的一个问题,我我觉得首先第一步还是要深刻理解这一领域涉及到的各种概念,知道原因了才能有深入的理解,其次是工欲善其事,必先利其器,一些工具函数统计学、数学基础要掌握,知道灵活运用。比如为什么机器学习中都使用矩阵来处理数据?知道原因才能想到如果自己写个算法怎么处理数据,下一篇计划总结一下贝叶斯算法,待续…………

题外思考

井盖为什么是园的而不是方的谈认知观?

       生活中其实处处都能体现出来人们的思想和想法,只要我们细心观察有一颗发现问题的心,牛顿为什么发现苹果?自然界或者人类社会中其实没有什么事情本来就是那样的,不同的认知观会发现不同的问题,如果当你看到井盖时是否会想到为什么是圆的,还是觉得它本来就是那样,两种不同的认知观会有不同的结果。
       有了认知观后,其次需要思考园的和方的区别在哪里,从易于使用、制造等多方面思考,就会发现哪种会好一些,生活中也没有标准答案一说,以前的教学给我们灌输的是标准答案,其实在不同条件、不同场景下,我们追求的结果可能是不同的,这就引出来因果学说。

你可能感兴趣的:(机器学习,机器学习)