guide2datamining阅读笔记(1)

推荐系统入门

最近无意间看到了面向程序员的数据挖掘导论,看了第一段就感觉很简单粗暴,看了第一章,记录一下吧~
第一章主要内容:

  • 推荐系统工作原理
  • 社会化协同过滤工作原理
  • 如何找到相似物品
  • 曼哈顿距离
  • 欧几里得距离
  • 闵可夫斯基距离
  • 皮尔逊相关系数
  • 余弦相似度
  • 使用Python实现K最邻近算法

协同过滤

就是根据他人的兴趣爱好来推荐,工作原理大概就是:我想要给你推荐一首歌,我会在所有有记录用户找一个最和你相似的,然后根据他的爱好来进行推荐。
辣么怎么样来找到最和你相似的用户呢?很多方法啊,先说根据距离计算:

  • 曼哈顿距离

  • 欧几里得距离

这两种方法都有一个问题,就是只能采用同时都有评价记录的数据。
将这两种方法可以推广成闵可夫斯基距离,公式是:

 d(x,y)=i=0n (|xiyi|r)1r

其中,r=1即为曼哈顿距离,r=2就是欧几里得距离。。。
注意

r值越大,单个维度的差值大小会对整体距离有更大的影响。

皮尔逊系数

由每个用户的打分标准非常不同,所以有“分数膨胀”的现象产生。例如:

  • Bill没有打出极端的分数,都在2至4分之间;
  • Jordyn似乎喜欢所有的乐队,打分都在4至5之间;
  • Hailey是一个有趣的人,他的分数不是1就是4。

解决方法之一就是使用皮尔逊相关系数,从图表上理解,两个用户意见相一致表现为一条直线。皮尔逊相关系数用于衡量两个变量之间的相关性,它的值在-1至1之间,1表示完全吻合,-1表示完全相悖。我们利用这一点来找到相似的用户。
皮尔逊相关系数的公式:

r=ni=1(xix¯)(yiy¯)ni=1(xix¯)2ni=1(yiy¯)2

上面的公式除了看起来比较复杂,另一个问题是要获得计算结果必须对数据做多次遍历。一般使用另外一个近似公式计算皮尔逊相关系数的近似值,比较复杂,就不列出了。其最大的优点是可以在实现时仅遍历一边数据。

余弦相似度

余弦相似度。它在文本挖掘中应用得较多,在协同过滤中也会使用到。
当单个用户的数据是稀疏的,即非零值较总体要少得多。

类似的情况是在计算两篇文章的相似度时。比如说我们想找一本和《The Space Pioneers》相类似的书,方法之一是利用单词出现的频率,即统计每个单词在书中出现的次数占全书单词的比例,如“the”出现频率为6.13%,“Tom” 0.89%,“space” 0.25%。我们可以用这些数据来寻找一本相近的书。但是,这里同样有数据的稀疏性问题。《The Space Pioneers》中有6629个不同的单词,但英语语言中有超过100万个单词,这样一来非零值就很稀少了,也就不能计算两本书之间的距离。

余弦相似度的计算中会略过这些零值匹配。它的计算公式是:

cos(x,y)=xy||x||×||y||

其中,“·”号表示数量积。“||x||”表示向量x的模,计算公式是: ni=1x2i

余弦相似度的范围从1到-1,1表示完全匹配,-1表示完全相悖。

根据不同的数据选择方法

  • 如果数据存在“分数膨胀”问题,就使用皮尔逊相关系数。
  • 如果数据比较“密集”,变量之间基本都存在公有值,且这些距离数据是非常重要的,那就使用欧几里得或曼哈顿距离。
  • 如果数据是稀疏的,则使用余弦相似度。

K近邻算法

只依靠最相似的 一个 用户来做推荐,如果这个用户有些特殊的偏好,就会直接反映在推荐内容里,这样推荐效果并不是最好的。解决方法之一是找寻多个相似的用户,这里就要用到K最邻近算法了。

最后把书里的题目实现了一下:

本书的网站上有一个包含25部电影评价的数据集,实现一个推荐算法。

#-*-encoding:utf-8-*-
import csv
from math import sqrt

class recommender:
    def __init__(self,data={},k=3,metric='pearson',n=5):
        self.data=data
        self.k=k
        self.metric=metric
        self.n=n
        if metric=='pearson':
            self.cal=self.metric

    def loadData(self,path=''):
        self.data={}
        users=[]
        i = 0
        with open(path+'Movie_Ratings.csv', newline='',encoding='utf-8') as f:
            reader = csv.reader(f)
            for line in reader:
                if i==0:
                    fields=str(line).split(',')
                    for x in fields:
                        if x!='':
                            key=x.strip('\ []"').strip("'").strip()
                            if key!='':
                                self.data[key]={}
                                users.append(key)
                    i=i+1
                else:
                    fields=str(line).split(",")
                    filmname=fields[0].strip().strip('\[]\'"')
                    for j in range(1,len(fields)):
                        if fields[j].strip().strip('\[]\'"')!='':
                            self.data[users[j-1]][filmname]=fields[j]

    def pearson(self,rating1={}, rating2={}):
        sum_xiyi,n=0.0,0
        sum_xi,sum_yi=0.0,0.0
        sum_xi2,sum_yi2=0.0,0.0
        for x1 in rating1:
            if x1 in rating2:
                x,y=int(rating1[x1].strip().strip('\[]\'"')),int(rating2[x1].strip().strip('\[]\'"'))
                sum_xiyi+=x*y
                sum_xi+=x
                sum_yi+=y
                sum_xi2+=pow(x,2)
                sum_yi2+=pow(y,2)
                n+=1
        denominator=sqrt(sum_xi2-pow(sum_xi,2)/n)*sqrt(sum_yi2-pow(sum_yi,2)/n)
        if denominator==0:
            return 0
        else:   
            return (sum_xiyi-(sum_xi*sum_yi)/n)/denominator

    def computeNearestNeighbor(self,username):
        nearestList=[]
        for user in self.data:
            if user!=username:
                dis=self.pearson(self.data[user],self.data[username])
                nearestList.append([user,dis])
        return sorted(nearestList,key=lambda x:nearestList[1],reverse=True)

    def recommend(self,username):
        nearestList=self.computeNearestNeighbor(username)
        totalDistance=0.0
        userrating=self.data[username]
        recommendations={}
        #先计算权重ss
        for i in range(self.k):
            totalDistance+=nearestList[i][1]
        #选出前k个和指定user接近的,汇总评分   
        for i in range(self.k):
            weight=nearestList[i][1]/totalDistance
            #获取第i个用户的评分记录
            neighborRating=self.data[nearestList[i][0]]
            #获得第I个邻居评价了但user没有评价过的电影,并存入其加权评分
            for film in neighborRating:
                if film not in userrating:
                    if  film not in recommendations:
                        recommendations[film]=float(neighborRating[film].strip().strip('\[]\'"'))*weight
                    else:
                        recommendations[film]+=float(neighborRating[film].strip().strip('\[]\'"'))*weight
        #开始推荐
        recommendations=list(recommendations.items())[:self.n]
        return sorted(recommendations,key=lambda x:x[1],reverse=True)

if __name__ == '__main__':
    r=recommender()
    r.loadData('D:\\')
    print(r.recommend('vanessa'));

你可能感兴趣的:(算法学习,python大法好,读书笔记)