数学建模社区-数学中国

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

作者: harveymao    时间: 2014-7-18 23:21
标题: 求协同过滤算法程序
本人在学校参加暑假培训,需要这个算法做题!求大神赐教,感激不尽$ c& t5 K0 L9 g7 e, H0 o/ n

作者: 百年孤独    时间: 2014-7-19 09:22
# -*- coding=utf-8 -*-
. h8 R8 [! B7 O* T' Y
0 G* N2 W4 u/ Z7 ]import math
. B/ w% T$ ?2 Simport sys
8 i1 }7 q% v- j7 J2 M5 z9 kfrom texttable import Texttable7 }% Q) ?) b6 t5 L' P; x
7 b2 c0 d1 d: X) I6 V

' m- ^5 m/ v( c+ l7 p#9 ~7 ~  S$ K! J7 v8 Z
#   使用 |A&B|/sqrt(|A || B |)计算余弦距离  k- B' z- E! ^
#
' o& m3 D1 r8 p# ~* t: y$ Q, G7 f#2 S+ D  c2 M2 P4 q# @( q5 L8 m
#
3 y' X. X' g; ydef calcCosDistSpe(user1,user2):
# B* {( u! w. D; m& M2 h, W; d    avg_x=0.0$ r8 q- X- D+ `" u  z. ]
    avg_y=0.0" D* X7 X, F1 `$ ^
    for key in user1:  h5 h  N; R2 A4 Z- L+ a
        avg_x+=key[1]
8 d2 K4 I, O2 [# E% q$ v    avg_x=avg_x/len(user1)" f4 ]& B. a3 Y. M1 b0 V1 J
   
& @0 I* T' O3 r6 @    for key in user2:% |: o8 _, Q, V( p: @
        avg_y+=key[1]
- |' Z; O% d2 h% Q    avg_y=avg_y/len(user2)
* F* z, Y9 B/ u$ }2 n9 t   
6 i1 w7 o. _: e2 `, e    u1_u2=0.01 Q0 r  x+ o6 t! O6 F
    for key1 in user1:
! ~' R2 i: j/ M+ u+ v        for key2 in user2:
! J% z% i. {  m: K% b5 F4 \            if key1[1] > avg_x and key2[1]>avg_y and key1[0]==key2[0]:
/ O( G9 B2 m; f3 X# Q2 ~                u1_u2+=1
, d% c6 ~% `* J5 u) H: A    u1u2=len(user1)*len(user2)*1.0
2 l1 g! }8 F0 @    sx_sy=u1_u2/math.sqrt(u1u2)8 r+ X" ~% {$ ~% H& _6 B- w# Q
    return sx_sy  C0 _& R0 I. T. ^$ N: @, Q9 N

5 U) o8 O1 m$ U, B1 a
, ]1 Y% p. n( J8 Y( `/ `6 m: N5 i#( N# f2 J) a, E. I" q
#   计算余弦距离1 x% D9 m1 F; \1 J& B
#! B& I* E, j- `$ o3 K/ L
#
4 Y4 X# U1 E; ~" Z5 pdef calcCosDist(user1,user2):  h" D. z: N/ @9 a; N3 B
    sum_x=0.0
- O) w8 l  [& X0 T& g    sum_y=0.0
; h7 e) p& n0 O0 B5 u+ q1 n# I    sum_xy=0.0. r( c9 B$ ^  s
    for key1 in user1:9 j0 E' ^. e3 m  N# g6 B9 R3 }
        for key2 in user2:
( I  I. l) K; N, P, ~3 Z) u            if key1[0]==key2[0] :
* d9 B5 m! h; d8 }# u& {3 [5 I                sum_xy+=key1[1]*key2[1]2 H. H; _5 i. r. c4 L8 Q
                sum_y+=key2[1]*key2[1]
# u6 i2 x1 ]1 ~: g6 |( _- G" `/ g                sum_x+=key1[1]*key1[1]" l2 E3 s  K" w! ]/ r1 Q1 _
   
. R: v/ U- `  W9 Z3 |" X2 l    if sum_xy == 0.0 :9 U1 `! R0 U' P$ Y( r) d
        return 0
) q' t8 i3 l" L: t* k* a    sx_sy=math.sqrt(sum_x*sum_y)
1 V; Q1 F5 i0 k    return sum_xy/sx_sy) S4 ^" r8 F8 s% ~3 w& ]' h# D

% j) ?9 Z8 H# e' n3 b
; l  z0 V! F8 P' a#
1 L+ N) n+ a. d% w2 x, F) K#
# N5 p0 T; [9 k9 p#   相似余弦距离
7 h0 ?3 {( M8 J' g9 O0 e## U: R$ s+ W, F
#1 `" W9 B: e2 O! R- E, H
#
3 g/ m+ v0 s/ \. U/ Kdef calcSimlaryCosDist(user1,user2):. j% r7 @  o6 s& [
    sum_x=0.0
5 r( o- u. i6 {6 X; `9 W6 Z0 L3 V    sum_y=0.0
( q: W5 r9 K" a5 s9 c    sum_xy=0.0
) u3 G8 N% r) l. N* f8 `    avg_x=0.0  [# i. \: j, @! p6 e& Q; D2 ~8 z6 m
    avg_y=0.0
) W( z+ b! P" r- T% A    for key in user1:
2 e; \' v6 ^3 H6 s        avg_x+=key[1]/ _9 u: x9 e) s
    avg_x=avg_x/len(user1)6 a& @1 Y; H4 R0 @' ~+ N2 Y
   
  t: @+ [# \2 x' E7 k9 V    for key in user2:
( F0 B1 W: ]9 ~' z        avg_y+=key[1]
! R2 ~. c; T+ w8 a    avg_y=avg_y/len(user2)9 U- A' s% Z: R- {
    2 @2 m$ a: \$ t) b( k, V
    for key1 in user1:
! j- }* U. r+ k$ f; b        for key2 in user2:& l7 m+ U5 V6 \6 ]$ W& b- T" K
            if key1[0]==key2[0] :
( z8 A* y$ Z! o$ ~* W! [                sum_xy+=(key1[1]-avg_x)*(key2[1]-avg_y)
1 j/ C: k# z4 ?8 P                sum_y+=(key2[1]-avg_y)*(key2[1]-avg_y)0 W3 W2 k5 I' _+ r
        sum_x+=(key1[1]-avg_x)*(key1[1]-avg_x)# m2 R: @! I/ @( Q1 l
   
8 o$ P: O0 e! e0 N    if sum_xy == 0.0 :2 S- q. F% @" [1 k- ?, b2 R5 E
        return 06 L+ q3 k5 w9 O" {) L5 C7 l
    sx_sy=math.sqrt(sum_x*sum_y)
, K/ w1 J( {( }/ }$ O4 X    return sum_xy/sx_sy
# {/ H. v4 m6 P: t   
7 h# E) o4 O. A3 ]: h! D: }2 |- [1 A, X( q
#
0 v7 T% G' A+ l( k" ^#   读取文件- `6 G# i# }1 V
#- M% c( T9 E" Z# y+ g- q( I$ o9 |
#
/ p6 s1 V, a) W! F/ gdef readFile(file_name):6 K1 i" _2 f6 s! M* ^) n
    contents_lines=[]
6 P7 }6 h8 `) c& A+ Z" b    f=open(file_name,"r")' N: \3 k  O3 s; s" k0 }! a  a
    contents_lines=f.readlines()" v7 s: C2 v  @- {
    f.close(); n( m5 Z1 [4 k6 w3 r
    return contents_lines& P9 r6 H( _) x1 z* J, v# N2 x
/ }8 H$ S& q0 B: F# ~
/ W0 K& F( T: b5 I$ r( ~$ h# y

2 L# h- D/ k0 {+ L2 @#
6 J. l9 g6 D: r2 \2 w#   解压rating信息,格式:用户id\t硬盘id\t用户rating\t时间+ X# C& K# r4 l' J- L  g% R; t
#   输入:数据集合. g/ E0 m6 P  N4 l
#   输出:已经解压的排名信息
9 j$ n7 `0 R& c0 A! ]#
  N+ A3 l; m7 _2 u4 jdef getRatingInformation(ratings):9 K' B, Q0 R% m; f1 @1 V
    rates=[]
9 F4 ]! c3 Q$ o! O    for line in ratings:
; D  N# c  C+ w! K) v        rate=line.split("\t")( f1 H/ Q5 H0 C' x
        rates.append([int(rate[0]),int(rate[1]),int(rate[2])])
* Y5 _3 _- m0 T1 ~$ L& ~    return rates
7 s) [6 `- U3 E' Y
. S  i- v  C& u6 M
5 |% h. m- ~9 [$ T#
$ _7 u- q0 b; L7 x) X3 Z1 j1 }#   生成用户评分的数据结构- v, s- I7 a) m" ?/ v
#   , u: ]$ v; {. a! u7 T& d
#   输入:所以数据 [[2,1,5],[2,4,2]...]7 [5 @( @" p+ m
#   输出:1.用户打分字典 2.电影字典) {2 X5 c5 g, F2 ], g1 c3 t! r9 V
#   使用字典,key是用户id,value是用户对电影的评价,) ?! X; z0 x  A$ F4 }, @+ i
#   rate_dic[2]=[(1,5),(4,2)].... 表示用户2对电影1的评分是5,对电影4的评分是2, C3 m) p6 f' V% j" `& y; a
#
3 O* m* J( Q/ L- D" rdef createUserRankDic(rates):8 B; [* q0 A  V4 U% ^
    user_rate_dic={}4 V1 i1 p3 E4 W6 `8 y1 V
    item_to_user={}# e( K6 A9 ]2 s( c& M  f0 w& U8 I
    for i in rates:8 R8 H9 C. ~4 U3 B* F% A
        user_rank=(i[1],i[2])7 P9 E, x8 M1 a% D1 \  [( m/ l
        if i[0] in user_rate_dic:8 i; u" u' ~9 [' w# W2 I" ~
            user_rate_dic[i[0]].append(user_rank). V6 N0 E4 }0 p- x9 E  E: Q4 E2 U
        else:6 G" F6 V. b6 h2 l9 e+ Y
            user_rate_dic[i[0]]=[user_rank]8 g: d# s5 s9 V# e2 h
            
: b" F- c, ]' V( X! w        if i[1] in item_to_user:4 Z+ G- w; g0 U! L# ]  @
            item_to_user[i[1]].append(i[0]). r( H: F6 s) Q" e
        else:5 f+ H0 R  [. n4 x
            item_to_user[i[1]]=[i[0]]6 c/ c9 g2 G& \' G
            
+ F1 v. B. @( t0 l# j4 P    return user_rate_dic,item_to_user! q( g& k) B( r" y. Y
# \4 t# p( i  I

  M! V; J  }  h0 }. v3 u#/ ~% G0 r( q3 E3 ?1 [- |+ P
#   计算与指定用户最相近的邻居
9 ]  [+ k& V, |# u- W) _#   输入:指定用户ID,所以用户数据,所以物品数据5 h+ E$ ~& h* }' K2 _* S9 c
#   输出:与指定用户最相邻的邻居列表& f, |, @5 l- e' X+ w
#
8 y9 q; t- f: ~9 |8 W) e  [def calcNearestNeighbor(userid,users_dic,item_dic):
3 R% ^  x; }( }9 ?7 _    neighbors=[]
5 u5 a) T0 h4 d, s3 K% m    #neighbors.append(userid)& i. k1 N- m& E) {8 Z# u3 B+ s
    for item in users_dic[userid]:3 \# e/ v9 W8 n. w
        for neighbor in item_dic[item[0]]:
& N! _" }. a& _  ~. c" c- b            if neighbor != userid and neighbor not in neighbors: * T# |. w" p& l
                neighbors.append(neighbor)& u5 d% {2 V$ @/ k( D
      
5 t; U6 c& n# W6 w8 _& F    neighbors_dist=[]: C1 W6 y! O. A* o& N; L! ^! V
    for neighbor in neighbors:
0 F# Y, y( ^  u6 |/ t) i6 v  N        dist=calcSimlaryCosDist(users_dic[userid],users_dic[neighbor])  #calcSimlaryCosDist  calcCosDist calcCosDistSpe
& P. Z* E% W- q3 `0 ~  t5 p! Z        neighbors_dist.append([dist,neighbor]): u, I  {5 s, s. z
    neighbors_dist.sort(reverse=True)
" |) D: B8 V9 ~$ A0 v( A  g% i# Y    #print neighbors_dist% g" `) q) y+ ^3 `! H% M
    return  neighbors_dist
: G, L6 p: Q# V$ E  b2 v& V; E% G8 H$ L5 R- D& S  Z9 Q! i$ t% P2 a$ B9 v

% K$ j9 |4 k5 c: z1 X/ x#
; T/ H$ Z5 z0 z6 ]#   使用UserFC进行推荐8 s; |& L* v. h" Z4 z# a
#   输入:文件名,用户ID,邻居数量8 A* k( S6 M2 ^# v6 o- V
#   输出:推荐的电影ID,输入用户的电影列表,电影对应用户的反序表,邻居列表
  N/ ^1 U: A9 `, F* U#& K# Q# ^" B  ], V% x& d
def recommendByUserFC(file_name,userid,k=5):) a4 r* f$ G9 w+ g5 C
    + Q% j0 G6 o* a: _: r" o% D
    #读取文件数据3 B5 n! P7 M4 v, N+ g1 b2 O
    test_contents=readFile(file_name)9 g% W- ?3 p2 h1 E' F8 K
    ; ~0 m5 G2 C1 f. O; X! h- U
    #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...] 2 \0 B: g3 d: F
    test_rates=getRatingInformation(test_contents)
: b+ J4 d  d: s0 I   
+ ?* z" n' x: ?    #格式化成字典数据 " {7 I4 b: O) P$ d9 ?  B
    #    1.用户字典:dic[用户id]=[(电影id,电影评分)...]  ~. i4 C5 \3 t, y3 k
    #    2.电影字典:dic[电影id]=[用户id1,用户id2...]
: D5 Y: x* Z* O" V" Y    test_dic,test_item_to_user=createUserRankDic(test_rates)# H( D/ U% W9 U4 N9 A8 M/ \+ N5 s
    . E' L7 E) Z1 y1 i$ Q' ]1 W+ H
    #寻找邻居
- \3 m2 Q" u" F    neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]- ^% G- h! W9 |2 \7 T9 U
        ( I; h4 u) K! D9 A1 k5 E
    recommend_dic={}
( B3 i) E2 U1 e9 y1 n    for neighbor in neighbors:- ?: u- b8 B% _1 ^6 y
        neighbor_user_id=neighbor[1]
1 H8 v! v+ l" L% K# r        movies=test_dic[neighbor_user_id]
+ t: j9 m; d7 v/ ~& a# l        for movie in movies:
, d; e; V& a0 w            #print movie  h6 [4 q- j: l$ K9 a6 J0 @
            if movie[0] not in recommend_dic:2 \1 b* Y6 e1 c* U; B; A
                recommend_dic[movie[0]]=neighbor[0]
* Y6 `+ S$ S+ Z7 C- g            else:
  p$ g" Q) q( _* J                recommend_dic[movie[0]]+=neighbor[0]
  ~/ X( ~; g6 U6 F. \) B9 u, J    #print len(recommend_dic)$ _' [6 c1 x4 q8 }9 N- g
      }8 t0 M  I: [& X' p  t8 ~
    #建立推荐列表
7 m& K) q/ p8 ^; C6 j' }    recommend_list=[]
- a" }( ^9 O+ j+ R    for key in recommend_dic:2 c% u' m- X/ p8 f
        #print key
" L8 ]: O- t0 n- U! Y1 b        recommend_list.append([recommend_dic[key],key])
4 g+ ?, x" z) j" a. w& E    7 d" Y' J* B" Q+ m
    6 k7 l3 k8 H0 B5 C: _
    recommend_list.sort(reverse=True)
+ U4 p! K! Z) ]# l    #print recommend_list
/ U  h8 K$ e% F    user_movies = [ i[0] for i in test_dic[userid]]8 H0 J  Q  G+ U: U) G$ W3 a2 l

" t) @2 z# q9 {+ s6 }    return [i[1] for i in recommend_list],user_movies,test_item_to_user,neighbors
" C( A4 O1 [) @8 \3 `  b4 e   
2 O) ?! e8 n* g    9 Y+ {, `0 o+ H6 A" M& a

  K. O+ c( u% l, Z#, B# ~( W4 K) n
#) |+ k" [" R' h
#   获取电影的列表! ^+ k: v- N2 C+ R; D3 d6 \8 a
#& z1 j9 `0 i0 s" Q
#; Q+ X& r% Q9 o
#
$ _& Z, g8 F3 q$ _+ d6 C! udef getMoviesList(file_name):: `" M. e, w$ G/ p# a* @/ k! i
    #print sys.getdefaultencoding()
4 x. G5 A. ?0 b( I" u# f8 g    movies_contents=readFile(file_name)
$ K8 a2 E2 a- F" H( k  F8 j% {    movies_info={}
; R: L3 G* M/ U8 j    for movie in movies_contents:  W. c2 ~) n& t% V2 Q
        movie_info=movie.split("|")6 C9 P, r0 ^+ j" j5 z% Z$ ?% U
        movies_info[int(movie_info[0])]=movie_info[1:]
, R$ t: b$ H: N( [6 J" G6 c0 S& ~    return movies_info
/ f* _. r4 H/ Y+ |% L- G' s- l   
% F: v. K2 a8 S  {) Y* L1 W+ t    & h5 |  z, P) w  O% u* R' W4 ?! W
      G3 X9 ~/ N% a
#主程序) k  o5 ?+ u% h, N% G0 F1 V  C
#输入 : 测试数据集合
6 l* K8 B# d) F% aif __name__ == '__main__':) [! Q7 T6 @$ F- _6 j+ N6 p; M1 m
    reload(sys)
, M* J9 h5 {% \# h  s    sys.setdefaultencoding('utf-8')( {3 O5 m$ s8 K0 n& I
    movies=getMoviesList("/Users/wuyinghao/Downloads/ml-100k/u.item")
7 t; B; H9 [/ Z; ]" w% K& @/ x  f    recommend_list,user_movie,items_movie,neighbors=recommendByUserFC("/Users/wuyinghao/Downloads/ml-100k/u.data",179,80)
/ z! @' y) ]5 N4 S5 S+ y    neighbors_id=[ i[1] for i in neighbors]& C2 X; j5 F6 b3 J. [5 c$ v
    table = Texttable()
0 a2 t: o) R# n. j2 I4 _    table.set_deco(Texttable.HEADER)
7 r0 u. Z& [8 \9 Y    table.set_cols_dtype(['t',  # text : W5 m( {/ G/ D
                          't',  # float (decimal)
, r1 r! m" j$ q8 Q; {                          't']) # automatic% c0 h$ Z+ ]* C" I# G
    table.set_cols_align(["l", "l", "l"])( W6 p6 w( R6 J( j( z
    rows=[]: r$ z* K# G" K0 n
    rows.append([u"movie name",u"release", u"from userid"])3 |: h! w! q! f, [+ E  i# k, e
    for movie_id in recommend_list[:20]:
1 }+ D- N& w' g3 y- e        from_user=[]( o, \. T5 t. _- N/ U
        for user_id in items_movie[movie_id]:
3 {8 G- l- [& K3 }9 u            if user_id in neighbors_id:. ?: o& M6 S* r" X) V3 o. J4 E
                from_user.append(user_id)) m& s5 G, _/ x' L% K1 s
        rows.append([movies[movie_id][0],movies[movie_id][1],""])/ b, B1 @1 ~7 S& y
    table.add_rows(rows)
! Q% y1 m+ s/ k2 G3 a0 J    print table.draw()
作者: mea_lsc    时间: 2015-4-19 00:25
百年孤独 发表于 2014-7-19 09:22 + w( d  V8 M+ ?1 J# f
# -*- coding=utf-8 -*-
& S4 a: \2 O/ F& A; Y, C
" I9 u' X+ K/ Q0 \import math
/ N/ [5 ?0 ?! r
这是什么语言的程序?
$ q) v8 }' S: J6 h7 R9 F, ^) j
作者: 1943973818    时间: 2018-9-1 22:11
我来水帖攒体力了,哈哈哈哈哈哈哈哈哈哈哈哈
4 b1 o: r! C  L* p' ], }- L! h3 L




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