离线计算,验证推荐的准确性(失败)

目的


算好了歌曲的相似度,我们就可以为用户产生推荐列表了。但是,我现在想试试产生的这个推荐列表到底有多准呢?

具体思路


收藏歌曲数大于或等于五十的用户,我会从这位用户已经收藏的歌曲里面随机删掉10%的歌曲,再用剩下的90%歌曲产生推荐列表。推荐列表只产生10首歌曲,比对这10首歌曲与删掉的10%的歌曲的重复度。
比如,收藏数为50的用户,删掉10%,还剩45首,利用这45首产生一个推荐列表:10首歌曲。如果这10首歌曲里面有被删除的那5首,显然准确率是100%。
我考虑了一下,如果收藏歌曲低于100首的,我们我们还是删除10首,高于100首的,我们删除10%。推荐列表只有10首,然后就看推荐列表里面产生了多少首被删除的歌曲。即使一个用户收藏了200首歌曲,会删除20首,但是依据剩余的180首来产生推荐列表10首,就看这推荐列表里面的10首里面有多少首是那20首里面的歌曲。
为了保证推荐的准确性,我决定对每个用户进行十次推荐的过程。所以,以下过程会进行10次,再求出平均值,显然不用加权平均。
  1. 对某一个用户收藏的歌曲
  2. 随机删除10%的歌曲,至少10首
  3. 产生推荐列表:歌曲10首
  4. 比对删除的歌曲和推荐的歌曲,记录推荐的歌曲内有多少首是原本被用户收藏的。
  5. 重复2-4过程10次。将3种10次记录的歌曲数相加再除以10。得到平均值
  6. 该平均值就表明了对这个用户推荐的准确度,是一个0到10的数。
经查询,收藏歌曲在50首以上人数有:3235。如下图所示:



数据存放与展示


计算的结果放在sql里面,先取一个名字吧,由于这次最关键的因素:相似度是由皮尔逊(pearson)计算出来。故表名:precisionbypearson。表里我认为3个数据比较合适
  1. userid int型
  2. favoritecount int型
  3. precision float型

除了用数据库保存结果以外,我觉得还可以,使用昨天画概率的方式来画一个图,那么最后的结果将会非常直观。x轴表示用户数量,y轴来表示准确度。


代码

下面我们来写代码:
import MySQLdb
import copy
from random import random,randint  
import math
import operator#为了让字典以值排序


def countPrecision():
    try:
        #用数组列表,每一个装一个用户的。每个数组装一个字典。
        users=[]
        musics=[]
        testSet=[]
        trainset=[]
        simMusics={}
        #下一句是连好数据库
        conn=MySQLdb.connect(host='localhost',user='root',passwd='root',db='musicrecomsys',port=3306)
        #用拿到执行sql语句的对象
        cur1=conn.cursor()
        count1=cur1.execute('SELECT userid,COUNT( userid )FROM moresmallfavorites GROUP BY userid having COUNT( userid )>400 ORDER by COUNT( userid 


)')
        results1=cur1.fetchall()
        print '开始读取数据.....'
        for r1 in results1:
            users.append({'userid':r1[0],'count':r1[1],'precision':0})
            break#由于我在这里break了,所以实际上只拿了一个用户的数据,我做测试
            
        print '读取数据完毕.....'
        for i in range(len(users)):
            currentId=users[i]['userid']
            precision=0#新的开始,使precision为0
            #下句count1会记录返回了多少歌曲数
            count1=cur1.execute('SELECT musicid FROM moresmallfavorites where userid= %s',[currentId])
            results1=cur1.fetchall()
            for r1 in results1:
                musics.append(r1[0])#就拿到了该用户收藏的歌
            #将收藏的歌曲集分为两部分:trainset和testSet,但先确定testSet的数量:testSetCount
            testSetCount=int(count1*0.1)
            if testSetCount<10:testSetCount=10
            print testSetCount
            for k in range(10):#重复10次这样的过程
                trainset=copy.deepcopy(musics)
                for j in range(testSetCount):
                    deleteCount=randint(0,len(trainset)-1)#生成的随机数n:0<=n<=len(musics)
                    testSet.append(trainset[deleteCount])
                    trainset.pop(deleteCount)#删除指定位置的元素,那么musics就变成了训练集
                #取出musics里面所有的相似的歌,去重,排序,取出前10个
                for j in range(len(trainset)):
                    count1=cur1.execute(' SELECT simmusicid,similarity FROM simmusic where musicid=%s',[musics[j]])
                    results1=cur1.fetchall()
                    for r1 in results1:
                        sim=simMusics.setdefault(r1[0],r1[1])#就拿到了该用户收藏的歌,但是用户收藏的两首歌的相似度歌重复的话,那么就取其中相似度高的


。
                        if sim>=r1[1]:continue
                       else:simMusics['r1[0]']=r1[1]
                #sortedSimMusics是一个以值降序排列的含二元元组的列表
                sortedSimMusics=sorted(simMusics.iteritems(), key=operator.itemgetter(1),reverse=True)#这时候是降序的
                for j in range(30):#我们只验证推荐列表里面的前30首歌是否属于测试集testSet
                    if sortedSimMusics[j][0] in testSet:precision+=1
            precision*=0.1
            print precision
        cur1.close()
        conn.close()
    except MySQLdb.Error,e:
        print "Mysql Error %d: %s" % (e.args[0], e.args[1])


失败


我上段代码,我没有写插入数据库的代码。而且由于一条break指令,让我只是对一个用户进行了测试。
代码写好后,当我对几个用户(收藏个数在50,400,600等)进行测试的时候,发现特别难得到我认为比较理想的数据。反而总是得到0,也就是我打算推荐的10首里没有一首用户收藏的,然后又被我们去掉了的歌曲。

当我以收藏了601首歌曲的用户为例时,那么测试集里面就会有61首歌曲,如果我只推荐相似度最高的前10首,那么我只能得到0,但是相似度最高的前20首,会得到1.3,相似度最高的30首,那么就会得到1.9和2.0。又不能说明相似度高的歌曲是不值得推荐的,也许用户只是暂时还没有发现这首歌曲。但是从离线计算的角度来看,确实我没有得到好的结果。


主要原因


这主要是因为:在相似度计算的过程中,有些歌曲的相似度数值高,所以我从训练集里面将所有的歌曲的相似度找到之后,排个序后,那么那些相似度高的歌曲将会排在前面。但是这些相似度高,又恰好不是测试集里面的数据。这样就导致我这样的验证方式几乎完全失效。最关键的原因就是,我不知道该如何从该用户收藏的歌中的相似歌来分配权重。用户收藏了那么多歌,每首歌有10首相似度,就算我选相似度高的,也未必正确。当然,这只是从离线计算的角度来看,确实是不容易能够命中被我随机删除了的用户已经收藏的歌曲。

总之,推荐列表不能如此单纯的仅仅以歌曲相似度来产生。面对一个用户产生推荐列表时,我必须考虑的更为综合和全面。

总结


总之我打算再做一些调查,看一下如何解决这个问题。
  1. 首先再分析一下这篇论文:基于音乐基因组的个性化移动音乐推荐系统_李瑞敏,毕竟中中文核心期刊。
  2. 其次是再看一些推荐关于推荐的书。比如:Recommender Systems Handbook


注意

  1. 我们利用了收藏数从80到500的用户来计算了歌曲的相似度,所以这部分用户的推荐准确概率应该是要高很多。然而,实际证明还是非常低的。
  2. 我们没有考虑歌曲被用户收藏的先后顺序,然而我认为这一点是有必要考虑,也就是最新收藏的歌曲的权重应该要高一些。



源代码


MusicRecom.py,没有上传网盘,在我的笔记本里,因为我只是复制了RealDataRecommendationformusic.py,然后多加了一个函数而已。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值