1+ <?php
2+ namespace Tigo \Recommendation \Collaborative ;
3+
4+ use Tigo \Recommendation \Collaborative \Base ;
5+
6+ /**
7+ * Slope One algorithm
8+ *
9+ * @author Tiago A C Pereira <tiagocavalcante57@gmail.com>
10+ */
11+ class SlopeOneCollaborative extends Base
12+ {
13+
14+ /**
15+ * Get average weight.
16+ * @var array
17+ */
18+ protected $ weight = [];
19+
20+ /**
21+ * Get items rated by other customers (difference matrix).
22+ * @var array
23+ */
24+ protected $ factor = [];
25+
26+ /**
27+ * Get items rated by the client.
28+ * @var array
29+ */
30+ protected $ myProduct = [];
31+
32+ /**
33+ * Get recommend.
34+ * @param array $table
35+ * @param mixed $user
36+ * @param mixed $score
37+ *
38+ * @return array
39+ */
40+ public function recommend ($ table , $ user , $ score = 0 )
41+ {
42+ return $ this ->filterRating ($ this ->prediction ($ table , $ user , $ score ));
43+ }
44+
45+ /**
46+ * Get customer rated product and update format.
47+ * @param array $table
48+ * @param mixed $user
49+ *
50+ * @return array
51+ */
52+ private function update ($ table , $ user )
53+ {
54+ $ this ->ratedProduct ($ table , $ user );
55+ foreach ($ this ->product as $ item ){
56+ $ this ->myProduct [$ item [self ::USER_ID ]][$ item [self ::PRODUCT_ID ]] = $ item [self ::SCORE ];
57+ }
58+ foreach ($ this ->other as $ item ){
59+ $ this ->factor [$ item [self ::USER_ID ]][$ item [self ::PRODUCT_ID ]] = $ item [self ::SCORE ];
60+ }
61+ }
62+
63+ /**
64+ * Get calculated items (f(x) = x + b).
65+ * @param array $table
66+ * @param mixed $user
67+ *
68+ * @return array
69+ */
70+ private function calculateItems ($ table , $ user )
71+ {
72+ $ this ->update ($ table , $ user );
73+ $ diff = $ this ->factor ;
74+ $ data = [];
75+ foreach ($ this ->factor as $ key1 => $ item1 ){
76+ foreach ($ item1 as $ key2 => $ value1 ){
77+ foreach ($ diff as $ key3 => $ item2 ){
78+ foreach ($ item2 as $ key4 => $ value2 ){
79+ if (!isset ($ data [$ key2 ][$ key4 ]) && !isset ($ this ->weight [$ key2 ][$ key4 ])){
80+ $ data [$ key2 ][$ key4 ] = 0 ;
81+ $ this ->weight [$ key2 ][$ key4 ] = 0 ;
82+ }
83+ if ($ key1 == $ key3 ){
84+ $ data [$ key2 ][$ key4 ] += ($ value1 - $ value2 );
85+ $ this ->weight [$ key2 ][$ key4 ] += 1 ;
86+ }
87+ }
88+ }
89+ }
90+ }
91+ return $ data ;
92+ }
93+
94+ /**
95+ * Get average difference.
96+ * @param array $table
97+ * @param mixed $user
98+ *
99+ * @return array
100+ */
101+ private function averageDifference ($ table , $ user )
102+ {
103+ $ component = $ this ->calculateItems ($ table , $ user );
104+ $ data = [];
105+ foreach ($ this ->myProduct as $ key1 => $ item1 ){
106+ foreach ($ item1 as $ key2 => $ value1 ){
107+ foreach ($ component as $ key3 => $ item2 ){
108+ foreach ($ item2 as $ key4 => $ value2 ){
109+ if ($ key2 == $ key4 ){
110+ if (!isset ($ data [$ key3 ][$ key4 ]))
111+ $ data [$ key3 ][$ key4 ] = 0 ;
112+ if ($ this ->weight [$ key3 ][$ key4 ] > 0 )
113+ $ data [$ key3 ][$ key4 ] += ($ value2 /$ this ->weight [$ key3 ][$ key4 ])+$ value1 ;
114+ }
115+ }
116+ }
117+ }
118+ }
119+ return $ data ;
120+ }
121+
122+ /**
123+ * Get prediction.
124+ * @param array $table
125+ * @param mixed $user
126+ * @param mixed $score
127+ *
128+ * @return array
129+ */
130+ private function prediction ($ table , $ user , $ score )
131+ {
132+ $ component = $ this ->averageDifference ($ table , $ user );
133+ $ weight = [];
134+ $ data = [];
135+ $ result = [];
136+ foreach ($ component as $ key1 => $ item1 ){
137+ foreach ($ item1 as $ key2 => $ value1 ){
138+ if (!isset ($ weight [$ key1 ]) && !isset ($ data [$ key1 ]) ){
139+ $ weight [$ key1 ] = 0 ;
140+ $ data [$ key1 ] = 0 ;
141+ }
142+ $ weight [$ key1 ] += $ this ->weight [$ key1 ][$ key2 ];
143+ $ data [$ key1 ] += $ value1 * $ this ->weight [$ key1 ][$ key2 ];
144+ }
145+ }
146+
147+ foreach ($ data as $ key1 => $ value ){
148+ $ average = round ($ value /$ weight [$ key1 ],2 );
149+ if ($ average >= $ score )
150+ $ result [$ key1 ] = $ average ;
151+ }
152+ return $ result ;
153+ }
154+
155+ }
0 commit comments