数学建模社区-数学中国

标题: 求协同过滤算法程序 [打印本页]

作者: harveymao    时间: 2014-7-18 23:21
标题: 求协同过滤算法程序
本人在学校参加暑假培训,需要这个算法做题!求大神赐教,感激不尽
% G  Y( E3 {. B7 {- q" E* B: M6 v
作者: 百年孤独    时间: 2014-7-19 09:22
# -*- coding=utf-8 -*-6 W# V# D" e$ E+ h8 ]9 {

+ D# ?4 v8 x% F! Z! fimport math
& ^3 b2 e. d0 N9 T( c! o& qimport sys
% N- ^2 s- F% K+ i5 cfrom texttable import Texttable
/ S# U$ ~' u/ F; b3 y  A% p/ r$ R& p3 N. ~5 r6 @" r; V

8 f( i! r' a) {" C; g- B#
- p; ^  u: U, n) b# Z2 k" S#   使用 |A&B|/sqrt(|A || B |)计算余弦距离0 T$ a  W* X0 ^* k! T2 a# i2 T
#6 G/ W8 i9 ?5 e) y
## G) A2 R- W- H* c/ `2 M2 u8 W
#/ V0 |8 |4 T: q' p
def calcCosDistSpe(user1,user2):
" A/ p7 p2 j# C    avg_x=0.0
& _$ r6 z* U: y! V    avg_y=0.0
) }; F6 w$ Y: E' f    for key in user1:' A1 X1 B  s# R$ X9 M- m
        avg_x+=key[1]
# z1 u* o" V  Y) O. U' R; _7 }. f    avg_x=avg_x/len(user1)% \, \0 C$ V% I  i- s- Q
   
# t9 R$ b, Y9 `4 Y( n    for key in user2:+ M2 @* n$ p; m2 q- @: ~0 k
        avg_y+=key[1]
! x8 D( n# |& ^" w; n    avg_y=avg_y/len(user2)
- u$ P6 B& U  u: `5 Y0 o1 R   
: l2 z& w/ t, G9 B, E: Q4 o    u1_u2=0.0
9 ?/ j0 P. a4 @; z    for key1 in user1:* I# x2 x' d* W0 S& k
        for key2 in user2:
0 F% U  w7 d) w4 E+ Y$ f            if key1[1] > avg_x and key2[1]>avg_y and key1[0]==key2[0]:6 K- Y" \; {& v% J
                u1_u2+=1
% Z& ?" V" {3 ~9 C    u1u2=len(user1)*len(user2)*1.0
& P7 Q7 V& y1 |0 R7 |5 d2 a    sx_sy=u1_u2/math.sqrt(u1u2)" H0 d  `! e  v
    return sx_sy
7 T  J$ \& q0 W* ]" H- g3 B' [" c+ R) J- H/ {5 O5 B
0 V1 o7 f. }) G, B( q3 R$ @- k" B
#" ~8 u  w# j! q/ L8 I
#   计算余弦距离
6 j5 Z$ P: d. D5 \* s#( N( i- K  ~& g! d* p; n* X2 `
#, U" z8 \: z9 c  c  |( R
def calcCosDist(user1,user2):
3 I7 R$ G" r. k# C. `& v5 ?. A% w    sum_x=0.0
/ |/ B$ b! d- u; c5 }, a8 ?    sum_y=0.0
7 Q; X3 C; }, h( C3 U: v    sum_xy=0.0
$ h$ @9 @$ ~1 t2 @    for key1 in user1:
& y' e; P6 i9 ~; f        for key2 in user2:
, d$ p$ Q5 V5 H- g% D/ G+ h* o6 _' H            if key1[0]==key2[0] :* P/ _. j$ ]7 m& F2 m
                sum_xy+=key1[1]*key2[1]
+ |9 b" u! Y$ h1 F7 b# {4 q0 b                sum_y+=key2[1]*key2[1]5 ?/ w  _) ^* g) T. I2 K5 V
                sum_x+=key1[1]*key1[1]. |, E- v" x) n
    5 Q$ t! G' L6 @
    if sum_xy == 0.0 :
$ S. ~" \2 @1 q5 s) n$ u+ f' Q' S        return 01 ^. z5 \5 I% G5 s. l1 j
    sx_sy=math.sqrt(sum_x*sum_y) . Y& \0 t2 R5 Q  F. o# z; {* `1 }
    return sum_xy/sx_sy1 g) g, L& O" x7 r6 P: T
  }3 U; c9 G$ m' ?
9 ?, V7 t+ S( b8 _, F8 K. y0 \
#" S2 U3 a4 y7 S; r% ]; V
#
$ K0 E4 ^$ w) L& S8 z#   相似余弦距离
! X# S9 T2 `* A, l. M) p; u- u#
% U& ^  t0 B+ |4 Q8 n4 T& \#
" p% v. \; D, ^9 O3 \6 }2 N$ d#  l8 ~  c% y& w
def calcSimlaryCosDist(user1,user2):
# ^# X/ R  _; D' i    sum_x=0.0
( |+ b4 _( [7 g$ [    sum_y=0.0# v+ k: l$ @1 X8 v" h7 T: H
    sum_xy=0.0
' T. M- m4 X; u    avg_x=0.0
& d& O( c2 ^) v$ E    avg_y=0.08 F' `3 M0 ]4 W
    for key in user1:4 j9 {  W7 z) h, E+ Y* Q1 i$ Y% d0 X
        avg_x+=key[1]
8 z* ^5 T3 y0 C- j; [& N    avg_x=avg_x/len(user1)
: \# @4 Y3 L' ^8 E4 \   
' n1 U. O7 D( Q" Y8 K* d    for key in user2:  @' q7 J; g* v% e/ ~' }" e
        avg_y+=key[1]: s$ z$ G& ^! p( f/ U4 A& v
    avg_y=avg_y/len(user2)
) O4 S* X1 v$ D4 K( G( m* J   
! k( |7 L& V6 p: e" `    for key1 in user1:8 L% U0 I3 {$ `# F2 D
        for key2 in user2:
% a  i+ h* I6 v2 X            if key1[0]==key2[0] :
0 ^. h& N! e! t% s2 F                sum_xy+=(key1[1]-avg_x)*(key2[1]-avg_y)7 }7 D- X) g& ^" p* N' R! S7 }
                sum_y+=(key2[1]-avg_y)*(key2[1]-avg_y)1 o9 \" v8 `8 H6 v" \% R
        sum_x+=(key1[1]-avg_x)*(key1[1]-avg_x)
) I6 [* b0 ?" P$ m5 y    0 o2 [9 H: ?2 H
    if sum_xy == 0.0 :' O  \# ^+ d: A% W
        return 05 d' n0 E8 F$ P5 J* g. S
    sx_sy=math.sqrt(sum_x*sum_y)
* h) t4 N3 C) D# w# |    return sum_xy/sx_sy
; c5 V, I7 A: T8 b8 O) `/ v   
0 j" Z$ J; O' Q3 [
# J$ a; M& d" b, L3 f& n#
9 ?. P# `& \- f% I# u#   读取文件3 t: D) a7 d/ G  v: ]4 S' i5 u4 X
#- t& J) s6 ], ~
#
" v; M' d2 b2 Zdef readFile(file_name):- a' n0 u5 A: f5 `
    contents_lines=[]8 P3 _( z) _( @  h) B
    f=open(file_name,"r")
( p0 Q/ s# ]6 S: L. X8 c    contents_lines=f.readlines()
/ |6 e7 @8 {* x( j# `    f.close()
9 X- |( ]1 e/ @( r/ S5 y" L    return contents_lines
. {5 ?. D. }$ ?3 z; i9 _& d" c' V. a9 `

2 y3 i3 C6 o% Q! ^! n" e; x) ]4 A5 z; m3 ]( V+ s
#
4 M& K: I4 z9 N6 Q2 c#   解压rating信息,格式:用户id\t硬盘id\t用户rating\t时间
- A# ]( ^  P7 Z( E# P* {0 w! E#   输入:数据集合
% i# Q& d' |: i$ N( l#   输出:已经解压的排名信息& v6 \5 f. ~& d4 V6 o! w8 q
#
' m8 ]* n2 i) P, q0 H( A. gdef getRatingInformation(ratings):& `9 @! Y; U( U
    rates=[]
+ V% w, O& e2 x    for line in ratings:
# p9 Z0 O  u" T) n0 ?/ a: t4 L        rate=line.split("\t")' A$ V4 ~+ d1 ^- F' V* T6 B
        rates.append([int(rate[0]),int(rate[1]),int(rate[2])])
8 }, r9 p+ l5 D+ m/ j# s, n    return rates
" u! x2 D: ]. U- j! ^' G1 i6 _) d
/ g, H- b8 t/ |- O1 N* L; i( L; x2 ]; b" {, X# U
#' j9 m: h# m/ J8 L5 U5 l
#   生成用户评分的数据结构
+ |3 M: m% j) I1 }9 E#   
) z" t9 Z$ J$ w# J: p$ s#   输入:所以数据 [[2,1,5],[2,4,2]...]
6 b; c4 ?  o& V#   输出:1.用户打分字典 2.电影字典7 d8 U$ O1 c! k( I6 W5 A# U5 B) i
#   使用字典,key是用户id,value是用户对电影的评价,$ C+ }6 t+ W# v$ R* Q# p; U! U
#   rate_dic[2]=[(1,5),(4,2)].... 表示用户2对电影1的评分是5,对电影4的评分是2! X1 f5 z  `. I) [7 f: N
#
& P. c/ X, D' J. g; Sdef createUserRankDic(rates):0 D2 ]+ q) C2 ~  Y
    user_rate_dic={}
4 O6 ~4 h$ ?, U; I    item_to_user={}
8 M7 r& s0 h4 O/ W, E8 v    for i in rates:
! N4 p& c; O8 Y4 H, J" N7 I, P        user_rank=(i[1],i[2])
+ D% C8 M4 F/ ?; {4 z        if i[0] in user_rate_dic:$ {8 W: C1 t; g
            user_rate_dic[i[0]].append(user_rank)' [2 Q" S' P' S1 Y8 Q
        else:" t% n" j+ a* h; h* |# H7 B
            user_rate_dic[i[0]]=[user_rank]- Z0 f+ g- m6 G! V: H5 W; V0 x- v4 y
            $ v' g7 K! c' g& a
        if i[1] in item_to_user:& Z3 ]& J4 y, }/ @
            item_to_user[i[1]].append(i[0])
% v" G0 ~; y2 Z9 F        else:
/ m: B. G. ]8 M            item_to_user[i[1]]=[i[0]]
4 q- f3 Z7 x2 j7 x            
+ R/ e" B( G, g" ~3 ]/ A( U- D    return user_rate_dic,item_to_user4 u8 M- {& A8 K6 R" L6 ~
4 t3 }  ]# R( `9 ^" F0 i2 E- J

7 I$ Y; k9 L8 m#4 F- T( j+ P- ?  D! \. n
#   计算与指定用户最相近的邻居
3 \* b, V. k$ u5 q! j7 k#   输入:指定用户ID,所以用户数据,所以物品数据
- |2 S. t; w* n7 g#   输出:与指定用户最相邻的邻居列表- @+ C. S6 E) m5 B. ~1 Q  C
#& E- ~! M) Y/ X/ h9 Y% G5 w
def calcNearestNeighbor(userid,users_dic,item_dic):
9 K, D$ t% @* Z3 c# [6 S    neighbors=[]( o0 M$ ]& T# H# ^) c
    #neighbors.append(userid)
$ I$ V2 e" ]! B1 H: ~: K    for item in users_dic[userid]:' B4 o1 ^7 M+ d; h; q' J) Z
        for neighbor in item_dic[item[0]]:4 z0 Z* J1 r# W8 |
            if neighbor != userid and neighbor not in neighbors:
, l6 W5 ]! L: x& t                neighbors.append(neighbor)
1 I" Q& e; d8 s( A; g/ v; a      " W8 z5 t4 C' E+ m, }7 C( z
    neighbors_dist=[]
0 _% l' Y; A. ?: g7 P    for neighbor in neighbors:
1 W" w. W2 ^) B        dist=calcSimlaryCosDist(users_dic[userid],users_dic[neighbor])  #calcSimlaryCosDist  calcCosDist calcCosDistSpe
; ?8 ^$ J" t1 P- H+ U5 d) ~/ X8 t        neighbors_dist.append([dist,neighbor])
: Q+ [! R; f- r* B( q2 o' a1 P1 @    neighbors_dist.sort(reverse=True)
) `( d) `: a, k7 N    #print neighbors_dist, Z8 [/ W# e3 m0 ~5 r( L
    return  neighbors_dist. I( a0 m+ f0 l* {$ @0 T

, a4 E: R8 j  u6 Q+ W% E
# m. h1 v1 l# H2 M1 U#4 \4 H1 H5 e4 Q
#   使用UserFC进行推荐
: ^# u2 e* C. }. i#   输入:文件名,用户ID,邻居数量) {7 Y1 j% e+ \9 w; K, j5 Y$ V# V. @
#   输出:推荐的电影ID,输入用户的电影列表,电影对应用户的反序表,邻居列表
& U* V& F  `2 ?3 `  I0 V  ^( y#
* I+ `6 R9 t7 v& w) b3 Wdef recommendByUserFC(file_name,userid,k=5):' n, [0 D- {! n5 |  ^) F7 U5 |1 H
    4 {7 h6 X! ^0 c! o5 }$ P
    #读取文件数据
4 O# t. e0 h/ `! Q: x' y  _    test_contents=readFile(file_name)
: ?4 B$ G. _. V  n9 D" W/ R" i    1 W1 k% Y  P3 X* _
    #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...] / ^: E/ h/ v' t
    test_rates=getRatingInformation(test_contents)
: C* n3 l, X& ~9 R    * t# [" M8 O) j( E+ O
    #格式化成字典数据 & K9 A3 u7 X+ ^( I: f/ z' f
    #    1.用户字典:dic[用户id]=[(电影id,电影评分)...]
" t2 A) g0 |. D5 r! [1 B1 N7 f2 s1 R    #    2.电影字典:dic[电影id]=[用户id1,用户id2...]' |4 `5 c1 {: \) P
    test_dic,test_item_to_user=createUserRankDic(test_rates)
) k* V. @  z6 S% a( A* `- u0 a5 i   
% \2 O# |! Q! R7 e1 C& ~    #寻找邻居. l; l4 U1 ^7 K* R6 a
    neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]
; ?; j, W6 r/ i4 {- L- B        # l: G+ d/ M. i% r' {
    recommend_dic={}
( [) i5 X6 }  }/ E$ e    for neighbor in neighbors:
; E5 R# R* s- V: }( }1 y* P1 ^        neighbor_user_id=neighbor[1]( l5 m4 G, m# ]  k1 w0 a
        movies=test_dic[neighbor_user_id]
' z* ^- `( Q1 o' ~- F4 B1 ~( D        for movie in movies:
4 \) F. R( c8 m            #print movie
5 c( H4 \- ]5 w8 V8 [) w: X" d            if movie[0] not in recommend_dic:3 y8 k. n3 n- K4 }4 w* |
                recommend_dic[movie[0]]=neighbor[0]
: ?& t5 R8 z5 G5 k9 p5 m            else:* U) l  p+ u2 _% b& X- W
                recommend_dic[movie[0]]+=neighbor[0]
( b) s. i9 m& t2 d' g' J    #print len(recommend_dic)4 }* g! H& x2 _. J
    9 R1 Z4 L- x6 v: c# c4 T: t
    #建立推荐列表3 K& M+ G* i/ L$ M1 ^8 Q8 g3 i
    recommend_list=[]
3 d, |! K1 t$ H! B+ p3 g+ N    for key in recommend_dic:
* s9 X8 B: P$ B: z        #print key1 @- k' E  x# n! A" A% e3 I
        recommend_list.append([recommend_dic[key],key])
; v* l( X% H: ]8 V    - X$ `  k: W- J: x8 R$ J0 l: o  f$ Y; f
   
8 W7 K* }5 ?. k) d% i    recommend_list.sort(reverse=True)
" V6 ~" n! W# ?4 v    #print recommend_list
& Q# M2 K/ {/ q" {    user_movies = [ i[0] for i in test_dic[userid]]
' o) W6 Z3 z$ B7 o  @. L3 d" f! k: p0 L8 }7 m) H
    return [i[1] for i in recommend_list],user_movies,test_item_to_user,neighbors4 E5 g9 u3 w' |7 F" K
   
* R& s8 C2 k8 P0 B* d, E   
  N$ y& T9 N% S* |) s
. G$ J( J2 @6 Y7 t#
7 U! e+ }8 m" h2 P+ d#
* e# O  y' R, ~7 k0 h3 P#   获取电影的列表
* Y) q% m3 l' y. Z- w$ Q* l#8 r$ Z# h3 r  B" e
#* `  n* L  c3 b8 d3 H4 O$ X/ h8 H- j
#2 o+ ?% ~, \% O$ d4 e+ n' B
def getMoviesList(file_name):$ C2 z6 m' T( I$ ~, e0 ^
    #print sys.getdefaultencoding()
' ]0 j, z5 v4 `$ J5 i0 J- F    movies_contents=readFile(file_name)/ y& j% R& s/ \2 I% i4 R
    movies_info={}
+ e" c" j# ], I2 }    for movie in movies_contents:
# T/ i( u+ w* K0 k9 B+ ?1 h        movie_info=movie.split("|")
; v7 x% k8 z! {9 R; a        movies_info[int(movie_info[0])]=movie_info[1:]
9 H- j6 |, _4 f& e. X1 C    return movies_info
" Q! C$ Z4 w$ z! \1 c   
& X; q5 y3 f& y4 z  K$ p   
1 A& L+ X8 z% ]2 Y+ [! f! G4 b    , q( S8 J1 O8 l% R/ ^3 D
#主程序
. ]2 C4 g- o0 V$ _$ c6 a#输入 : 测试数据集合" G% ?3 O, z! z1 c- [. s" _
if __name__ == '__main__':+ z2 ^1 f/ ^7 C7 z0 M: |( o
    reload(sys)$ n$ w3 n8 K7 ?6 `3 w- E5 B4 C; ]. [
    sys.setdefaultencoding('utf-8')
2 ]; S' ?; P# o) y& ?    movies=getMoviesList("/Users/wuyinghao/Downloads/ml-100k/u.item")* n" @) C2 S. }! ~
    recommend_list,user_movie,items_movie,neighbors=recommendByUserFC("/Users/wuyinghao/Downloads/ml-100k/u.data",179,80)
2 T/ `% B6 k: c    neighbors_id=[ i[1] for i in neighbors]
% X- I/ L% r* b. Y    table = Texttable()- C5 @& z) z4 E( u7 a0 O: m0 ^$ `
    table.set_deco(Texttable.HEADER); o2 x0 ]: r' i2 S
    table.set_cols_dtype(['t',  # text $ [4 |( }: k: O( T9 Y2 \: d
                          't',  # float (decimal)8 N/ J( ~& o; u# R" F1 x
                          't']) # automatic" O/ [. G1 s+ q* U0 h9 T
    table.set_cols_align(["l", "l", "l"])
# K" U! u6 m8 T* b0 A; m    rows=[]
2 Z& n9 @& h: ]4 Z" f5 t    rows.append([u"movie name",u"release", u"from userid"])
3 ]) v  Y- Z4 O, O2 F) I/ ^    for movie_id in recommend_list[:20]:
" w( ~: B7 F, z, s0 f        from_user=[]
1 G2 \2 d$ p& b+ [1 k% _& f        for user_id in items_movie[movie_id]:
! t( v; |' a" M, S4 R/ |            if user_id in neighbors_id:
5 W4 v1 J5 n; ]1 l                from_user.append(user_id)
7 K4 W" W! X  d: ]        rows.append([movies[movie_id][0],movies[movie_id][1],""])
2 p$ B2 F) Z5 G# m9 F3 S! f$ m* Y3 C    table.add_rows(rows)
( N, P" s8 C1 f/ E4 k' h    print table.draw()
作者: mea_lsc    时间: 2015-4-19 00:25
百年孤独 发表于 2014-7-19 09:22 . A* k) d0 {, Z; N3 Y! U7 [2 F
# -*- coding=utf-8 -*-# L$ f: U) ^. d4 s# l) X2 O
) U5 U' N7 @  X/ A  _/ l- T! K% U+ ~
import math
5 a- M8 u, M: o. B  X
这是什么语言的程序?
2 h0 F1 r5 S' V1 h" R4 m
作者: 1943973818    时间: 2018-9-1 22:11
我来水帖攒体力了,哈哈哈哈哈哈哈哈哈哈哈哈
0 K+ `6 h/ H" H. D: D. q




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5