package org.mahout.recommendations.dating;
import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastIDSet;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.EuclideanDistanceSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.IDRescorer;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.apache.mahout.common.iterator.FileLineIterable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static org.apache.mahout.cf.taste.web.RecommenderWrapper.readResourceToTempFile;
/**
* Download dating site ratings from here:
* http://www.occamslab.com/petricek/data/libimseticomplete.zip
*
* @author Krisztian Horvath
*/
public class LibimsetiRecommender implements Recommender {
private final Recommender delegate;
private final DataModel model;
private final FastIDSet men;
private final FastIDSet women;
private final FastIDSet usersRateMoreMen;
private final FastIDSet usersRateLessMen;
public LibimsetiRecommender() throws TasteException, IOException {
this(new FileDataModel(readResourceToTempFile("src/main/resources/ratings.dat")));
}
public LibimsetiRecommender(DataModel model) throws TasteException, IOException {
this.model = model;
UserSimilarity similarity = new EuclideanDistanceSimilarity(model);
UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);
delegate = new GenericUserBasedRecommender(model, neighborhood, similarity);
FastIDSet[] menWomen = parseMenWomen(readResourceToTempFile("src/main/resources/gender.dat"));
men = menWomen[0];
women = menWomen[1];
usersRateMoreMen = new FastIDSet(50000);
usersRateLessMen = new FastIDSet(50000);
}
private FastIDSet[] parseMenWomen(File genderFile) throws IOException {
FastIDSet men = new FastIDSet(50000);
FastIDSet women = new FastIDSet(50000);
for (String line : new FileLineIterable(genderFile)) {
int comma = line.indexOf(',');
char gender = line.charAt(comma + 1);
if (gender == 'U') {
continue;
}
long profileID = Long.parseLong(line.substring(0, comma));
if (gender == 'M') {
men.add(profileID);
} else {
women.add(profileID);
}
}
men.rehash();
women.rehash();
return new FastIDSet[]{men, women};
}
@Override
public List<RecommendedItem> recommend(long userID, int howMany) throws TasteException {
IDRescorer rescorer = new GenderRescorer(men, women, usersRateMoreMen, usersRateLessMen, userID, model);
return delegate.recommend(userID, howMany, rescorer);
}
@Override
public List<RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) throws TasteException {
return delegate.recommend(userID, howMany, rescorer);
}
@Override
public float estimatePreference(long userID, long itemID) throws TasteException {
IDRescorer rescorer = new GenderRescorer(men, women, usersRateMoreMen, usersRateLessMen, userID, model);
return (float) rescorer.rescore(itemID, delegate.estimatePreference(userID, itemID));
}
@Override
public void setPreference(long userID, long itemID, float value) throws TasteException {
delegate.setPreference(userID, itemID, value);
}
@Override
public void removePreference(long userID, long itemID) throws TasteException {
delegate.removePreference(userID, itemID);
}
@Override
public DataModel getDataModel() {
return delegate.getDataModel();
}
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
delegate.refresh(alreadyRefreshed);
}
}