数学建模社区-数学中国

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

作者: harveymao    时间: 2014-7-18 23:21
标题: 求协同过滤算法程序
本人在学校参加暑假培训,需要这个算法做题!求大神赐教,感激不尽2 l+ W3 n0 H7 M! _6 Z9 F1 W6 P

作者: 百年孤独    时间: 2014-7-19 09:22
# -*- coding=utf-8 -*-
# X. g8 y. f3 |+ R; m
. z2 c4 H4 W2 Q' t1 M! A' iimport math
/ n; I, y0 ^) ]: }& Iimport sys1 ?. N7 ^. x# V' Z1 U5 h+ E, T
from texttable import Texttable; r0 G$ k! z& [7 N3 @$ x
# W! T. j" \1 h8 l8 _- l6 r% U7 o9 L! g
# O9 R6 H5 f. \; k+ f- x
#
. i& D4 Q( L4 R; W#   使用 |A&B|/sqrt(|A || B |)计算余弦距离# |2 k; z1 h5 V
#  T8 \9 c% `9 ]2 W
#! ^) w* S" d# {
#
( j  c! e( L: P- q0 jdef calcCosDistSpe(user1,user2):
- ~: Q0 J8 P3 S0 o- U0 _0 b( \    avg_x=0.00 l( t- @+ I9 i9 G
    avg_y=0.08 e- H. M3 R  E( e: b' ]/ T) V
    for key in user1:
" B2 B7 `% r7 r% f9 L6 L        avg_x+=key[1]
+ M6 I& |/ V: D* m    avg_x=avg_x/len(user1)
! ~! q% V; s( ?7 B0 x    9 c3 }( \, @: \  r- L- X
    for key in user2:3 a  K3 v( L3 l1 P% s6 ^
        avg_y+=key[1]9 }0 d4 P( r6 |- K# M/ G# D7 F6 N
    avg_y=avg_y/len(user2)
& Z5 _+ ]: F  a" O6 ?* L( M   
$ r8 j9 `3 B' k! x9 _    u1_u2=0.0  f: |  Y& I" c
    for key1 in user1:
% i  O9 x4 A3 R6 E6 h" r: M        for key2 in user2:
: m. A' [1 T# z2 v3 g/ k            if key1[1] > avg_x and key2[1]>avg_y and key1[0]==key2[0]:
/ v6 g% Z) E) Y& f8 z- u5 ], L                u1_u2+=1
! i& h$ |& K2 v8 l/ L. @& s7 s5 N    u1u2=len(user1)*len(user2)*1.0
1 X3 p$ l% _" I$ O    sx_sy=u1_u2/math.sqrt(u1u2): C0 _3 L, Q5 ?; o) m. k
    return sx_sy
2 o5 M' R2 e3 z% O" h5 T( ?% F% b7 l1 M  y" G9 r- Q

5 w/ q  q' ~6 N% B" ?7 C#
, `$ q, }0 Y# f4 q% e#   计算余弦距离8 ^! U! E* x5 G) z6 z: o
#
7 ~" Z9 ~4 }7 X5 x' ?- `$ s( E) a#
1 ~" P, N! H/ S/ Rdef calcCosDist(user1,user2):$ d9 W, U+ z1 K4 m% U+ {2 s
    sum_x=0.0
' P! T: q# h& r    sum_y=0.0) ~+ U% j) G; d; V8 c- L9 T
    sum_xy=0.0
, A" x# W' x  V, D3 Q# B    for key1 in user1:
( N3 b% t/ i5 O; B4 c        for key2 in user2:) l2 L* H5 X' K6 c. A
            if key1[0]==key2[0] :
+ E+ I; G# U. \                sum_xy+=key1[1]*key2[1]3 ~3 c" R1 S9 _7 P$ X  i! M' s! e8 U
                sum_y+=key2[1]*key2[1]
- ~: T. D8 n; P6 t* D5 o; t& M" z# H                sum_x+=key1[1]*key1[1]
) H3 ^8 ?: r+ X    & u: J" Q+ F1 N3 e
    if sum_xy == 0.0 :
( N5 ]& a+ h" D+ J! e        return 06 s6 s, F/ T( \9 I! ?4 p1 y' d5 J8 d
    sx_sy=math.sqrt(sum_x*sum_y) # L$ X/ h2 J4 p
    return sum_xy/sx_sy4 Z- c: z; l, I+ O
/ z9 Q- j0 _4 N% \2 x* N
- p5 v9 n4 M) \0 u- y
#
& J: B: S9 h+ E! M( L1 K#
1 t( X& i5 N8 x8 q0 o! z#   相似余弦距离
" C4 c& O) X. H2 S( s- a#
0 D/ r. \6 S& c! L# [+ u#9 \4 I( i1 o. r$ z% i
#
: P& E3 w- w2 ?; Ndef calcSimlaryCosDist(user1,user2):
) o1 ~9 [, Q9 F3 C. H/ k) i    sum_x=0.04 r  S; v- |9 d
    sum_y=0.04 t+ J& e% r; C) N" q
    sum_xy=0.0/ Q! I! ]8 h( Y1 }0 k) p+ x
    avg_x=0.07 p  Y/ t+ D3 r# t& O! h
    avg_y=0.0/ V$ i7 B! `( N4 V/ p
    for key in user1:. u, v, @. j0 d8 Z
        avg_x+=key[1]9 L3 `: @1 @8 @: X% _
    avg_x=avg_x/len(user1)' j5 |5 c! U3 I
   
, K+ V4 }0 S1 ?6 t/ l/ R3 {! p  T    for key in user2:
4 \1 a- D" [) F) B. I7 `  s        avg_y+=key[1]8 V) t- M+ n; F4 k2 {$ b
    avg_y=avg_y/len(user2)' {+ D, H/ K0 o
   
3 S! z' ~6 F: M$ @    for key1 in user1:
$ s+ l6 R1 }0 y( q0 x! D        for key2 in user2:
7 @* ^" P0 ?3 o& Y9 L            if key1[0]==key2[0] :
, I# ^8 u3 u- ^$ s! ?                sum_xy+=(key1[1]-avg_x)*(key2[1]-avg_y)- I1 a  {1 {/ k: O8 N/ K9 X" N
                sum_y+=(key2[1]-avg_y)*(key2[1]-avg_y)( x" Y. f4 f4 z- I8 }! G2 u; _) B
        sum_x+=(key1[1]-avg_x)*(key1[1]-avg_x)
" S3 m, h  M' s0 t* [5 l9 z* V0 ]    5 d( G- D# Z7 Z" E9 q1 L
    if sum_xy == 0.0 :
. U0 s2 c$ Q: j! O* |3 q4 s" F" L        return 0
! i) c" G2 B/ K* X- x! c' Y    sx_sy=math.sqrt(sum_x*sum_y)
  a- S( c: l- Z3 j/ L' Q    return sum_xy/sx_sy+ Q! Q( y1 }3 `  z2 @
      K8 h/ L1 Q6 K7 m$ T! h, y

8 H/ b3 w0 s. M3 v% P" h7 n#
$ A5 s/ b: j3 l#   读取文件/ _) ?4 Y  X' A- S" ]+ ?
#
0 r. q4 w4 R/ {. N#! }( b3 ~+ D/ s  X% A; [. T3 s
def readFile(file_name):
% ^$ c) B: ~: i( t    contents_lines=[]2 k8 k' C6 ^2 s6 k
    f=open(file_name,"r")7 n; @% P# Z2 ]  d. l  D- u2 \! `, C
    contents_lines=f.readlines()
2 n$ h* ~+ S7 p/ J" \    f.close()
/ F' e, U3 d  ~  k0 E% ]- v    return contents_lines0 W  `9 w$ M6 B$ x' A0 G* f8 i
$ v/ X% v4 n0 F/ B
. I* ?( s4 x7 {  u
& C* M- U6 k9 g+ `* x% B
#
7 O0 H7 P! z; C( U#   解压rating信息,格式:用户id\t硬盘id\t用户rating\t时间
8 Q* M, r' p% ^  O' M' ^- J#   输入:数据集合& R7 H8 g( O7 W3 A9 y5 u  u& L' G
#   输出:已经解压的排名信息
# L; b5 _. [7 t: G# H#6 V+ v  ^5 D2 T" h% W0 j; [$ U8 h
def getRatingInformation(ratings):" T/ g% O2 C" g7 n' t3 \
    rates=[]- ?# d, J6 W. x2 `! J7 |
    for line in ratings:
/ \: b2 Z) A/ z8 X+ ]5 R        rate=line.split("\t")8 A" _) o+ }3 L
        rates.append([int(rate[0]),int(rate[1]),int(rate[2])])! W8 s' ^% X) ?6 d+ K* u& i
    return rates6 @1 ?- A- B) w5 c% V0 ?9 F0 @# E5 g
+ o& r3 I6 a) Y% v7 ]% O( Y
0 o3 C+ X3 k' H/ N* W6 E
#
4 Z3 W7 M" @. n#   生成用户评分的数据结构
0 z, Y* H0 d0 c7 B7 h#   : f3 J) {# Z0 }6 p# o% ^
#   输入:所以数据 [[2,1,5],[2,4,2]...]2 |6 k( [* R( P( J* v0 d$ i& Z
#   输出:1.用户打分字典 2.电影字典
' ~; U3 U8 i3 Q; }, C' R/ s#   使用字典,key是用户id,value是用户对电影的评价,  s0 B, Q9 U& }1 |+ Y6 U) P; J1 d4 M, O
#   rate_dic[2]=[(1,5),(4,2)].... 表示用户2对电影1的评分是5,对电影4的评分是2' H" \- @" L; g  L
#
" O( g9 ~  v- adef createUserRankDic(rates):% L1 v' [6 P) l, i* Y2 _
    user_rate_dic={}. U$ x' e  F+ _. D. |5 I  c
    item_to_user={}6 c% ]  t; R3 R5 S
    for i in rates:
1 h0 e( m+ x$ L0 ^. t, S        user_rank=(i[1],i[2])
1 C4 c3 k6 V6 i        if i[0] in user_rate_dic:4 d" ~& ~& n4 e4 D: O
            user_rate_dic[i[0]].append(user_rank)
! z% o1 n+ F* `$ U        else:! V9 b) K9 n1 J3 o5 P/ S& @8 o( h& W
            user_rate_dic[i[0]]=[user_rank]8 A7 c2 L% w. t0 l7 Q) h) Y- e
            * D+ f& K2 M: _9 Z7 E
        if i[1] in item_to_user:
) @* V* @, u7 E+ _7 t            item_to_user[i[1]].append(i[0])
, ?8 G; J4 t. ~0 O  t( [        else:9 t( R: N+ i$ Q- r  [
            item_to_user[i[1]]=[i[0]]
" x* u# N/ U0 L( \8 X/ k' Z            
7 }. n0 M; Z" A: P! b4 F    return user_rate_dic,item_to_user( z1 g$ {1 \' W% A* w

- l1 S; n( |) t# R. b; Y" j+ j7 Y/ q. y
#/ }9 Z8 |2 V% {$ x
#   计算与指定用户最相近的邻居
; U0 b1 f) s% a: Z8 o#   输入:指定用户ID,所以用户数据,所以物品数据# e. ]0 s) n9 S8 r9 y: D7 K* C
#   输出:与指定用户最相邻的邻居列表
' e4 z8 K  ]. g. W4 z+ d1 S6 {#6 q# r5 u8 g% Y/ Z  E
def calcNearestNeighbor(userid,users_dic,item_dic):
3 ]! i: M7 l( ?8 ^  w+ o: K    neighbors=[]
7 l1 s" t  F+ @8 n5 l3 g% k2 q    #neighbors.append(userid)
( d( z# x2 [2 x9 ~' i# _0 {' @    for item in users_dic[userid]:
( |* }; n: z1 z; @8 E1 {        for neighbor in item_dic[item[0]]:- B6 e" o4 _' l0 T, C  t
            if neighbor != userid and neighbor not in neighbors: + E( r3 L) m8 n2 o) {8 |
                neighbors.append(neighbor)
, K/ x: ]- B( C" i( B      
( B6 F) g$ y( P% G    neighbors_dist=[]
0 U" W7 H; \6 t  K9 g    for neighbor in neighbors:
  L# {& G7 Y. E2 O" w8 H8 B        dist=calcSimlaryCosDist(users_dic[userid],users_dic[neighbor])  #calcSimlaryCosDist  calcCosDist calcCosDistSpe  C4 k% o8 O8 u" b* G+ f& l
        neighbors_dist.append([dist,neighbor])
1 X. y$ x2 i+ h! ]    neighbors_dist.sort(reverse=True)
- [( \( X0 D4 d" l, z) P. b. a' d    #print neighbors_dist1 n6 M; x) f" e1 _9 L# [" T* P
    return  neighbors_dist! `9 `7 }7 k1 m9 C

- F& ]) O8 V" B3 A& u& D+ d! T6 T! W1 u- B
#
' g9 K: U: T8 j0 i2 k+ N) P& T#   使用UserFC进行推荐0 n( ~* F2 p* B
#   输入:文件名,用户ID,邻居数量6 K# X7 ^9 t; X; U- K
#   输出:推荐的电影ID,输入用户的电影列表,电影对应用户的反序表,邻居列表. ^. O* e% n* w
#
7 U. w& U8 T/ z/ Zdef recommendByUserFC(file_name,userid,k=5):$ p  I* S1 {! f3 c
   
2 [7 j* V1 I6 p! K" P! l    #读取文件数据4 G6 c% E- ~, G$ z1 g
    test_contents=readFile(file_name)
+ X; x$ w  g- p2 @1 p! u0 x   
! o# V- i5 I* J1 K& j# x% H    #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...]
: Q# S" {  s9 O. c8 s1 x: W    test_rates=getRatingInformation(test_contents)1 |1 q0 D3 ]/ W  j% O7 }. Y) t
   
# G( k! e5 D* J1 I) J$ `. S/ r5 d    #格式化成字典数据 * X( s! I. [  v/ ^. h6 {4 H) z
    #    1.用户字典:dic[用户id]=[(电影id,电影评分)...]# D) Z; [1 p$ n2 `& L: x  N
    #    2.电影字典:dic[电影id]=[用户id1,用户id2...]
9 d! Z: ?4 I8 V" I0 G# z    test_dic,test_item_to_user=createUserRankDic(test_rates)0 L2 V0 S& W, C7 b
    ; n# C6 X7 r" ?7 ]9 ?1 k' {
    #寻找邻居
* R7 H" e9 A; M; b; I# ?% Q: O. \    neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]8 O  x# ]8 z7 |/ N4 L+ }
        . A+ F, w3 F7 L- s7 y( R3 R+ E+ ~, q
    recommend_dic={}
  C2 h4 N* s, c; {, _) n    for neighbor in neighbors:; Q( M! i- P+ z1 k5 e* r9 q% w
        neighbor_user_id=neighbor[1]1 x% }6 P& N* t! f* W
        movies=test_dic[neighbor_user_id]0 g- `7 X4 N3 W) d& A
        for movie in movies:* H+ i& v7 d2 p, V8 ^
            #print movie
8 ~# z& Q* N9 s, Z& q' N; n8 g            if movie[0] not in recommend_dic:, X9 }/ ]2 `1 D! O6 J
                recommend_dic[movie[0]]=neighbor[0]
6 x/ d  d# n) p, ?! o+ Y            else:
2 T( |/ Q6 m5 c5 e                recommend_dic[movie[0]]+=neighbor[0]
; K6 z3 a0 j' Z; Z! B  X    #print len(recommend_dic)
$ W7 t! v  {: q* g   
; u, b9 K2 s1 `! p    #建立推荐列表" U: P6 Y! ^$ Y3 ?. H
    recommend_list=[]
% M0 ^) u2 z5 l; ]8 Q1 w4 B/ ?5 p7 \0 f    for key in recommend_dic:
6 p- D& z1 K# q        #print key+ z0 j7 p  G  w8 Y; a, `% V% _7 z0 m
        recommend_list.append([recommend_dic[key],key])
$ T) C; W- t) W! r2 B% G4 c7 @    + ]/ \$ I! c: m4 p/ B1 w4 Q
    , y; y& Q" X; S  n" p2 K1 u
    recommend_list.sort(reverse=True)0 i0 K8 ?0 V0 u; x* A& m
    #print recommend_list; O% X) J3 u+ L9 f
    user_movies = [ i[0] for i in test_dic[userid]]# k2 `/ H* P- t. w4 Z. {: y) t4 d) p8 \

1 z; [+ @1 ?9 P  U    return [i[1] for i in recommend_list],user_movies,test_item_to_user,neighbors' L- [7 s' V% F# |- _
   
8 M8 V5 |; X1 h' i5 n    : G( n# k7 s0 l

. C" w: `* W+ Z7 J#+ D' D/ C- h6 w; c/ F0 K% _" Q
#" V# r/ `2 [; ?( p$ s
#   获取电影的列表; D0 y; h! A" q$ B# M: \
#
0 b" \  l. L6 q/ e#
1 b8 w' ^4 Y. r+ w  \$ o' [#% \6 G0 Z) N  u  f1 r8 p
def getMoviesList(file_name):& C6 k; m: _% X8 }9 q8 p. x
    #print sys.getdefaultencoding()1 R5 U7 `/ [" C3 R' d
    movies_contents=readFile(file_name)
2 O+ k  ~* Y4 K    movies_info={}1 p4 K# G" p( N% m
    for movie in movies_contents:3 U; x. ^: |6 W
        movie_info=movie.split("|")# ^2 Z5 `3 {6 g, g; k( n
        movies_info[int(movie_info[0])]=movie_info[1:]" N1 N' h( a+ y. ~: d! C1 H4 L: {
    return movies_info  W& u/ v- e4 c+ d/ _
   
) h6 R& _" o* J' b3 d2 [( J    ( @5 y6 L2 R9 ?2 `0 k
   
' K8 Q. Y8 s( n' T#主程序
( ^  m0 R3 K  r8 C8 }+ ^; c2 t#输入 : 测试数据集合
0 B7 T3 r6 b7 ]% n' W4 Q4 m0 n7 Wif __name__ == '__main__':
, b( o) @( C0 |4 B; d, K$ c/ q$ W    reload(sys)
  h1 `; H% Q% w1 Y    sys.setdefaultencoding('utf-8')( s" k" Y0 Q5 ?5 O* \8 Q8 O# U
    movies=getMoviesList("/Users/wuyinghao/Downloads/ml-100k/u.item")- r" u; g4 @/ X( }$ t8 r
    recommend_list,user_movie,items_movie,neighbors=recommendByUserFC("/Users/wuyinghao/Downloads/ml-100k/u.data",179,80)2 |0 y+ h. L, b. o  X
    neighbors_id=[ i[1] for i in neighbors]
/ l6 }" O' I" {" C6 ]5 T! l5 h/ ?    table = Texttable()( d) p/ K7 K7 L% z) n" c
    table.set_deco(Texttable.HEADER)8 U' U1 c  B8 j1 R9 h  ?
    table.set_cols_dtype(['t',  # text * C) `7 K3 i9 T' n5 H) o  K
                          't',  # float (decimal)' Z  c, c5 q/ G
                          't']) # automatic
2 V* R& ]# k( s# X; I% e! [# k    table.set_cols_align(["l", "l", "l"])
+ S* L; [, K- B7 S1 ]0 j    rows=[]
1 c7 S& A; n$ L    rows.append([u"movie name",u"release", u"from userid"])
' w$ n1 i. P  \" V    for movie_id in recommend_list[:20]:
4 o. V0 U8 C! x( n        from_user=[], L4 j* {! a' p
        for user_id in items_movie[movie_id]:7 t6 Z* _; W# q+ N) G
            if user_id in neighbors_id:% ^' j1 h0 X& G8 w- K
                from_user.append(user_id)' W0 i" j/ L) g) {
        rows.append([movies[movie_id][0],movies[movie_id][1],""])
  K" F  T  o) k4 m5 Z8 X# m: k    table.add_rows(rows), _) u* W6 g4 A4 \% m& A/ o4 }5 p1 [
    print table.draw()
作者: mea_lsc    时间: 2015-4-19 00:25
百年孤独 发表于 2014-7-19 09:22
7 Q3 N: b2 O5 `# K5 S8 p+ b( u% D# -*- coding=utf-8 -*-* d* I- E5 u4 E. F  v- K

% ], {, r. T( @1 q$ Zimport math

* I2 m  O" h9 u8 a* W, G这是什么语言的程序?
. @7 o; Y) x/ b* c
作者: 1943973818    时间: 2018-9-1 22:11
我来水帖攒体力了,哈哈哈哈哈哈哈哈哈哈哈哈
: n7 U+ T' ?2 e/ E




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