package util;
public class GameRecommender {
/**
* This class is used to recommend games to a specific user based on the rating.
* It is a machine learning system using a specific algorithm called
* collaborative filtering.
*
* There are many algorithms used for recommender systems. I just used a simple one
* called the "maximum likelihood approach". Other algorithms can be used to enhance
* accuracy.
*
* @author Eunsu (Joe) Ryu - jesryu
*
*/
/**
* Parameters
* Double[][] dataset = user-game rating data organized into a matrix (value at i-row, j-th column corresponds to
* User i's rating on Game j).
* numUsers = number of registered users in the system
* numGames = number of registered games in the system
* K = rank parameter. Default is set to 5.
* lambda = precision parameter. Default is set to 1.0.
* numIterations = number of iterations needed to get result. More iterations means more accurate result.
* Default is set to 50.
*
*/
private Double[][] dataset;
private int numUsers;
private int numGames;
private int K;
private double lambda;
private int numIterations;
/**
* Constructor for organized data. Used if the rating data is organized into
* the user-rating matrix
* @param data = dataset
*/
public GameRecommender(Double[][] data, int rows, int cols){
this(data,rows,cols,5,1.0,50);
}
/**
* Constructor for organized data. Used if the rating data is organized into
* the user-rating matrix
* @param data = dataset
*/
public GameRecommender(Double[][] data, int rows, int cols, int kval, double lambdaval, int defaultIterations){
dataset = data;
numUsers = rows;
numGames = cols;
K = kval;
lambda = lambdaval;
numIterations = defaultIterations;
}
/**
* Take the inner product to two vectors with equal dimension. Multiply the corresponding elements
* from the two vectors and add them up.
* @param u, first vector
* @param v, second vector
* @return <u,v>, inner product of the vectors u and v
*/
private Double vectorInnerProduct(double[] u, double[] v) {
double value = 0;
for (int i = 0; i < u.length; i++){
value += u[i]*v[i];
}
return Double.valueOf(value);
}
/**
* Predict rating on Game j by User i. We use maximum likelihood approach.
* Prediction is done by an algorithm called gradient descent.
* @param i, user ID
* @param j, game ID
* @return predicted rating by User i on Game j.
*/
public Double predictRating(int i, int j){
double[][] U = new double[numUsers][K];
double[][] V = new double[numGames][K];
for (int iter = 0; iter < numIterations; iter++){
for (int J = 0; J < numGames; J++) {
for (int k = 0; k < K; k++){
if (dataset[i][J]!=null){
U[i][k] -= -lambda*computeInteremediateGradient(i, J, k, U[i], V[j]);
}
}
}
for (int I = 0; I <numUsers; I++){
for (int k = 0; k < K; k++){
if (dataset[I][j]!=null){
V[j][k] -= -lambda*computeInteremediateGradient(I, j, k, U[I], V[j]);
}
}
}
}
return vectorInnerProduct(U[i], V[j]);
}
/**
* Compute the intermediate gradient for the above predictRating method.
*/
private double computeInteremediateGradient(int i, int j, int k, double[] u, double[] v){
return dataset[i][j] - vectorInnerProduct(u, v)*v[k];
}
}