该内容已被发布者删除 该内容被自由微信恢复
文章于 2017年4月2日 被检测为删除。
查看原文
被用户删除
其他

用 kNN 算法预测豆瓣电影用户的性别

2015-10-26 Python开发者

(点击上方公号,可快速关注)


出处: 夏方方(@陆晨炜)

网址:http://www.cnblogs.com/xiaff/p/4858332.html


摘要


本文认为不同性别的人偏好的电影类型会有所不同,因此进行了此实验。利用较为活跃的274位豆瓣用户最近观看的100部电影,对其类型进行统计,以得到的37种电影类型作为属性特征,以用户性别作为标签构建样本集。使用kNN算法构建豆瓣电影用户性别分类器,使用样本中的90%作为训练样本,10%作为测试样本,准确率可以达到81.48%。


实验数据


本次实验所用数据为豆瓣用户标记的看过的电影,选取了274位豆瓣用户最近看过的100部电影。对每个用户的电影类型进行统计。本次实验所用数据中共有37个电影类型,因此将这37个类型作为用户的属性特征,各特征的值即为用户100部电影中该类型电影的数量。用户的标签为其性别,由于豆瓣没有用户性别信息,因此均为人工标注。


数据格式如下所示:


X1,1,X1,2,X1,3,X1,4……X1,36,X1,37,Y1

X2,1,X2,2,X2,3,X2,4……X2,36,X2,37,Y2

…………

X274,1,X274,2,X274,3,X274,4……X274,36,X274,37,Y274


示例:


0,0,0,3,1,34,5,0,0,0,11,31,0,0,38,40,0,0,15,8,3,9,14,2,3,0,4,1,1,15,0,0,1,13,0,0,1,1 0,1,0,2,2,24,8,0,0,0,10,37,0,0,44,34,0,0,3,0,4,10,15,5,3,0,0,7,2,13,0,0,2,12,0,0,0,0


像这样的数据一共有274行,表示274个样本。每一个的前37个数据是该样本的37个特征值,最后一个数据为标签,即性别:0表示男性,1表示女性。


kNN算法


k-近邻算法(KNN),是最基本的分类算法,其基本思想是采用测量不同特征值之间的距离方法进行分类。


算法原理:存在一个样本数据集合(训练集),并且样本集中每个数据都存在标签(即每一数据与所属分类的关系已知)。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较(计算欧氏距离),然后提取样本集中特征最相似数据(最近邻)的分类标签。一般会取前k个最相似的数据,然后取k个最相似数据中出现次数最多的标签(分类)最后新数据的分类。


在此次试验中取样本的前10%作为测试样本,其余作为训练样本。


首先对所有数据归一化。对矩阵中的每一列求取最大值(max_j)、最小值(min_j),对矩阵中的数据X_j,

X_j=(X_j-min_j)/(max_j-min_j) 。


然后对于每一条测试样本,计算其与所有训练样本的欧氏距离。测试样本i与训练样本j之间的距离为:

distance_i_j=sqrt((Xi,1-Xj,1)^2+(Xi,2-Xj,2)^2+……+(Xi,37-Xj,37)^2) ,

对样本i的所有距离从小到大排序,在前k个中选择出现次数最多的标签,即为样本i的预测值。


实验结果


首先选择一个合适的k值。 对于k=1,3,5,7,均使用同一个测试样本和训练样本,测试其正确率,结果如下表所示。


表1 选取不同k值的正确率表

k1357
测试集162.96%81.48%70.37%77.78%
测试集266.67%66.67%59.26%62.96%
测试集362.96%74.07%70.37%74.07%
平均值64.20%74.07%66.67%71.60%


由上述结果可知,在k=3时,测试的平均正确率最高,为74.07%,最高可以达到81.48%。


上述不同的测试集均来自同一样本集中,为随机选取所得。


Python代码


这段代码并非原创,来自《机器学习实战》(Peter Harrington,2013),并有所改动。


#coding:utf-8

from numpy import *

import operator

def classify0(inX, dataSet, labels, k):

dataSetSize = dataSet.shape[0]

diffMat = tile(inX, (dataSetSize,1)) - dataSet

sqDiffMat = diffMat**2

sqDistances = sqDiffMat.sum(axis=1)

distances = sqDistances**0.5

sortedDistIndicies = distances.argsort()

classCount={}

for i in range(k):

voteIlabel = labels[sortedDistIndicies[i]]

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

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

return sortedClassCount[0][0]

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)) #element wise divide

return normDataSet, ranges, minVals

def file2matrix(filename):

fr = open(filename)

numberOfLines = len(fr.readlines()) #get the number of lines in the file

returnMat = zeros((numberOfLines,37)) #prepare matrix to return

classLabelVector = [] #prepare labels return

fr = open(filename)

index = 0

for line in fr.readlines():

line = line.strip()

listFromLine = line.split(',')

returnMat[index,:] = listFromLine[0:37]

classLabelVector.append(int(listFromLine[-1]))

index += 1

fr.close()

return returnMat,classLabelVector

def genderClassTest():

hoRatio = 0.10 #hold out 10%

datingDataMat,datingLabels = file2matrix('doubanMovieDataSet.txt') #load data setfrom file

normMat,ranges,minVals=autoNorm(datingDataMat)

m = normMat.shape[0]

numTestVecs = int(m*hoRatio)

testMat=normMat[0:numTestVecs,:]

trainMat=normMat[numTestVecs:m,:]

trainLabels=datingLabels[numTestVecs:m]

k=3

errorCount = 0.0

for i in range(numTestVecs):

classifierResult = classify0(testMat[i,:],trainMat,trainLabels,k)

print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])

if (classifierResult != datingLabels[i]):

errorCount += 1.0

print "Total errors:%d" %errorCount

print "The total accuracy rate is %f" %(1.0-errorCount/float(numTestVecs))



Python开发者

微信号:PythonCoder

可能是东半球最好的 Python 微信号

--------------------------------------

投稿网址:top.jobbole.com

商务合作QQ:2302462408


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存