使用k近邻算法根据数据识别性别

发表于 算法 2017-08-20 阅读数: 107

k近邻算法是最简单的机器学习算法之一。它可以很方便地用来分类。

需要:

Python环境

训练集

k近邻算法其实就是算不同的特征值之间的距离然后进行分类,语言描述太抽象,下面我举个例子(求X的性别):

k近邻算法

我们要使用k近邻算法求出X的性别,就是用X的特征值算出与其他人的特征值的距离,当然,我们还需要考虑数值问题,数值大的变量对结果的影响也大了,像这里,衣服的数量总体比打扮时间长度多,对结果的影响也更大,但实际上不应该如此。这个我们到后面再讲解如何进行处理,公式如下(欧式公式):

k近邻算法

如X和小丽的距离就是:

k近邻算法

求出X和所有人的距离后,取最短距离的前k个人的性别,在这k个人中,出现最多次的那个性别,就是X的性别。

这里的k就是这个算法名字的由来,k是可以自取的,随着样本数量的增加应该适时调整。

首先先构造这个算法的函数:

def classify(X,dataSet,labels,k):

    #X是待测对象的特征值矩阵,dataSet是样本,labels是要分类的特征

    dataSetSize = dataSet.shape[0]

    #求矩阵长度

    minusMat = tile(X,(dataSetSize,1)) - dataSet

    #进行减法(tile就是重复(x,y)次X)

    sqMinusMat = minusMat ** 2

    #平方

    sqDistances = sqMinusMat.sum(axis=1)

    #相加,axis=1就是每一行内相加

    distances = sqDistances ** 0.5

    #欧式公式开根

    sortedDistIndicies = distances.argsort()

    #返回数组中距离从小到大的数据的索引

    classCount = {}

    #字典,准备计数

    for i in range(k):

        #执行k次

        votelabels = labels[sortedDistIndicies[i]]

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

        #寻找存不存在这个符号,不存在则返回默认0,然后加一

    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse = True)

    # classCount.items() 对这个字典里的对象

    # reverse = True 降序

    # key=operator.itemgetter(1) 根据第一个数值比较 如 'B':2 中的2

    return sortedClassCount[0][0]

    # 返回出现次数最多的项目

下面我们就用这个函数来识别一下X的性别。先把样本集创建出来:

def createDataSet():

    group = array([[40,30],[18,10],[32,34],[23,17],[26,7],[38,23]])

    labels = ['女','男','女','男','男','女']

    return group,labels

写出X的数据,并将样本集和数据传入函数后运行:

X = [35,15]

group,labels = createDataSet()

print(classify(X,group,labels,3))

k近邻算法

得到结果为男性,有点出乎意料。

但是我们还没有处理权重问题,之前就提到了,拥有衣服的数量和每天化妆打扮的时间长度所占权重是不一样的。于是我们需要归一化特征值。所谓的归一化特征值就是将所有的特征值按照其比重转化为0到1之间的值(有点像S函数)。算法是这样的:

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

转换为函数:

def balance(X,dataSet):

    min = dataSet.min(0)

    max = dataSet.max(0)

    #取得两列的最小最大值

    ranges = max - min

    #取得范围

    normDataSet = zeros(shape(dataSet))

    #创建一个同等大小值为零的矩阵

    m = dataSet.shape[0]

    #取得列的长度

    normDataSet = dataSet - tile(min,(m,1))

    #oldValue - min

    normDataSet = normDataSet/tile(ranges,(m,1))

    #(oldValue - min) / (max - min)

    #下面计算X的

    X_return = zeros(shape(X))

    X_return = X - tile(min,(1,1))

    X_return = X_return / tile(ranges, (1, 1))

    return normDataSet,X_return

X的特征值归一化后是:

[[ 0.77272727  0.2962963 ]]

而训练集是:

[[ 1.          0.85185185]

 [ 0.          0.11111111]

 [ 0.63636364  1.        ]

 [ 0.22727273  0.37037037]

 [ 0.36363636  0.        ]

 [ 0.90909091  0.59259259]]

显然,这样的标准更加科学,不会因为某些数字大而影响变量之间的权重。

重新计算:

X = [35,15]

group,labels = createDataSet()

group,X = balance(X,group)

print(X)

print(group)

print(classify(X,group,labels,3))

k近邻算法

结果依然是男的,这个其实蛮出乎意料的,因为X的衣服数量挺多的,我们会在主观上人为它是一名女生,但实际上,更加客观的数据告诉我们,它是男生。

题图来自网络参考文献:《机器学习实战》欢迎访问https://alltoshare.comhttps://wanttoshop.cn

幻象客 二维码

Add comment