package happy.research.cf; import happy.coding.io.FileIO; import happy.coding.io.FileIO.MapWriter; import happy.coding.io.Logs; import happy.coding.math.Maths; import happy.coding.math.Sims; import happy.coding.math.Stats; import happy.coding.system.Systems; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * This approach is an implementation of our working paper: * * From ratings to trust: an empirical study of implicit trust in recommender systems, ACM SAC, 2013. * * @author guoguibing * */ public class ITrust_mt extends DefaultCF_mt { private String trustMetric; private String trustDir; public ITrust_mt() throws Exception { methodId = "iTrust"; trustMetric = params.readParam("itrust.probe.method"); } @Override protected Performance runMultiThreads() throws Exception { // probe trust from ratings probeITrust(); for (int i = 0; i < ratingArrays.length; i++) { threads[i] = new Thread(new ITrust_t(i)); threads[i].start(); } for (Thread tr : threads) tr.join(); return pf; } /** * Probe implicit trust from user ratings * @throws Exception */ private void probeITrust() throws Exception { trustDir = Dataset.DIRECTORY + trustMetric + "-" + params.TRAIN_SET.substring(0, params.TRAIN_SET.lastIndexOf(".base")) + Systems.FILE_SEPARATOR; if (FileIO.exist(trustDir)) return; else FileIO.makeDirectory(trustDir); switch (trustMetric) { case "TM1": TM1(); break; case "TM2": TM2(); break; case "TM3a": TM3a(); break; case "TM3b": TM3b(); break; case "TM4": TM4(); break; case "TM5": TM5(); break; } } /** * Implementation of the <em>TM1</em> method. * * @throws Exception */ private void TM1() throws Exception { List<Double> recalls = new ArrayList<>(); List<Double> NDCGs = new ArrayList<>(); for (final String u : userRatingsMap.keySet()) { Map<String, Rating> usRatings = userRatingsMap.get(u); if (usRatings == null) { if (userTNsMap.containsKey(u)) recalls.add(0.0); continue; } /* variable for storing u's trusted neighbors */ Map<String, Double> tls = new HashMap<>(); for (String v : userRatingsMap.keySet()) { if (u.equals(v)) continue; Map<String, Rating> vsRatings = userRatingsMap.get(v); if (vsRatings == null) continue; double sum = 0; int count = 0; for (String item : usRatings.keySet()) { if (vsRatings.containsKey(item)) { Rating ur = usRatings.get(item); Rating vr = vsRatings.get(item); double dis = Math.abs(ur.getRating() - vr.getRating()); double val = 1 - dis / Dataset.maxScale; sum += val; count++; } } if (count > 0) { double trust = sum / count; if (trust > 0) tls.put(v, trust); } } saveTrust(u, tls); trustList(recalls, NDCGs, u, tls); } recordResults(recalls, NDCGs); } /* end of TM1() */ /** * record the results by NDCGS and Recalls * * @param recalls * @param NDCGs */ private void recordResults(List<Double> recalls, List<Double> NDCGs) { double NDCG = Stats.mean(NDCGs); double recall = Stats.mean(recalls); Logs.debug("NDCG = {}, recall = {}", NDCG, recall); methodSettings.add(NDCG + ""); methodSettings.add(recall + ""); } /** * Compute the quality of trust list * * @param recalls * @param NDCGs * @param u * @param tls */ private void trustList(List<Double> recalls, List<Double> NDCGs, final String u, Map<String, Double> tls) { Map<String, Double> tns = userTNsMap.get(u); if (tns != null && tns.size() > 0) { int cnt = 0; for (String v : tns.keySet()) { if (tls.containsKey(v)) cnt++; } recalls.add((cnt + 0.0) / tns.size()); /* ranking trust list */ if (tls.size() > 0) { List<Pair> list = new ArrayList<>(); for (Entry<String, Double> en : tls.entrySet()) { Pair p = new Pair(en.getKey(), en.getValue()); list.add(p); } Collections.sort(list); Collections.reverse(list); /* compute NDCG */ double DCG = 0; double iDCG = 0; for (int i = 0; i < tns.size(); i++) iDCG += 1 / Maths.log(i + 2, 2); for (int i = 0; i < list.size(); i++) { String item = list.get(i).left; if (!tns.containsKey(item)) continue; int rank = i + 1; DCG += 1 / Maths.log(rank + 1, 2); } NDCGs.add(DCG / iDCG); } } } /** * save the computed implicit trust to disk * * @param u active user u * @param tns u's trusted neighbors * @throws Exception */ private void saveTrust(final String u, Map<String, Double> tns) throws Exception { if (tns.size() > 0) { String trustFile = trustDir + u + ".txt"; FileIO.writeMap(trustFile, tns, new MapWriter<String, Double>() { @Override public String processEntry(String key, Double val) { return key + " " + val; } }, false); } } /** * Implementation of the <em>TM2</em> method. * * @throws Exception */ private void TM2() throws Exception { List<Double> recalls = new ArrayList<>(); List<Double> NDCGs = new ArrayList<>(); int thetaI = 2; double thetaS = 0.707; for (final String u : userRatingsMap.keySet()) { Map<String, Rating> usRatings = userRatingsMap.get(u); if (usRatings == null) { if (userTNsMap.containsKey(u)) recalls.add(0.0); continue; } /* variable for storing u's trusted neighbors */ Map<String, Double> tls = new HashMap<>(); for (String v : userRatingsMap.keySet()) { if (u.equals(v)) continue; Map<String, Rating> vsRatings = userRatingsMap.get(v); if (vsRatings == null) continue; List<Double> us = new ArrayList<>(); List<Double> vs = new ArrayList<>(); for (String item : usRatings.keySet()) { if (vsRatings.containsKey(item)) { Rating ur = usRatings.get(item); Rating vr = vsRatings.get(item); us.add(ur.getRating()); vs.add(vr.getRating()); } } int size = us.size(); if (size < 2) continue; if (size <= thetaI) continue; double pcc = Sims.pcc(us, vs); if (Double.isNaN(pcc)) continue; if (pcc > thetaS) { double trust = pcc; if (trust > 0) tls.put(v, trust); } } saveTrust(u, tls); trustList(recalls, NDCGs, u, tls); } recordResults(recalls, NDCGs); } /* end of TM2() */ /** * Implementation of the <em>TM3a</em> method. * * @throws Exception */ private void TM3a() throws Exception { List<Double> recalls = new ArrayList<>(); List<Double> NDCGs = new ArrayList<>(); for (final String u : userRatingsMap.keySet()) { Map<String, Rating> usRatings = userRatingsMap.get(u); if (usRatings == null) { if (userTNsMap.containsKey(u)) recalls.add(0.0); continue; } double meanU = RatingUtils.mean(usRatings, null); /* variable for storing u's trusted neighbors */ Map<String, Double> tls = new HashMap<>(); for (String v : userRatingsMap.keySet()) { if (u.equals(v)) continue; Map<String, Rating> vsRatings = userRatingsMap.get(v); if (vsRatings == null) continue; double meanV = RatingUtils.mean(vsRatings, null); double sum = 0; int count = 0; for (String item : usRatings.keySet()) { if (vsRatings.containsKey(item)) { Rating ur = usRatings.get(item); Rating vr = vsRatings.get(item); double pred = meanU + vr.getRating() - meanV; double dist = pred - ur.getRating(); double val = 1 - dist / Dataset.maxScale; sum += val; count++; } } if (count > 0) { double trust = sum / count; if (trust > 0) tls.put(v, trust); } } saveTrust(u, tls); trustList(recalls, NDCGs, u, tls); } recordResults(recalls, NDCGs); } /* end of TM3a() */ /** * Implementation of the <em>TM3b</em> method. * * @throws Exception */ private void TM3b() throws Exception { List<Double> recalls = new ArrayList<>(); List<Double> NDCGs = new ArrayList<>(); double lambda = 0.05; for (final String u : userRatingsMap.keySet()) { Map<String, Rating> usRatings = userRatingsMap.get(u); if (usRatings == null) { if (userTNsMap.containsKey(u)) recalls.add(0.0); continue; } double meanU = RatingUtils.mean(usRatings, null); int sizeU = usRatings.size(); /* variable for storing u's trusted neighbors */ Map<String, Double> tls = new HashMap<>(); for (String v : userRatingsMap.keySet()) { if (u.equals(v)) continue; Map<String, Rating> vsRatings = userRatingsMap.get(v); if (vsRatings == null) continue; int sizeV = vsRatings.size(); double meanV = RatingUtils.mean(vsRatings, null); double sum = 0; int count = 0; for (String item : usRatings.keySet()) { if (vsRatings.containsKey(item)) { Rating ur = usRatings.get(item); Rating vr = vsRatings.get(item); double pred = meanU + vr.getRating() - meanV; double dist = pred - ur.getRating(); double val = Math.pow(dist / Dataset.maxScale, 2); sum += val; count++; } } if (count > 0) { double trust = 1 - sum / count; double factor = (count + 0.0) / (sizeU + sizeV - count); trust *= factor; if (trust > lambda) tls.put(v, trust); } } saveTrust(u, tls); trustList(recalls, NDCGs, u, tls); } recordResults(recalls, NDCGs); } /* end of TM3b() */ /** * Implementation of the <em>TM5</em> method. * * @throws Exception */ private void TM5() throws Exception { List<Double> recalls = new ArrayList<>(); List<Double> NDCGs = new ArrayList<>(); for (final String u : userRatingsMap.keySet()) { Map<String, Rating> usRatings = userRatingsMap.get(u); if (usRatings == null) { if (userTNsMap.containsKey(u)) recalls.add(0.0); continue; } double meanU = RatingUtils.mean(usRatings, null); /* variable for storing u's trusted neighbors */ Map<String, Double> tls = new HashMap<>(); for (String v : userRatingsMap.keySet()) { if (u.equals(v)) continue; Map<String, Rating> vsRatings = userRatingsMap.get(v); if (vsRatings == null) continue; double meanV = RatingUtils.mean(vsRatings, null); double sum = 0; int count = 0; List<Double> us = new ArrayList<>(); List<Double> vs = new ArrayList<>(); for (String item : usRatings.keySet()) { if (vsRatings.containsKey(item)) { Rating ur = usRatings.get(item); Rating vr = vsRatings.get(item); double pred = meanU + vr.getRating() - meanV; double dist = Math.abs(pred - ur.getRating()); double val = dist / Dataset.maxScale; sum += val; count++; us.add(ur.getRating()); vs.add(vr.getRating()); } } if (count > 0) { double uncertainty = sum / count; if (count < 2) continue; double pcc = Sims.pcc(us, vs); if (Double.isNaN(pcc)) continue; double belief = 0.5 * (1 - uncertainty) * (1 + pcc); double trust = belief; if (trust > 0) tls.put(v, trust); } } saveTrust(u, tls); trustList(recalls, NDCGs, u, tls); } recordResults(recalls, NDCGs); } /* end of TM5() */ /** * Implementation of the <em>TM4</em> method. * * @throws Exception */ private void TM4() throws Exception { double epsilon = 0.0; switch (Dataset.dataset) { case FILMTRUST: epsilon = 0.8; break; case EPINIONS: epsilon = params.readDouble("itrust.tm4.epsilon"); break; default: epsilon = 1.0; break; } List<Double> recalls = new ArrayList<>(); List<Double> NDCGs = new ArrayList<>(); for (final String u : userRatingsMap.keySet()) { Map<String, Rating> usRatings = userRatingsMap.get(u); if (usRatings == null) { if (userTNsMap.containsKey(u)) recalls.add(0.0); continue; } double meanU = RatingUtils.mean(usRatings, null); /* variable for storing u's trusted neighbors */ Map<String, Double> tls = new HashMap<>(); for (String v : userRatingsMap.keySet()) { if (u.equals(v)) continue; Map<String, Rating> vsRatings = userRatingsMap.get(v); if (vsRatings == null) continue; double meanV = RatingUtils.mean(vsRatings, null); int correct = 0; int involve = 0; for (String item : usRatings.keySet()) { if (vsRatings.containsKey(item)) { Rating ur = usRatings.get(item); Rating vr = vsRatings.get(item); double pred = meanU + vr.getRating() - meanV; double dist = Math.abs(pred - ur.getRating()); if (dist <= epsilon) correct++; involve++; } } if (involve > 0) { double trust = (correct + 0.0) / involve; if (trust > 0) tls.put(v, trust); } } saveTrust(u, tls); trustList(recalls, NDCGs, u, tls); } recordResults(recalls, NDCGs); } /* end of TM4() */ }