「集合知プログラミング」では、インターネットを通じて集合知のモトとなるデータを集め、取り扱う方法が説明されています。
その2章「推薦を行う」にて「del.icio.usのリンクを推薦するシステム」の説明があります。delicious(デリーシャス)とは、ソーシャルブックマークサイトです。簡単に言えば、お気に入りのサイトを公開して共有するサービスです。
del.icio.us
https://delicious.com/
沢山の人が、お気に入りのブックマークを登録しています。登録されているブックマークを分析して、ある人と同じ嗜好を持つ人を探しだすプログラムを作ります。さらに、その人が好みそうなリンクを推薦するシステムを作ります。
「集合知プログラミング」では、Pythonのコードでの説明がされています。この「del.icio.usのリンクを推薦するシステム」では、Pythonのモジュール「pydelicious」を使います。
検証は、Mac OS X 10.7.5のPython 2.7.1で行います。
「pydelicious」のバージョンは、「pydelicious-0.6」を使用します。
下記のソースは、del.icio.usのデータセットを作る処理本体の deliciousrec.py の内容です。
書籍の記載のままでは、動作しない箇所があります。1行目「import time」の記載不足、8行目「for p2 in get_urlposts(p1['href']):」24行目「url=post['href']」は、del.icio.usのAPIの仕様変更により、「for p2 in get_urlposts(p1['url']):」「url=post['url']」への修正が必要です。
その2章「推薦を行う」にて「del.icio.usのリンクを推薦するシステム」の説明があります。delicious(デリーシャス)とは、ソーシャルブックマークサイトです。簡単に言えば、お気に入りのサイトを公開して共有するサービスです。
del.icio.us
https://delicious.com/
沢山の人が、お気に入りのブックマークを登録しています。登録されているブックマークを分析して、ある人と同じ嗜好を持つ人を探しだすプログラムを作ります。さらに、その人が好みそうなリンクを推薦するシステムを作ります。
「集合知プログラミング」では、Pythonのコードでの説明がされています。この「del.icio.usのリンクを推薦するシステム」では、Pythonのモジュール「pydelicious」を使います。
検証は、Mac OS X 10.7.5のPython 2.7.1で行います。
「pydelicious」のバージョンは、「pydelicious-0.6」を使用します。
下記のソースは、del.icio.usのデータセットを作る処理本体の deliciousrec.py の内容です。
書籍の記載のままでは、動作しない箇所があります。1行目「import time」の記載不足、8行目「for p2 in get_urlposts(p1['href']):」24行目「url=post['href']」は、del.icio.usのAPIの仕様変更により、「for p2 in get_urlposts(p1['url']):」「url=post['url']」への修正が必要です。
import time
from pydelicious import get_popular,get_userposts,get_urlposts
def initializeUserDict(tag,count=5):
user_dict={}
for p1 in get_popular(tag=tag)[0:count]:
for p2 in get_urlposts(p1['url']):
user=p2['user']
user_dict[user]={}
return user_dict
def fillItems(user_dict):
all_items={}
for user in user_dict:
for i in range(3):
try:
posts=get_userposts(user)
break
except:
print "Failed user "+user+", retrying"
time.sleep(4)
for post in posts:
url=post['url']
user_dict[user][url]=1.0
all_items[url]=1
for ratings in user_dict.values():
for item in all_items:
if item not in ratings:
ratings[item]=0.0
あと、推薦をするプログラム recommendations.py が必要です。
from math import sqrt
# Returns a distance-based similarity score for person1 and person2
def sim_distance(prefs,person1,person2):
# Get the list of shared_items
si={}
for item in prefs[person1]:
if item in prefs[person2]: si[item]=1
# if they have no ratings in common, return 0
if len(si)==0: return 0
# Add up the squares of all the differences
sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2)
for item in prefs[person1] if item in prefs[person2]])
return 1/(1+sum_of_squares)
# Returns the Pearson correlation coefficient for p1 and p2
def sim_pearson(prefs,p1,p2):
# Get the list of mutually rated items
si={}
for item in prefs[p1]:
if item in prefs[p2]: si[item]=1
# if they are no ratings in common, return 0
if len(si)==0: return 0
# Sum calculations
n=len(si)
# Sums of all the preferences
sum1=sum([prefs[p1][it] for it in si])
sum2=sum([prefs[p2][it] for it in si])
# Sums of the squares
sum1Sq=sum([pow(prefs[p1][it],2) for it in si])
sum2Sq=sum([pow(prefs[p2][it],2) for it in si])
# Sum of the products
pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])
# Calculate r (Pearson score)
num=pSum-(sum1*sum2/n)
den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
if den==0: return 0
r=num/den
return r
# Returns the best matches for person from the prefs dictionary.
# Number of results and similarity function are optional params.
def topMatches(prefs,person,n=5,similarity=sim_pearson):
scores=[(similarity(prefs,person,other),other)
for other in prefs if other!=person]
scores.sort()
scores.reverse()
return scores[0:n]
# Gets recommendations for a person by using a weighted average
# of every other user's rankings
def getRecommendations(prefs,person,similarity=sim_pearson):
totals={}
simSums={}
for other in prefs:
# don't compare me to myself
if other==person: continue
sim=similarity(prefs,person,other)
# ignore scores of zero or lower
if sim<=0: continue
for item in prefs[other]:
# only score movies I haven't seen yet
if item not in prefs[person] or prefs[person][item]==0:
# Similarity * Score
totals.setdefault(item,0)
totals[item]+=prefs[other][item]*sim
# Sum of similarities
simSums.setdefault(item,0)
simSums[item]+=sim
# Create the normalized list
rankings=[(total/simSums[item],item) for item,total in totals.items()]
# Return the sorted list
rankings.sort()
rankings.reverse()
return rankings
def transformPrefs(prefs):
result={}
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
# Flip item and person
result[item][person]=prefs[person][item]
return result
def calculateSimilarItems(prefs,n=10):
# Create a dictionary of items showing which other items they
# are most similar to.
result={}
# Invert the preference matrix to be item-centric
itemPrefs=transformPrefs(prefs)
c=0
for item in itemPrefs:
# Status updates for large datasets
c+=1
if c%100==0: print "%d / %d" % (c,len(itemPrefs))
# Find the most similar items to this one
scores=topMatches(itemPrefs,item,n=n,similarity=sim_distance)
result[item]=scores
return result
def getRecommendedItems(prefs,itemMatch,user):
userRatings=prefs[user]
scores={}
totalSim={}
# Loop over items rated by this user
for (item,rating) in userRatings.items( ):
# Loop over items similar to this one
for (similarity,item2) in itemMatch[item]:
# Ignore if this user has already rated this item
if item2 in userRatings: continue
# Weighted sum of rating times similarity
scores.setdefault(item2,0)
scores[item2]+=similarity*rating
# Sum of all the similarities
totalSim.setdefault(item2,0)
totalSim[item2]+=similarity
# Divide each total score by total weighting to get an average
rankings=[(score/totalSim[item],item) for item,score in scores.items( )]
# Return the rankings from highest to lowest
rankings.sort( )
rankings.reverse( )
return rankings
def loadMovieLens(path='/data/movielens'):
# Get movie titles
movies={}
for line in open(path+'/u.item'):
(id,title)=line.split('|')[0:2]
movies[id]=title
# Load data
prefs={}
for line in open(path+'/u.data'):
(user,movieid,rating,ts)=line.split('\t')
prefs.setdefault(user,{})
prefs[user][movies[movieid]]=float(rating)
return prefs
用意ができたので、Pythonのインタラクティブシェルで動作を確認します。
#必要なモジュールの読み込み
>>> import recommendations
>>> from deliciousrec import *
>>> import random
# 「design」というタグを付けているユーザーの取得
>>> delusers=initializeUserDict('design')
# 取得した各ユーザーのリンクを取得
>>> fillItems(delusers)
# 取得したユーザー達の中からランダムに1人を取得
>>> user=delusers.keys()[random.randint(0,len(delusers)-1)]
# このユーザーに似ているユーザーをリストアップ
>>> recommendations.topMatches(delusers,user)
[
(0.5344262295081967, u'thehrisworld'),
(-0.16393442622950818, u'yaax'),
(-0.16393442622950818, u'tchiule'),
(-0.16393442622950818, u'sneurgaonkar'),
(-0.16393442622950818, u'sethkontny')
]
# このユーザーが好みそうなリンクを推薦
>>> recommendations.getRecommendations(delusers,user)[0:10]
[
(1.0, u'http://www.youtube.com/watch?v=C5tOEBmBAHg'),
(1.0, u'http://www.lifeisstory.com/'),
(1.0, u'http://techcrunch.com/2013/09/06/what-to-do-if-you-get-a-troll-demand/'),
(1.0, u'http://on.mash.to/1dJDvYC'),
(0.0, u'https://www.facebook.com/sethkontny/posts/10201536626993865'),
(0.0, u'https://communities.vmware.com/community/vmtn/vcloud-automation-center'),
(0.0, u'http://www.yorkdispatch.com/breaking/ci_24031648/more-sleep-better-kids-but-too-much-trouble'),
(0.0, u'http://www.wpcentral.com/geophoto-windows-phone-8-helping-you-remember-where-you-took-photo'),
(0.0, u'http://www.wired.com/wiredscience/2013/09/wired-space-photo-of-the-day-saturn-storm-circles-planet/'),
(0.0, u'http://www.wired.com/wiredscience/2013/09/what-exactly-is-astrovirology/')
]

0 件のコメント:
コメントを投稿