【Python机器学习】k-近邻算法简单实践——改进约会网站的配对效果

需求背景:

XX一直使用约会网站寻找适合自己的约会对象,ta会把人分为3种类型:

不喜欢、魅力一般、非常有魅力

对人分类轴,发现了对象样本的以下3种特征:

1、每年获得的飞行里程数

2、玩视频游戏所耗时间百分比

3、每周消费的冰淇淋数量

数据初始化:

将上述特征输入到分类器之前,必须将待处理数据的格式处理成分类器可以接受的格式。因为源数据存在txt文件中,所以要创建一个函数处理数据:

def file2matrix(filename):
    fr=open(filename)
    arrayOlines=fr.readlines()
    numberOfLines=len(arrayOlines)
    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

从上面的代码可以看到,Python处理文本文件非常容易。

处理顺序:

1、获得文件的行数

2、创建以0填充的矩阵NumPy

3、循环处理文件中的每行数据,使用函数line.strip()截取掉所有的回车字符

分析数据:

使用Matplotlib制作原始数据的散点图:

datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()

可以看到,由于没有使用样本分类的特征值,很难从图中看出任何有用的数据模式信息,所以调试代码,利用scatter函数进行个性化标记散点图上的点:

ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))

现在就可以看出每种分类人群的特征

准备数据:归一化数值

从数据上可以看出,每年飞行里程数对于计算结果的影响远远大于另外两个特征的影响。而产生这种线性的原因,仅仅是因为飞行里程数远大于其他特征,但因为用户认为这三种特征是同等重要的,所以作为特征之一,里程数不应该如此严重的影响到计算结果。

处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,比如将取值范围处理为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=zeros(shape(dataSet))
    m=dataSet.shape[0]
    normDataSet=dataSet-tile(minVals,(m,1))
    normDataSet=normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals

在这个函数中,我们将每列的最小值放在变量minVals中,将最大值放在变量maxVals中,其中dataSet.min(0)中的参数0使得函数可以从列中选取最小值,而不是选取当前行的最小值。然后,函数计算可能的取值范围,并创建新的返回矩阵。为了归一化特征值,我们必须使用当前值减去最小值,然后除以取值范围。需要注意的是,特征矩阵由1000*3个值,而minVals和range的值都是1*3.为了解决这个问题,使用NumPy库中的tile()函数将变量内容复制乘输入矩阵同样大小的矩阵。这是具体特征值相处。

测试算法:作为完整程序验证分类器

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

完美分类器的错误量为0,而错误率为1.0的分类器不会给出任何正确的分类

为了测试分类器效果,我们创建以下函数:

def datingClassTest():
    hoRatio=0.10
    datingDataMat=datingLabels=file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals=autoNorm(datingDataMat)
    m=normMat.shape[0]
    errorCount=0.0
    numTestVecs=int(m*hoRatio)
    for i in range(numTestVecs):
        classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,],datingLabels[numTestVecs:m],3)
        print(classifierResult,datingLabels[i])
        if (classifierResult!=datingLabels[i]):errorCount+=1.0
    print(errorCount/float(numTestVecs))

函数datingClassTest首先使用了file2matrix和autoNorm函数从文件中读取数据并将其转化为归一化特征值。接着计算测试向量的数量,这一步决定了normMat向量中哪些数据用于测试,那些数据用于训练;然后将这两部分数据输入到原始kNN分类器函数classify0.最后,函数计算错误率并输出结果。

需要注意,此处我们使用原始分类器。

分类器处理数据集的错误率为5%,这是一个还不错的结果。我们可以改变函数中hoRatio和变量k的值,检测错误率是否会随着变量值的变换而增加,

使用算法:构建完整可用系统

上面已经在数据上对分类器进行了测试,现在可以用这个分类器对人员进行分类:

def classifyPerson():
    resultList=['完全不喜欢','一般魅力','很有魅力']
    percentTats=float(input('每年玩视频游戏的时间比例?'))
    ffMiles=float(input('每年的飞行里程数?'))
    iceCream=float(input('每年吃冰激凌的数量?'))
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals=autoNorm(datingDataMat)
    inArr=array([ffMiles,percentTats,iceCream])
    classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    print('你对于这个人的感受:',resultList[classifierResult-1])

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值