Last active
January 21, 2016 02:05
-
-
Save sudipto80/7d750a446de3ff1f7f53 to your computer and use it in GitHub Desktop.
User User Collaborative Filtering 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Average rating for all other rated items by the user | |
//except the item "except" | |
let rBaru(u:float list)(except:int)= | |
let filtered = u |> List.mapi(fun i j -> if i <> except then j else 0.0) | |
|> List.filter(fun t -> t <> 0.0) | |
float ( List.sum filtered ) / float filtered.Length | |
//The following function finds the common item indices | |
let commonItemIndices (ratings:(float list)list)(a:int)(u:int)= | |
List.zip ratings.[a] ratings.[u] | |
|> List.mapi (fun index rating -> | |
if fst rating <> 0.0 | |
&& snd rating <> 0.0 then index else -1 ) | |
|> List.filter ( fun index -> index <> -1) | |
//The following function returns the average of user a and u | |
let mu_au (ratings:(float list)list)(a:int)(u:int)= | |
let com = commonItemIndices ratings a u | |
let mu_a = com |> List.map (fun index -> ratings.[a].[index]) |> List.average | |
let mu_u = com |> List.map (fun index -> ratings.[u].[index]) |> List.average | |
(mu_a,mu_u) | |
//Calculates User-User similarity using Pearson's Correlation Coefficient | |
let Simu (ratings:(float list)list) (a:int)(u:int)= | |
//Indices of the items rated by both user a and u | |
let common = commonItemIndices ratings a u | |
let averages = mu_au ratings a u | |
let ra = fst averages | |
let ru = snd averages | |
let num = common |> List.sumBy (fun index -> (ratings.[a].[index] - ra)* | |
(ratings.[u].[index] - ru)) | |
let d1 = common |> List.sumBy (fun index -> (ratings.[a].[index] - ra)** 2.0) | |
let d2 = common |> List.sumBy (fun index -> (ratings.[u].[index] - ru)** 2.0) | |
//If either d1 or d2 is 0 then we shall hit a divide by zero case | |
//to avoid that we must return 0. | |
if d1 = 0.0 || d2 = 0.0 then 0.0 else num / ((sqrt d1) * (sqrt d2 )) | |
//User-User Basic Collaborative Filtering - basic | |
let Predictu(ratings:(float list)list)(a:int)(i:int) = | |
let rb = rBaru ratings.[a] i | |
let neighborIndices = ratings | |
|> List.mapi(fun index rating -> | |
if rating.[i] <> 0.0 then index else -1) | |
|> List.filter(fun index -> index <> -1) | |
//Rating of neighbors are obtained | |
let neighbors = neighborIndices | |
|> List.map (fun index -> ratings.[index]) | |
let gaps = neighbors |> List.map (fun neighbor -> neighbor.[i] - (rBaru neighbor i)) | |
let simis = neighborIndices |> List.map (fun index -> Simu ratings a index) | |
let num = List.zip gaps simis |> List.sumBy (fun t -> fst t * snd t) | |
let den = simis |> List.sumBy (fun similarity -> abs similarity) | |
if den <> 0.0 then | |
let div = num / den | |
let predicted = rb + div | |
//Sometimes the value of "predicted" can be beyond the range. [1-5] | |
//so having a 7 is same as 5.0 in practice (meaning the user might love the item) | |
//so is having a -1 which is same as 1 (meaning the user might hate the item) | |
if predicted > 5.0 then 5.0 elif predicted < 1.0 then 1.0 else predicted | |
else | |
0.0 //We don't know what it is. | |
//Calculates the standard deviation | |
let stddev(list:float list)= | |
sqrt (List.fold (fun acc elem -> acc + (float elem - List.average list) ** 2.0 ) 0.0 | |
list / float list.Length) | |
//Calculates the z-score | |
let zscore (ratings:(float list)list)(userIndex:int)(itemIndex:int)= | |
let rBar = rBaru ratings.[userIndex] itemIndex | |
let sigma = stddev ratings.[userIndex] | |
ratings.[userIndex].[itemIndex] - rBar / sigma | |
let PredictuZ(ratings:(float list)list)(a:int)(i:int) = | |
let rb = rBaru ratings.[a] i | |
let neighborIndices = ratings | |
|> List.mapi(fun index rating -> | |
if rating.[i] <> 0.0 | |
then index else -1) | |
|> List.filter(fun index -> index <> -1) | |
let neighbors = neighborIndices|> List.map (fun index -> ratings.[index]) | |
//This line is changed to use Z-Score instead of just the differences. | |
let gaps = neighbors |> List.map (fun neighbor -> zscore ratings a i) | |
let simis = neighborIndices |> List.map (fun index -> Simu ratings a index) | |
let num = List.zip gaps simis |> List.sumBy (fun t -> fst t * snd t) | |
let den = simis |> List.sumBy (fun t -> abs t) | |
if den <> 0.0 then | |
let div = num / den | |
let predicted = rb + div * stddev ratings.[a] | |
//Sometimes the value can be beyond the range. | |
//so having a 7 is same as 5.0 in practice | |
//so is having a -1 which is same as zero | |
if predicted > 5.0 then 5.0 elif predicted < 1.0 then 1.0 else predicted | |
else | |
0.0 //Else we don't know | |
//The above rating matrix is represented as (float list)list in F# | |
let ratings = [[4.;0.;5.;5.];[4.;2.;1.;0.];[3.;0.;2.;4.];[4.;4.;0.;0.];[2.;1.;3.;5.]] | |
//Finding the predicted rating for user 1 for item 2 | |
let p12 = Predictu ratings 0 1 //3.95 roughly | |
let p12Z = PredictuZ ratings 0 1 //5.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment