import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Scanner;
public class ItemBasedRecommendationSystem {
private User[] movies;
private int UserName;
public int Users = 200;
private int Movies = 1000;
private int m = 30;
private double[] similarity;
private double[][] ratings;
private int[] topA;
private Hashtable<Integer, Integer> needToBeWritten;
private Hashtable<Double,Double> negativeValues;
private double[] averageOfUser;
private double UserAverage;
private double[]User;
public ItemBasedRecommendationSystem() throws FileNotFoundException {
similarity = new double[Movies];
ratings = new double[Users][Movies];
topA = new int[m];
Scanner s = new Scanner(new BufferedReader(new FileReader(new File("train.txt"))));
for (int i = 0; i < Users; i++) {
for (int j = 0; j < Movies; j++) {
ratings[i][j] = s.nextInt();
}
}
findUserAverages();
}
public int loadNextUser(double[] User, Scanner s) {
int name = UserName;
while (name == UserName) {
try {
User[s.nextInt() - 1] = s.nextInt();
if (s.hasNext()) {
name = s.nextInt() - 1;
}
} catch (Exception e) {
break;
}
}
return name;
}
private void findUserAverages() {
averageOfUser = new double[Users];
for (int i = 0; i < Users; i++) {
double sum = 0, count = 0;
for (int j = 0; j < Movies; j++) {
if (ratings[i][j] != 0) {
sum += ratings[i][j];
count++;
}
}
averageOfUser[i] = sum / count;
}
}
private double findAverage(double[] User) {
double sum = 0, count = 0;
for (int i = 0; i < User.length; i++) {
if (User[i] >= 1) {
sum += User[i];
count++;
}
}
return sum / count;
}
public void predictItemBasedSimilarity(String input, String output) throws FileNotFoundException, IOException {
Scanner s = new Scanner(new BufferedReader(new FileReader(new File(input))));
PrintStream fout = new PrintStream(new File(output));
UserName = s.nextInt() - 1;
while (s.hasNext()) {
needToBeWritten = new Hashtable<Integer, Integer>();
User = new double[Movies];
Arrays.fill(User, -1);
int nextUser = loadNextUser(User, s);
for (int movie = 0; movie < User.length; movie++) {
if (User[movie] == 0) {
UserAverage = findAverage(User);
findSimilarMoviesTo(movie);
findTopANearestFor();
needToBeWritten.put(movie, 1);
double prediction=predict();
double rounded=Math.round(prediction);
double adjusted=adjust(rounded);
System.out.println(UserName+" "+movie+" "+prediction+" "+rounded+" "+adjusted);
User[movie] = adjusted;
}
}
write(UserName, User, fout);
UserName = nextUser;
}
fout.flush();
fout.close();
}
private int adjust(double d) {
if (d > 5) {
return 5;
} else if (d <= 0) {
int temp=(int)(d+5);
if(temp>5)
return 5;
else if (temp==0)
return 1;
else return temp;
} else {
return (int)d;
}
}
private void findTopANearestFor() {
int j = 0;
for (int i = Movies - 1; j < m && i >= 0; i--) {
int movie = movies[i].name;
if(User[movie]>0){
topA[j] = movies[i].name;
j++;
}
}
for (int j=0; j < m; j++) {
topA[j] = -1;
}
}
private void sortUsers() {
movies = new User[Movies];
for (int i = 0; i < Movies; i++) {
movies[i] = new User(Math.abs(similarity[i]), i);
}
Arrays.sort(movies, User.BySimilarity);
}
private void findSimilarMoviesTo(int predictForMovie) {
for (int movie = 0; movie < Movies; movie++) {
if (movie == predictForMovie) {
continue;
}
double movieMean=findMeanFor(movie);
double predictForMovieMean=findMeanFor(predictForMovie);
double innerProduct = 0;
double lengthOfUser = 1;
double lengthofUser = 1;
for (int user = 0; user < Users; user++) {
if (ratings[user][movie] > 0 && ratings[user][predictForMovie] > 0) {
innerProduct += (ratings[user][movie] -averageOfUser[user]) * (ratings[user][predictForMovie] - averageOfUser[user]);
lengthOfUser += Math.pow((ratings[user][movie] - averageOfUser[user]), 2);
lengthofUser += Math.pow((ratings[user][predictForMovie] - averageOfUser[user]), 2);
}
}
similarity[movie] = innerProduct / (Math.sqrt(lengthOfUser) * Math.sqrt(lengthofUser));
}
sortUsers();
}
private void write(int UserName, double[] User, PrintStream fout) {
for (int movie = 0; movie < User.length; movie++) {
if (User[movie] != -1 && needToBeWritten.get(movie) != null) {
fout.println((UserName + 1) + " " + (movie + 1) + " " + (int)(Math.round(User[movie])));
}
}
}
private int findMeanFor(int movie){
double sum=0,count=0;
for(int user=0;user<Users;user++){
if(ratings[user][movie]>0){
sum+=ratings[user][movie];
count++;
}
}
return (int)Math.round(sum/count);
}
private double predict() {
int j = 0;
double numerator = 0;
double denominator = 0;
for (int i = 0; i < m && topA[i] != -1; i++) {
int movie = topA[i];
if(User[movie]>0){
numerator += similarity[movie] * (User[movie]);
denominator += Math.abs(similarity[movie]);
}
}
return (numerator / denominator);
}
public static void main(String args[]) throws FileNotFoundException, IOException {
ItemBasedRecommendationSystem r = new ItemBasedRecommen