数学建模社区-数学中国

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

作者: harveymao    时间: 2014-7-18 23:21
标题: 求协同过滤算法程序
本人在学校参加暑假培训,需要这个算法做题!求大神赐教,感激不尽. g& J' ?1 S9 H3 F4 V

作者: 百年孤独    时间: 2014-7-19 09:22
# -*- coding=utf-8 -*-7 y2 @) P' e' R0 ?4 g- w  z

; [7 j7 c5 q% R! W, t0 s/ aimport math) M* |+ w1 m5 P9 G
import sys
( g4 u1 ^+ \8 C8 X' V$ x8 M: U2 Bfrom texttable import Texttable
  b5 Q3 p8 z$ B$ ^* G
0 w; K8 j$ Q1 E+ ?: G6 a2 H( i7 Q% v) u
#; P$ k. U  b- l1 d+ W
#   使用 |A&B|/sqrt(|A || B |)计算余弦距离7 H, J% i1 {  i& r( N+ J
#
- t3 P+ s2 T0 R1 t#
7 S6 [2 t# e( h6 K8 v, k#1 G& m+ {3 A1 T6 N
def calcCosDistSpe(user1,user2):
7 i1 G1 j0 k3 F2 |* v4 U* o    avg_x=0.0
5 A. ?9 @4 \: x+ j3 L) Q    avg_y=0.0- C! I4 R6 W2 e  b! R
    for key in user1:5 F1 w1 g3 M# v8 C
        avg_x+=key[1]; {% t7 _5 |! y5 v- }0 w
    avg_x=avg_x/len(user1)
9 H# d0 I6 w! C( A   
, ]) V8 v! I3 B6 I: g    for key in user2:
+ P& _1 V; }. k- |( Z        avg_y+=key[1]
3 B( q: V! p# @9 K    avg_y=avg_y/len(user2)
$ R1 L+ H1 Y+ S% |0 J! V   
: t* }8 g" a! Q5 N' {    u1_u2=0.0
1 q; i! e; F7 v0 y! j5 P    for key1 in user1:5 z+ D  Q$ R" n) O) r
        for key2 in user2:5 e3 P+ P. x3 y* `' e: m
            if key1[1] > avg_x and key2[1]>avg_y and key1[0]==key2[0]:
7 x' \' U) z) j" c2 Y& K                u1_u2+=1
9 [# _# X& D7 N. o    u1u2=len(user1)*len(user2)*1.0
) N: D9 e) F! h) }: ^    sx_sy=u1_u2/math.sqrt(u1u2)
6 D( m! |9 }4 _. y  p# w    return sx_sy0 f2 \- K) Y8 N* D
) S3 u6 U  e% G& w7 f' D
8 H$ y# a& `. |
#
* m/ |# f2 @( s9 L3 r0 C#   计算余弦距离
% ]0 \* p4 L2 L! M#
8 Q6 B& p2 `( v. r#
% r) X2 D6 F$ Tdef calcCosDist(user1,user2):
0 B6 _6 A6 x+ O; L& H& H  Y) m% p6 p    sum_x=0.0
0 A) f# I& n& M% H/ k3 Q    sum_y=0.0
* l2 ]' N) m2 |+ q7 ]0 k    sum_xy=0.06 O" }2 b. s% O9 Z( R) N  P
    for key1 in user1:
3 V7 F5 l4 @% @. L- f: V        for key2 in user2:
/ ~4 j% m$ l" Z) V  z. n; V: m0 \            if key1[0]==key2[0] :( s6 V& H3 R; v& G8 y
                sum_xy+=key1[1]*key2[1]
- h$ Y3 k" @+ A: C                sum_y+=key2[1]*key2[1]
. a8 W7 m, s5 p' ^8 C$ K% b& t$ b                sum_x+=key1[1]*key1[1]
+ Y) k, d. w3 V  c, \. f0 ?    9 Y8 O  s+ v& z/ y- @
    if sum_xy == 0.0 :* S6 v' t, T. g1 f
        return 0
. N$ k8 r+ ?3 L0 E! l7 t0 c0 P    sx_sy=math.sqrt(sum_x*sum_y) & v2 q9 w( g* M0 }# L
    return sum_xy/sx_sy
# ~; Z" m& |2 K( B2 W
5 w! v9 h: U; o+ e" C: |" W" z3 x) x3 L0 B/ ]
#& h3 X3 Z. y4 J/ c
#
. k- ~6 X( Y' \& f0 S: n5 y#   相似余弦距离1 K; L; a0 T9 o9 a0 D) g
#) g" E4 q% k9 ]% h  G
#
" {, {) x& H6 |/ {: v1 z#
+ ^* }" y6 ]1 F/ H7 V: Y0 Jdef calcSimlaryCosDist(user1,user2):
" i; Y2 M$ J' |1 Q% o4 r    sum_x=0.0" w- j8 s& c; {( Q* v6 G. n
    sum_y=0.0* `/ [" y) Z* v: W0 n
    sum_xy=0.0
" G; A% E$ g. t) W    avg_x=0.0' P$ [& m: C( z& f# ^
    avg_y=0.0& l- `. q/ ^% y, u7 E8 O( J# D5 ?* r
    for key in user1:- y1 Y4 x+ a: @* h/ P
        avg_x+=key[1]
9 x0 `" v/ x# J" f: v    avg_x=avg_x/len(user1)
& b3 `1 o& i! {( X- h0 K0 }- S   
5 P( v( ?: j9 j, M! S+ m% C    for key in user2:' ~- k  ~( a  t+ L8 M" y2 }$ I7 C9 c
        avg_y+=key[1]
7 k2 v+ g4 B( {) ^4 k! A    avg_y=avg_y/len(user2)
* k% u8 h5 v/ u* Q    % ]  ]: g  ]. a7 n6 C
    for key1 in user1:
4 v0 s: }& a1 [        for key2 in user2:3 y; E. M2 x+ X/ `7 h) _
            if key1[0]==key2[0] :
' N0 d% E$ L1 @, W  e                sum_xy+=(key1[1]-avg_x)*(key2[1]-avg_y)' {* F; `. @3 w- v# a  P. x
                sum_y+=(key2[1]-avg_y)*(key2[1]-avg_y)
2 R1 J- t* p, H5 u4 k: q/ J        sum_x+=(key1[1]-avg_x)*(key1[1]-avg_x)4 l9 j" C1 i+ Q; u/ r/ y
   
2 J( n) `1 K9 y9 w1 ^* W    if sum_xy == 0.0 :
* L/ g" r7 C" x( _# u( t0 o        return 06 r3 x4 D+ ]  ~' W/ h2 q" [
    sx_sy=math.sqrt(sum_x*sum_y)
6 _1 r0 k' G% ^( o" N. P: S. P4 k    return sum_xy/sx_sy
# @. m0 k( N0 s   
4 w2 Q- I/ I+ j2 k
, l  `: J/ O* o, C#7 m$ y( n8 P, L& D# P; B
#   读取文件
& ~& G# u. T6 @( s#
$ P$ i4 E4 J; E; ]9 s) {* {#
6 {* R$ s" W  i. c$ ~def readFile(file_name):
& k) K6 @- o1 Z, i+ k% T    contents_lines=[]7 j2 v: C! k' T" Y& n+ ]! v! F
    f=open(file_name,"r")
! `, {0 _' T2 z( U    contents_lines=f.readlines()8 {$ F5 }4 {! c" ]& |' }9 Z+ N
    f.close()
1 _/ {: Z3 B% L. G  ]    return contents_lines& _$ Q; K) b' E5 F

; T7 F1 m% x! Z  }8 G- C8 P5 R9 I- @3 z" V& X+ ?  t

: J8 W5 {  Z' h, U. r2 E- v2 l#
& {( }; _* M0 y8 O8 _/ g#   解压rating信息,格式:用户id\t硬盘id\t用户rating\t时间/ K# A; L' E, d2 P. F. j+ Z
#   输入:数据集合
( }3 @0 ?- m9 ^5 [#   输出:已经解压的排名信息3 i% S2 K8 G9 z# q
#& S* k5 w9 L+ z8 p" V2 ^* _! B
def getRatingInformation(ratings):
$ R: g6 w% J. Z( J$ x) s) }! O    rates=[]4 k; S- ~. I! a  S  P
    for line in ratings:1 x3 R8 s: o' W; h
        rate=line.split("\t")
( H- m  d- N) z% \        rates.append([int(rate[0]),int(rate[1]),int(rate[2])])
+ G: w4 j/ g* \* x" C5 @    return rates8 o- s& x* O( r* O8 L
! Y4 o2 Y9 [: ?
! x4 X$ J9 v' E- [! w
#7 V3 E* `- s2 K9 c8 W$ {
#   生成用户评分的数据结构
; f) j9 B0 }& T$ G; m* l2 s" H9 k) \#   3 e1 ~+ p8 R( J) v- X+ P0 @- v
#   输入:所以数据 [[2,1,5],[2,4,2]...]+ n% _" p; g, S7 \
#   输出:1.用户打分字典 2.电影字典5 R7 Z1 O" U1 i& O1 e
#   使用字典,key是用户id,value是用户对电影的评价,$ M* {* W+ \8 J) Y2 r1 d
#   rate_dic[2]=[(1,5),(4,2)].... 表示用户2对电影1的评分是5,对电影4的评分是2
& Y3 M  N* R' Y' J; d# @8 I- J#7 s2 O1 C, e' v
def createUserRankDic(rates):
$ B6 Q, O7 ?% O* @    user_rate_dic={}9 p) i7 S" m8 [2 f, C( s3 `
    item_to_user={}- J- T7 K9 m. [( D" X/ s4 _
    for i in rates:
% L, y- ]8 p) n: \9 J        user_rank=(i[1],i[2])
( Q1 B( ]( K2 Y2 S1 F' ?        if i[0] in user_rate_dic:
# R. a% w2 ^; n4 i3 t0 }: ~            user_rate_dic[i[0]].append(user_rank)
+ y/ T; [. o0 q5 ]. E3 T        else:$ Y, X7 y: Q# M* g+ n, V: g
            user_rate_dic[i[0]]=[user_rank]
! v: ~' J3 u- W' E  E8 N) s            6 ?1 g5 P) i* U$ l5 _4 @* E+ F3 y
        if i[1] in item_to_user:
- R- U7 s. C& ^0 b/ g            item_to_user[i[1]].append(i[0])
$ W3 B; Z& s! W# }        else:" F2 `% k4 @, y
            item_to_user[i[1]]=[i[0]]. U. v1 N% {/ @
            ; ?, E1 H( D- d. \4 ]. i& c& y
    return user_rate_dic,item_to_user  }7 t3 W$ g* t4 G$ e0 }

/ S" L$ L: v7 C! M8 Y
! D; r; c' L+ l( @  D7 D#! s# P, k) a/ {1 a. _! }0 F4 p- e
#   计算与指定用户最相近的邻居
# W1 F2 Y& U5 {% F9 b4 b$ q#   输入:指定用户ID,所以用户数据,所以物品数据
2 }  W2 c' D1 K; [#   输出:与指定用户最相邻的邻居列表
6 z9 `+ ^9 o/ {- Q5 U#
8 u. g# X, U* Q$ F' mdef calcNearestNeighbor(userid,users_dic,item_dic):
6 r" O: G; ]; j    neighbors=[]
3 l4 l, @+ X! ]* }5 K7 S4 J    #neighbors.append(userid)9 ^5 O/ J# m7 @- ?  q9 f9 @/ Q
    for item in users_dic[userid]:
% g" r8 x; t. S  O        for neighbor in item_dic[item[0]]:
7 R" s  @* {4 S            if neighbor != userid and neighbor not in neighbors:   @$ _" }  ]0 d
                neighbors.append(neighbor)2 v$ n& r: n5 O7 w
      
, G# D+ V6 r& O; c+ F6 _6 `2 Z" P    neighbors_dist=[], N4 f- w5 q1 [: y9 X6 b
    for neighbor in neighbors:7 `# G; X9 y: d+ {
        dist=calcSimlaryCosDist(users_dic[userid],users_dic[neighbor])  #calcSimlaryCosDist  calcCosDist calcCosDistSpe
, l4 C+ w- [) L! N! d  D        neighbors_dist.append([dist,neighbor])  U0 S0 J! H8 Y6 w2 {" Z
    neighbors_dist.sort(reverse=True)7 R. K: N! K+ l3 U. Q
    #print neighbors_dist" {& O7 I- c9 l% h
    return  neighbors_dist
( ?, n: a0 B2 b; J1 e3 `' j" C, Q% N) `* E

  s1 Y4 M  }9 z0 T: C! b#
' w( S1 [/ K, W. A#   使用UserFC进行推荐
& W9 K3 R& @' W1 q#   输入:文件名,用户ID,邻居数量1 g2 D+ v; ]3 g1 p
#   输出:推荐的电影ID,输入用户的电影列表,电影对应用户的反序表,邻居列表
$ |6 i4 N5 \! Q6 c/ T% |. A. K#
, P0 g' W. H9 v+ [- J: i7 v4 V5 hdef recommendByUserFC(file_name,userid,k=5):
8 ]- k  Q- Z+ L) i5 L" `    4 b% U/ I4 M6 b, s
    #读取文件数据
0 A8 a4 s! r. j' H3 r    test_contents=readFile(file_name)
* c9 K% S1 R- ^! S9 N    : A. Z2 |/ p6 L) f" h9 ~
    #文件数据格式化成二维数组 List[[用户id,电影id,电影评分]...]
  v, e# Y# \9 G2 d    test_rates=getRatingInformation(test_contents)" c8 H8 G% n( `* E3 w$ M2 P# D
    . \& }. `. y2 `$ m8 [
    #格式化成字典数据 7 J* `6 n' X6 a
    #    1.用户字典:dic[用户id]=[(电影id,电影评分)...]& m1 S8 g3 E! N/ t3 i5 ^
    #    2.电影字典:dic[电影id]=[用户id1,用户id2...]) ~  C: K$ G4 \. M1 d5 u$ P! ~6 {
    test_dic,test_item_to_user=createUserRankDic(test_rates)9 t2 |$ Z7 a( N# c$ i
    , V' ~$ l6 `" T, G, k8 w7 h
    #寻找邻居
# x# [, o3 N$ W    neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]
* n' c, P4 @6 V$ A9 [        
1 u* z" p" y/ [5 T    recommend_dic={}
% L! i: U+ H# L6 l    for neighbor in neighbors:# d( R' x0 ^/ W" @& ~9 n2 n4 S- e& t
        neighbor_user_id=neighbor[1]
/ P$ X& _! V% v4 d2 D# V, Y        movies=test_dic[neighbor_user_id]6 D! x% ~( j& Q0 b
        for movie in movies:
) r- K- }7 k8 f. `- j$ v9 q            #print movie
& E9 `+ e; u, H" l5 m            if movie[0] not in recommend_dic:
, |* S( Y$ |- l3 T+ w1 I* X                recommend_dic[movie[0]]=neighbor[0]$ {5 Y, ~  ~; F
            else:: v% Z' R) c  V) V) z; X
                recommend_dic[movie[0]]+=neighbor[0]
9 Q2 t9 J3 w  z& k/ z" M    #print len(recommend_dic)& Z, G+ K3 b% \  V
   
# X  |- ]9 a  z- i7 T; C* r) s    #建立推荐列表7 F0 g3 g7 e! ~2 Y8 F7 b0 U
    recommend_list=[]
9 a) ?! K6 x+ g, j: c8 {# N: V/ {+ W    for key in recommend_dic:
) x: ~" K2 [' H! m1 v1 j        #print key5 F2 U' F' h) A% ]' ?- K. I0 B
        recommend_list.append([recommend_dic[key],key])2 M7 N4 N6 U- T4 b$ p% e
   
7 [% |+ E: C& o* |& _) c9 e8 J   
( ^4 |+ m" ?4 C7 n0 a7 b    recommend_list.sort(reverse=True)
3 M( @  e0 g0 x0 A+ M/ T, T" \+ E    #print recommend_list
5 a# J  m. m* F: c    user_movies = [ i[0] for i in test_dic[userid]]% p1 [3 w' x' H6 ]8 ]3 w
% _# B9 U$ `5 e
    return [i[1] for i in recommend_list],user_movies,test_item_to_user,neighbors
% S/ b5 r! v0 }    & B5 g5 `" x- r, [5 Z: E8 V
    1 n* z# `0 q* G/ t6 e1 \

$ E9 t/ h5 C8 Z' f, |0 C#( r) l6 T9 i2 f6 ^  T8 Y/ x
#
; |0 t9 r1 L8 H7 t#   获取电影的列表' {+ K4 t! e; e5 v7 U
#) ^4 i5 l" w" q/ U* o9 a
#0 S5 v' N/ N# c( s
#. v9 A, c& E' X7 x$ J3 U* {
def getMoviesList(file_name):
9 Z% x% V! C/ x, I    #print sys.getdefaultencoding()3 }* }8 s5 n' ]: m4 Q9 A; \
    movies_contents=readFile(file_name)
- O) A) u/ N# [( N+ k, O) O6 m# Y    movies_info={}
% G3 ~2 |* d9 f- J3 M( o8 K    for movie in movies_contents:! Y' ~8 E8 Q. s1 Z! t
        movie_info=movie.split("|")( D; v1 u) u2 o; p( t0 Y
        movies_info[int(movie_info[0])]=movie_info[1:]) o- M' ^9 Y3 M& O5 j
    return movies_info
$ g! d! ?% d1 x+ Q6 ]  y- h2 @   
( |$ {3 _0 q7 B" r6 Z+ {' g    7 U1 x$ e2 b  \) b: c. L
   
* f' d; Q8 N" _6 ~( Q$ P3 f* O#主程序
! K4 }, |- t) ]6 z#输入 : 测试数据集合& Y: v( s; j/ U5 w
if __name__ == '__main__':
4 m# b  R" W- s    reload(sys)3 v. K- u( C( `( A" N# n
    sys.setdefaultencoding('utf-8')
4 k3 Y& [8 w- u0 y; |( B0 w    movies=getMoviesList("/Users/wuyinghao/Downloads/ml-100k/u.item")4 s. ?( _4 S7 \' o8 k5 L
    recommend_list,user_movie,items_movie,neighbors=recommendByUserFC("/Users/wuyinghao/Downloads/ml-100k/u.data",179,80)
% n( y" b/ K7 X% y! y' G% z' W    neighbors_id=[ i[1] for i in neighbors]& F8 w( b5 @  f* j# N
    table = Texttable()
- X0 n2 \/ _) j! m$ e5 v    table.set_deco(Texttable.HEADER)
- S8 @: {* U, {# L: T8 V    table.set_cols_dtype(['t',  # text
) u2 k" Y7 i# O                          't',  # float (decimal)1 t! e! Q7 {( V# s) `
                          't']) # automatic
3 m. l! l4 r. R# I1 r9 f    table.set_cols_align(["l", "l", "l"])& D5 M% @4 Y. {: t* y. j* b1 E
    rows=[]
  C! Y1 t5 b7 B6 {4 w- l    rows.append([u"movie name",u"release", u"from userid"])
6 Z# S  [4 H+ O9 R4 v, |3 ~    for movie_id in recommend_list[:20]:
7 s# a' O, H; W5 Q. _        from_user=[]
3 R2 c% R/ g( B        for user_id in items_movie[movie_id]:
4 d. e0 S, b3 w9 Y            if user_id in neighbors_id:% f7 O+ o, M: c7 \8 y4 n$ P
                from_user.append(user_id)
6 ?8 f# B! S, Q) g* A. B+ Y. l        rows.append([movies[movie_id][0],movies[movie_id][1],""])# w1 s+ ]4 E. i
    table.add_rows(rows)
) @! P: ~0 {; k2 o$ ~1 j    print table.draw()
作者: mea_lsc    时间: 2015-4-19 00:25
百年孤独 发表于 2014-7-19 09:22
8 M- q( V  [+ b% c: l# -*- coding=utf-8 -*-7 s! s$ W3 o+ r  I
& Q  \7 Z# @" z- W! o; L- l
import math
" e5 x! K$ L; R4 y
这是什么语言的程序?" g: P. z9 B! ]/ g3 ^

作者: 1943973818    时间: 2018-9-1 22:11
我来水帖攒体力了,哈哈哈哈哈哈哈哈哈哈哈哈
$ E# Z+ q9 {' {; E( l




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