数学建模社区-数学中国

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

作者: harveymao    时间: 2014-7-18 23:21
标题: 求协同过滤算法程序
本人在学校参加暑假培训,需要这个算法做题!求大神赐教,感激不尽" a8 g: t+ Y6 i9 w) W. q* R

作者: 百年孤独    时间: 2014-7-19 09:22
# -*- coding=utf-8 -*-
, L. M9 Y: k, W8 a+ {% t- ]
; z; T+ d' T! |+ d1 |* ~import math, z/ }, b6 U' |- K0 N2 L
import sys
; l, \# ?( h- q0 [7 D. @2 ^from texttable import Texttable
. |' R5 d" o3 f! A; r# @% B- z3 m
" R! u/ _. ?+ `- c* f  [3 n+ z4 T( ~: O8 D" v
#, t& a+ Z; K$ r' R( N
#   使用 |A&B|/sqrt(|A || B |)计算余弦距离
7 y  E% H6 b0 s, W#7 C5 v$ u3 V9 X1 e% X
#
8 i3 s( w$ l& @/ n  j9 K3 {#
0 x3 p( E( M. B4 ~: O9 F4 m/ f2 d2 @def calcCosDistSpe(user1,user2):3 v6 e$ n) Q  w' q8 ^3 R
    avg_x=0.06 c, H, }" ^! |" G
    avg_y=0.0! S# w7 [/ p" K) C0 u& o! M
    for key in user1:
4 @5 B0 V# M6 ~3 [  F9 t$ }; Y        avg_x+=key[1]' P9 ]1 @2 d  ]+ X# W
    avg_x=avg_x/len(user1)/ h/ G: I1 o+ O) C
   
7 v- U1 s; H" C    for key in user2:
; y; ?: Q. u8 J3 M7 |/ z7 T8 u) e7 X        avg_y+=key[1]9 a5 I- h/ Z) B: H! U/ W9 \* s$ b! S
    avg_y=avg_y/len(user2)2 l# J6 f! Q6 o& n* U" K1 ^
    ( s7 ?' Y2 l/ ^; [% f3 E
    u1_u2=0.00 v4 ]1 z; [" o
    for key1 in user1:/ J: P, Z$ ~: [7 U, b
        for key2 in user2:
( D0 T8 x0 k& Q" n& W6 D; Q0 G            if key1[1] > avg_x and key2[1]>avg_y and key1[0]==key2[0]:
, j: X! _; g5 Y4 P9 o- u. z9 E                u1_u2+=1# p2 W, p$ d" x8 u, u/ w
    u1u2=len(user1)*len(user2)*1.0$ m5 m. }3 y7 n9 ?' n" T
    sx_sy=u1_u2/math.sqrt(u1u2)7 r: d, G) l& N: W0 t
    return sx_sy
* l; {# w' T( T3 o3 V* c" `& P) w5 R. S

0 t3 n9 k' ?6 _2 P#7 _3 V4 g/ n# [
#   计算余弦距离
( U! {6 U. D! u+ L- P  C#
+ N2 D  F& d/ N0 O2 ^. X#
( q/ s8 Y' g- kdef calcCosDist(user1,user2):! I/ O% m) h* y9 ?" ^6 f
    sum_x=0.0
$ H5 G: ~, V: b    sum_y=0.0
# `% Y4 B& y% D( Q7 }* i* C    sum_xy=0.0
1 k, p3 Z6 ~+ X/ K  I    for key1 in user1:
5 R6 M9 \1 F2 V        for key2 in user2:4 S6 ?% i) r7 W8 a/ n( G4 o. _
            if key1[0]==key2[0] :6 Z# g4 v; c1 I: t8 m, t
                sum_xy+=key1[1]*key2[1]
  J9 i! W2 _# S/ y8 L                sum_y+=key2[1]*key2[1]4 v6 v, i- M, Z/ F6 y
                sum_x+=key1[1]*key1[1]
. P7 G. v, Q1 R$ Q  }    . A- _- P- [8 m! L/ z# i
    if sum_xy == 0.0 :. q4 s, m+ g& C- n0 Y
        return 0
9 Y' t. w8 M% l7 f* Y9 Y    sx_sy=math.sqrt(sum_x*sum_y)
4 k/ ^+ T! {% I0 x9 a! Z    return sum_xy/sx_sy. j6 Q9 O3 y# {, }+ w
) H# ^$ a+ q$ d0 n' e0 J, J- y

5 P* U+ }- b4 J# j9 a, d#
0 c  M2 Q5 D" O#/ [$ _6 i8 O  o: G! m
#   相似余弦距离
6 T% u7 Y( k9 |" b& k+ J## g% K1 g' K; X! T8 j
#
8 D$ a6 K' t6 W2 l+ v#6 _5 X: C" w& V& t, s
def calcSimlaryCosDist(user1,user2):7 a: m4 u! H. r% Y  c
    sum_x=0.0
1 J! u7 Y. W) ^- k* K1 s    sum_y=0.06 e8 I: H: R2 k: z4 G! `
    sum_xy=0.0
: `0 N3 t9 _$ r, s) z% ?9 F: `$ j    avg_x=0.0
$ H% L' r/ m1 s: {  E4 k* |" ^    avg_y=0.0
! D5 X9 I8 n! O! Z3 \# V, c  l    for key in user1:+ i8 Z% Q! r" n7 W3 t5 [4 ^
        avg_x+=key[1]
& x6 q0 b) \% o/ L/ a) Z0 {# t    avg_x=avg_x/len(user1)% E/ s: T3 b  a: t5 A/ T5 H
    * L: W' {8 Q3 P2 c
    for key in user2:7 k8 N$ E  T# O0 k- b# ]$ L: P
        avg_y+=key[1]" D! o) F( C, v! `# s! d6 l
    avg_y=avg_y/len(user2)3 d/ N/ ~* H0 Z; o( S# `: c$ e. o, h
   
6 N$ D* V7 l) w$ T/ m" x; e    for key1 in user1:
" r$ A5 [& }# A' ?# P        for key2 in user2:
2 E: ~6 @! u( L0 z1 c% o            if key1[0]==key2[0] :. ^, g9 Q- {; B4 i
                sum_xy+=(key1[1]-avg_x)*(key2[1]-avg_y)
, a+ ^7 X8 U: Q+ Z  I                sum_y+=(key2[1]-avg_y)*(key2[1]-avg_y)
( X. D; X4 L2 }# Y( }% s( b        sum_x+=(key1[1]-avg_x)*(key1[1]-avg_x)
7 V' s$ n9 @8 n7 I& K  c   
/ @4 e5 ], X+ j; i    if sum_xy == 0.0 :8 P9 [1 {" N4 E1 j# C" \
        return 0
4 o  h! `2 g( W6 t/ I4 E( T& _    sx_sy=math.sqrt(sum_x*sum_y)
$ _# n2 ?2 l9 i5 t. E( U    return sum_xy/sx_sy
9 K. A& |1 n5 V2 v   
3 U; Q0 l) }- t  ^
6 z2 P( t) g' R#/ P8 x0 C3 H) v/ T' C) G* ^! r
#   读取文件5 {% g  ?9 z& b5 c
## f* O( F% v5 Y, t
#
1 R" ^3 J( o3 vdef readFile(file_name):7 [: _" F: d7 F0 n# v
    contents_lines=[]
) g' s( U5 c; G4 @/ H4 h+ A    f=open(file_name,"r")
7 ^; Y# R; o: }: Q! C: a( a9 T& n    contents_lines=f.readlines()
7 a# V5 n) e) @- i$ Y    f.close()
3 m3 K/ J& _5 G! r# J4 A    return contents_lines& B. z2 y4 B1 Y4 b* t9 Y

2 y/ b8 L2 S$ ]/ M# o; W/ S
. d7 G, p! ~, L( y' P4 y
5 f( k  M, L0 h% l#( M; t; N: |6 j6 x3 y
#   解压rating信息,格式:用户id\t硬盘id\t用户rating\t时间7 G0 t0 y0 Z$ D0 [# h2 \$ a+ n9 d
#   输入:数据集合
. _- ]  n4 T: t* m' J#   输出:已经解压的排名信息
! I! b" x& D+ r* z/ m#. k. j5 \+ ^" V8 v( s; A- [
def getRatingInformation(ratings):
$ ^/ w* u3 `* y    rates=[]; K: F0 x* a0 }
    for line in ratings:
( S5 m/ F4 L: R6 A" `        rate=line.split("\t")0 d, {1 Z6 |7 A6 ^) S
        rates.append([int(rate[0]),int(rate[1]),int(rate[2])])& M! z2 M5 ^% ~$ a
    return rates
0 U$ O3 o" V# {5 j$ ^- u! w6 J2 W8 k. T! O
  ]3 o8 j7 k2 p1 e) X
#5 Y% _1 O9 P1 T5 Y$ V: |
#   生成用户评分的数据结构
7 i& m; @5 e( g7 s% U#   
  J3 Q1 A# }2 A8 F$ x( {4 Q#   输入:所以数据 [[2,1,5],[2,4,2]...]) }7 Z8 t$ l( s+ l
#   输出:1.用户打分字典 2.电影字典
: a# G; V3 V/ R9 ~2 b8 F, ?4 O#   使用字典,key是用户id,value是用户对电影的评价,
& {# T+ V8 [+ Y( G; Q; R9 ~8 a#   rate_dic[2]=[(1,5),(4,2)].... 表示用户2对电影1的评分是5,对电影4的评分是2
& S  L  ]6 [1 R* u3 x+ D/ ]#! }6 f: n; p2 y* x& ]
def createUserRankDic(rates):- A8 ~- e. ^( E# s3 X! C, S8 u3 \
    user_rate_dic={}5 d  e8 ^# z7 w! L
    item_to_user={}
7 N' k0 e/ X1 ?; G1 @0 @7 \    for i in rates:( q* v$ z8 v: x$ u3 o, d- I3 x
        user_rank=(i[1],i[2])1 Z6 L9 }. {5 t, T$ Q; r
        if i[0] in user_rate_dic:, D" w% M9 g) ?  d) Q+ ^
            user_rate_dic[i[0]].append(user_rank)
4 L. u/ M) z# u/ K        else:6 f$ Z0 N- [: i6 C# H
            user_rate_dic[i[0]]=[user_rank]! K7 Y4 M# e% l4 ^, v
            
: g4 H/ ^/ t) o        if i[1] in item_to_user:3 C8 @& k* e' W7 p& K# d
            item_to_user[i[1]].append(i[0])
! m# q4 i8 @* h1 c& p+ a- ^        else:) `' Q5 y$ k5 V- [6 r, b/ b) E
            item_to_user[i[1]]=[i[0]]
& ?; i& B" i! t4 J, G3 e; I            & y/ d. A" N! D. M8 s
    return user_rate_dic,item_to_user' n1 l# f* R+ H! z$ L4 e( R: k
! J5 t( ?- B3 h1 L+ _, d

' ]* q7 t- c7 n# p- B% {#2 d1 l7 c& }8 z9 P( p
#   计算与指定用户最相近的邻居
! e! m+ }, J) \: x0 W#   输入:指定用户ID,所以用户数据,所以物品数据
/ R5 H5 }) v- s$ d; [8 a#   输出:与指定用户最相邻的邻居列表
! l$ ]1 L% d4 {1 g0 b7 f* y#
, h, G1 k/ m+ t8 C" T: E# xdef calcNearestNeighbor(userid,users_dic,item_dic):
- D; C( x6 O- j' }2 D    neighbors=[]
5 `" R9 r! A. c4 @, Z9 B  T    #neighbors.append(userid)+ }5 S) M- Z( d" }' s/ u
    for item in users_dic[userid]:2 r6 ?' }9 k  q( |; R* E$ ~% T
        for neighbor in item_dic[item[0]]:) Q. Y% n% ^* L. I: F; J+ T3 [3 g
            if neighbor != userid and neighbor not in neighbors: 7 ]% z5 P' |& y6 D+ v7 H: C
                neighbors.append(neighbor)
* X9 d% D+ ?5 R0 E      
3 u. u+ ?& \* C- o" a" R+ F# R    neighbors_dist=[]
# @$ \; C% @3 V9 N$ m    for neighbor in neighbors:
- \. N& l, H! E        dist=calcSimlaryCosDist(users_dic[userid],users_dic[neighbor])  #calcSimlaryCosDist  calcCosDist calcCosDistSpe; Z: P( a" X8 v' v6 H& H
        neighbors_dist.append([dist,neighbor])/ I4 k" M) R& N( _: d
    neighbors_dist.sort(reverse=True)8 W  |2 t2 S4 t, v! }' r) R
    #print neighbors_dist. u( O( O$ D. Y. @6 v9 ]9 k
    return  neighbors_dist
6 w: g. R# w2 a( H2 H" U. |9 D7 K

; D) R$ m* n9 N#
* @9 A3 c$ a8 R, b- J/ Q3 Q# k#   使用UserFC进行推荐
9 M& P; I6 \: ~0 I/ c#   输入:文件名,用户ID,邻居数量, d& O1 @& z. R% n
#   输出:推荐的电影ID,输入用户的电影列表,电影对应用户的反序表,邻居列表
) ~& c# F- d+ H" `; b' c#
: t+ J: H; j2 m2 a( ]1 Ddef recommendByUserFC(file_name,userid,k=5):% Z& I. E, w' Y: ~2 G
   
# ?0 i' c8 z' O1 T    #读取文件数据
" U4 R! o& F' L, P: L* ^    test_contents=readFile(file_name)
7 I2 |& K5 |& y) g   
/ u! Y; X$ x2 S" r" `4 o    #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...]
& o, A( F; O+ q7 Z& a7 R- S3 i    test_rates=getRatingInformation(test_contents)' N) w" d5 C$ `! b
   
5 ]4 R/ |0 g) d- F. X4 Q# X    #格式化成字典数据
" b  X+ A# e* `) A0 M/ ]    #    1.用户字典:dic[用户id]=[(电影id,电影评分)...]- [4 j( v2 ^& G' k2 X3 M% a) z; a
    #    2.电影字典:dic[电影id]=[用户id1,用户id2...]
1 m7 l/ ~) B+ W" Q; u7 k: z    test_dic,test_item_to_user=createUserRankDic(test_rates)* A7 O6 P. P/ E3 }
    * N, x6 U' I6 N% g2 Z
    #寻找邻居1 ~/ u1 `! U2 j0 E  v+ s
    neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]
6 y( ~, Z% O" I8 ~+ U- I) r# }        
4 B3 l% ^) l! {2 m% z( e    recommend_dic={}5 G# ]. T+ E- u" F2 U  W
    for neighbor in neighbors:
1 G$ x) ?% l& V  y        neighbor_user_id=neighbor[1]" b3 ^- ~) ~; i* M: N3 S
        movies=test_dic[neighbor_user_id]' ?! w* r! Y0 G4 |
        for movie in movies:, B& L+ C# N+ W* V, s) E
            #print movie% ~* N2 w$ O% Y+ P8 _2 e, H
            if movie[0] not in recommend_dic:
' \% m( A/ D3 c/ {7 b                recommend_dic[movie[0]]=neighbor[0]
, b; Z% h1 Q! ?+ B0 D- r) {9 ?            else:
( R) K. r# e4 z" B( g/ B) R                recommend_dic[movie[0]]+=neighbor[0]% ]5 |4 N  _  }' X; |
    #print len(recommend_dic), t# E4 X/ Y  m) B  `
    9 g7 J! P8 @5 K3 P
    #建立推荐列表- x: T! P9 \5 a* T* y. g' F
    recommend_list=[]
, y, x! l; V( t: G  F" K    for key in recommend_dic:- b( O* J2 C: l% x
        #print key) B+ f4 W* y+ G
        recommend_list.append([recommend_dic[key],key])
5 s) \' {% C3 j, k( j; G0 M   
1 e7 }7 Y* N& d2 x   
* G6 C4 f! D! s2 x    recommend_list.sort(reverse=True)
6 ~( m* G9 V7 R! }( {    #print recommend_list' @" E- _3 X) [# q3 r
    user_movies = [ i[0] for i in test_dic[userid]]& f1 c% x: T6 \2 W4 f

7 g' s5 Y3 G- M. O5 O    return [i[1] for i in recommend_list],user_movies,test_item_to_user,neighbors2 _  T- ^+ i6 R! {/ H. S/ F; @
    / [4 \6 W2 D% C: Z  q& i
   
: B+ d* k7 z( b5 h4 c
% A2 x8 ?! @0 |3 h$ t#
4 X4 O  z' v0 U1 W3 V* i8 \#6 K$ l% u  M" Q5 O- `$ ]$ J
#   获取电影的列表
/ m- b& R3 I6 |#
. Y8 B; t6 Z3 S#  ^+ K8 T2 G( J) a8 K! O5 K( L2 S
#
7 s5 G/ D% E. ~! T" D. z; D8 Zdef getMoviesList(file_name):
) m* S. D) D- H    #print sys.getdefaultencoding()  f. v& k; O/ q/ E
    movies_contents=readFile(file_name)
. W/ s; h6 F' k% C8 Y2 b' r    movies_info={}
1 X& C. J- I* h1 a1 x  p0 a+ y    for movie in movies_contents:3 w/ p0 i2 ~5 p- A7 z
        movie_info=movie.split("|")
2 ^% X  J2 }0 ^; p' a. w7 F/ f) H" x        movies_info[int(movie_info[0])]=movie_info[1:]
4 a  o4 T2 ]  C2 Q* n) K    return movies_info& \% Z) J' Z) `9 c/ Y/ L9 L4 S$ A, J
   
0 }  N% Z& U6 O" _  A    * J$ m) F& r& I, Q
   
0 n0 q& K0 J5 [#主程序
, x% N$ ?4 j6 j/ v- ]+ x#输入 : 测试数据集合8 g) |" _1 k& Q+ @/ \5 L' d. B9 N" p
if __name__ == '__main__':# B0 _, W+ N" v/ R% H
    reload(sys)2 |6 x7 \9 [/ o6 n3 h% O
    sys.setdefaultencoding('utf-8')" w* S* }, F! ~. i; Z
    movies=getMoviesList("/Users/wuyinghao/Downloads/ml-100k/u.item"); |' c& E  {% F9 g' \3 Z9 ^6 l
    recommend_list,user_movie,items_movie,neighbors=recommendByUserFC("/Users/wuyinghao/Downloads/ml-100k/u.data",179,80)' N0 f. v' S* t- t& U$ ~
    neighbors_id=[ i[1] for i in neighbors]  y+ \, t8 i" v; @% z
    table = Texttable()7 I7 ]4 f! q2 u2 V4 F6 c+ Z) j% ]/ t4 B
    table.set_deco(Texttable.HEADER)2 |- x: O; a9 e) ~
    table.set_cols_dtype(['t',  # text
- x: }/ g: y- B, h8 P                          't',  # float (decimal)! I9 B1 F: p9 ]. p- Y) }9 r  ~
                          't']) # automatic6 p6 |4 O& x# A: P5 N. ^
    table.set_cols_align(["l", "l", "l"])) B$ ?2 ]  ^+ y' P/ w+ H: V0 o
    rows=[]
. Q- F" e! i3 Q& [; y/ I# m    rows.append([u"movie name",u"release", u"from userid"])
8 m# q1 }) q+ K4 ]. E    for movie_id in recommend_list[:20]:
8 `1 E1 U. K7 J; _  E+ `        from_user=[]
! U1 W! J2 A7 |. c2 l6 e8 @        for user_id in items_movie[movie_id]:
4 Z8 {/ f$ d! v8 Q4 o- x            if user_id in neighbors_id:
# V( ^( _. M: ^! ?+ x                from_user.append(user_id)
; r& Y/ B' x  D        rows.append([movies[movie_id][0],movies[movie_id][1],""])6 X1 `  `, t" f" [, v0 H8 ^
    table.add_rows(rows)% p4 g- V6 s* F+ G+ t& i
    print table.draw()
作者: mea_lsc    时间: 2015-4-19 00:25
百年孤独 发表于 2014-7-19 09:22
* r$ a2 X) [3 v, U# -*- coding=utf-8 -*-
! d1 v3 h3 Z$ ~  x4 ]/ O, A6 O% F6 w: @4 v" S  R: G3 a( V) A
import math

3 u6 c- g8 I* X* [6 y# K2 \$ V( |这是什么语言的程序?
. J  j9 I  `7 ~
作者: 1943973818    时间: 2018-9-1 22:11
我来水帖攒体力了,哈哈哈哈哈哈哈哈哈哈哈哈# E& Z3 h8 h0 M4 i5 F) e





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