当前位置:   article > 正文

python 简单的数据挖掘_python 数据挖掘

差值矩阵

python -- 面向程序员的数据挖掘指南-推荐系统入门-004

import pandas as pd

import numpy as np

还有一种比较流行的基于物品的协同过滤算法,名为Slope One,它最大的优势是简单,因此易于实现。

Slope One算法是在一篇名为《Slope One:基于在线评分系统的协同过滤算法》的论文中提出的,由Lemire和Machlachlan合著。这篇论文非常值得一读。

我们用一个简单的例子来了解这个算法。假设Amy给PSY打了3分,Whitney Houston打了4分;Ben给PSY打了4分。我们要预测Ben会给Whitney Houston打几分。 用表格来描述这个问题即:

我们可以用以下逻辑来预测Ben对Whitney Houston的评分:由于Amy给Whitney Houston打的分数要比PSY的高一分,所以我们预测Ben也会给高一分,即给到5分。

这就是Slope One算法:Slope One算法是基于不同物品之间的评分差的线性算法,预测用户对物品评分的个性化算法。

你可以将Slope One分为两个步骤:

Step1:计算物品之间的评分差的均值,记为物品间的评分偏差(两物品同时被评分);

Step2:根据物品间的评分偏差和用户的历史评分,预测用户对未评分的物品的评分。

下面用简单的例子来说明一下Slope One算法。

第一步、我们来考察PSY和Taylor Swift之间的差值, 有两个用户(Amy和Ben)同时对PSY和Taylor Swift打过分。

# 计算差值, 一共有2个用户对两者都进行了打分

a = (4-3)+(5-2)

# 计算平均值

b = a/2

print(a, b)

4 2.0

所以PSY和Taylor Swift的差异是2,即用户们给Taylor Swift的评分比PSY要平均高出两分。

试想我们的音乐站点有100万个用户对20万个歌手做评价。如果有一个新用户对10个歌手做了评价,我们是否需要重新计算20万×20万的差异数据,或是有其他更简单的方法?

答案是当然不啦,只需要在差异数据的基础上更新即可,完全没必要重新计算一遍差异数据。

举个例子,说明一下:

比如说Taylor Swift和PSY的差值是2,假设是根据9位用户的评价计算得到的。当有一个新用户对Taylor Swift打了5分,PSY打了1分时,更新后的差值为:

# 计算差异总值,再求平均值

print('差值为',(9*2+4)/(9+1))

差值为 2.2

第二步:使用加权的Slope One算法进行预测

好,现在我们有了物品之间的差异值,下面就用它来进行预测。这里我们将使用加权的Slope One算法来进行预测, 计算出Ben对Whitney Houston的预测评分

1、Ben的打分的有['Taylor Swift', 'PSY'];

2、计算Whitney Houston 和 Taylor Swift的差值:Amy: 4-4=0, Daisy: 3-5=-2, 即差值均 值为 -1;

3、Ben对Taylor Swift 打5分,根据Whitney Houston 和 Taylor Swift的差值,计算Ben对Whitney Houston的预测评分: 5-1=4;

4、计算Whitney Houston 和 PSY 的差值:Amy: 4-3=1, Clara: 4-3.5=0.5, 即差值均值为 (1+0.5)/2=0.75;

5、Ben对 PSY 打2分,根据Whitney Houston 和 PSY 的差值,计算Ben对Whitney Houston的预测评分: 2+0.75=2.75;

6、计算加权分值:(4*2+2.75*2)/(2+2)=3.375。

users = {"Amy": {"Taylor Swift": 4, "PSY": 3, "Whitney Houston": 4},

"Ben": {"Taylor Swift": 5, "PSY": 2},

"Clara": {"PSY": 3.5, "Whitney Houston": 4},

"Daisy": {"Taylor Swift": 5, "Whitney Houston": 3}}

df = pd.DataFrame(users)

print(df)

Amy Ben Clara Daisy

Taylor Swift 4 5.0 NaN 5.0

PSY 3 2.0 3.5 NaN

Whitney Houston 4 NaN 4.0 3.0

1、计算差值矩阵

# 计算差值矩阵

def computeDeviations(data):

result = {}

for b1 in data.iterrows():

result[b1[0]] = {}

for b2 in data.iterrows():

temp = (b1[1]-b2[1]).dropna()

result[b1[0]][b2[0]] = temp.mean()

result = pd.DataFrame(result)

return result

print(computeDeviations(df))

####################################

Taylor Swift PSY Whitney Houston

Taylor Swift 0.0 -2.00 -1.00

PSY 2.0 0.00 0.75

Whitney Houston 1.0 -0.75 0.00

2、预测加权分数

# 预测加权分数

def predictRating(user, data):

result = computeDeviations(data)

# 获取用户需要预测的项目

pre_user = list(data[user][data[user].isna()].index)

for index in pre_user:

#计算分值

score = (result[index]+data[user]).dropna()

#计算加权系数

x = {}

for item in score.index:

x[item] = len(data.reindex([index,item]).dropna(axis=1).index)

x = pd.Series(x)

print((score*x).sum()/x.sum())

predictRating('Ben', df)

3.375

老规矩,编写成一个推荐类

class recommender:

def __init__(self, data):

self.data = data

self.recomment = []

# 计算差值矩阵

def computeDeviations(self):

result = {}

for b1 in self.data.iterrows():

result[b1[0]] = (b1[1]-self.data).mean(axis=1)

self.deviations = pd.DataFrame(result)

# 预测加权分数

def predictRating(self, user):

# 获取用户需要预测的项目

pre_user = list(self.data[user][self.data[user].isna()].index)

for index in pre_user:

#计算分值

score = (self.deviations[index]+self.data[user]).dropna()

#计算加权系数

x = {}

for item in score.index:

x[item] = len(self.data.reindex([index,item]).dropna(axis=1).index)

x = pd.Series(x)

self.recomment.append([(score*x).sum()/x.sum(), index])

下面我们为Clara推荐:

r = recommender(df)

r.computeDeviations()

r.predictRating('Clara')

print(r.recomment)

[[5.25, 'Taylor Swift']]

Slope One算法适用于物品更新不频繁,数量相对较稳定并且物品数目明显小于用户数的场景。依赖用户的用户行为日志和物品偏好的相关内容。

优点:

1.算法简单,易于实现,执行效率高;

2.可以发现用户潜在的兴趣爱好;

缺点:

依赖用户行为,存在冷启动问题和稀疏性问题。

MovieLens数据集

让我们在另一个数据集上尝试一下Slope One算法。 MovieLens数据集是由明尼苏达州大学的GroupLens研究项目收集的,是用户对电影的评分。这个数据集可以在http://www.grouplens.org下载,有三种大小,这里我使用的是最小的那个,包含了943位用户对1682部电影的评价,约10万条记录。

df = pd.read_csv('./datamining/ml-latest-small/ratings.csv')

result = {}

for item in df.iterrows():

if not result.get(item[1]['userId']):

result[item[1]['userId']] = {}

result[item[1]['userId']][item[1]['movieId']] = item[1]['rating']

print(len(result))

df = pd.DataFrame(result)

610

class recommender:

def __init__(self,data):

self.frequency={}

self.deviation={}

self.data=data

#计算所有item之间评分偏差

def computeDeviation(self):

for ratings in self.data.values():

for item,rating in ratings.items():

self.frequency.setdefault(item,{})

self.deviation.setdefault(item,{})

for item2,rating2 in ratings.items():

if item!=item2:

self.frequency[item].setdefault(item2,0)

self.deviation[item].setdefault(item2,0.0)

self.frequency[item][item2]+=1#两个项目的用户数

self.deviation[item][item2]+=(rating-rating2)#累加两个评分差值

for item,ratings in self.deviation.items():

for item2 in ratings:

ratings[item2]/=self.frequency[item][item2]

#评分预测

def predictRating(self,userRatings,k):

recommendations={}

frequencies={}

for item,rating in userRatings.items():

for diffItem,diffRating in self.deviation.items():

if diffItem not in userRatings and item in self.deviation[diffItem]:

fre=self.frequency[diffItem][item]

recommendations.setdefault(diffItem,0.0)

frequencies.setdefault(diffItem,0)

#分子部分

recommendations[diffItem]+=(diffRating[item]+rating)*fre

#分母部分

frequencies[diffItem]+=fre

recommendations=[(k,v/frequencies[k]) for (k,v) in recommendations.items()]

#排序返回前k个

recommendations.sort(key=lambda a_tuple:a_tuple[1],reverse=True)

return recommendations[:k]

r=recommender(result)

r.computeDeviation()

u=result[5]

print(r.predictRating(u,5))

[(5746.0, 9.5), (6835.0, 9.5), (5764.0, 9.0), (7899.0, 9.0), (136850.0, 6.5)]

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号