package happy.research.tp; import happy.coding.io.Logs; import happy.coding.math.Sims; import happy.coding.math.Stats; import happy.coding.system.Debug; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; /** * Implementation of our model: ETAF (Extended Trust Antecedents Framework) * * @author guoguibing * */ public class ETAF extends TrustModel { // whether use fixed alpha to combine local and global trust float alpha = 0.5f; // the extent to use ability as a rater float gamma = 0.5f; float eta = 0.5f; // is integrity is enabled boolean isIn = true; int disjoint = 0; public ETAF() { model = "ETAF"; } protected float predict(String u, String v) throws Exception { float lt = local(u, v); float gt = gts.containsKey(v) ? gts.get(v) : 0f; float tp = gls.containsKey(u) ? gls.get(u) : 0f; // trust propensity if (lt == 0 && gt > 0) { disjoint++; //Logs.debug("Number of gt>0, lt==0: {}", disjoint); } return (alpha * lt + (1 - alpha) * gt) * tp; } /** * Evaluate two users' local trustworthiness */ protected float local(String u, String v) throws Exception { float lt = 0.0f; Collection<String> rvs = reviews.get(v); if (rvs.size() == 0) return lt; // user v has not written any reviews float sum = 0.0f; int cnt = 0; Map<String, Float> rts = ratings.row(u); for (String rv : rvs) { if (rts.containsKey(rv)) { sum += rts.get(rv); cnt++; } } // local ability float ab = cnt > 0 ? logic(cnt, 0.1f, 5) * (sum / cnt) : 0f; // local benevolence float be = lns.contains(u, v) ? (lns.get(u, v) - min_lns) / (max_lns - min_lns) : 0f; lt = ab * be; if (lt > 0 && isIn) { // integrity if (Debug.OFF) { Multiset<Float> uVals = HashMultiset.create(rts.values()); Multiset<Float> vVals = HashMultiset.create(ratings.row(v).values()); double dkl = 0; int cnt_k = 0; for (Float val : uVals.elementSet()) { if (vVals.contains(val)) { double pvk = (vVals.count(val) + 0.0) / vVals.size(); double puk = (uVals.count(val) + 0.0) / uVals.size(); cnt_k++; if (pvk > 0 && puk > 0) dkl += Math.log(pvk / puk) * pvk; } } //float in = ins.containsKey(v) ? ins.get(v) : 0f; //in = 1.0f; float in = cnt_k > 0 ? (float) Math.exp(-dkl) : 0f; lt *= in; } else if (Debug.ON) { lt *= 0.5; } } // local trustworthiness return lt; } /** * Evaluate users' global trustworthiness */ protected void global() throws Exception { Logs.debug("Execute global evaluation of trustworthiness ..."); // initialize review qualities for (String rw : rws) rqs.put(rw, 0.0f); // global ability using Digg's algorithm float beta = 0.5f; int iter = 0; while (true) { float err = 0; // compute review's quality for (String rv : rws) { Map<String, Float> rts = ratings.column(rv); if (rts.size() == 0) { // if no one rated this review continue; } // writer String v = reviewUserMap.get(rv); float den = 0.0f, num = 0.0f; int cnt = 0; for (Entry<String, Float> en : rts.entrySet()) { String u = en.getKey(); // rater float rate = en.getValue(); if (!rbs.containsKey(u)) rbs.put(u, (float) Math.random()); // lazy initialization float rb = rbs.get(u); if (!lns.contains(u, v)) lns.put(u, v, (float) Math.random()); float ln = lns.get(u, v); num += rb * rate * (1 - beta * ln); den += rb; cnt++; } float rq = weight(cnt) * (num / den); float rq_last = rqs.get(rv); float e = rq_last - rq; rqs.put(rv, rq); err += e * e; } // update users' rbs for (String u : users) { Map<String, Float> rts = ratings.row(u); if (rts.size() == 0) continue; // if user has rated nothing int n_rates = rts.size(); float w = weight(n_rates); float sum = 0; for (Entry<String, Float> en : rts.entrySet()) { String rv = en.getKey(); float rate = en.getValue(); float diff = rate - rqs.get(rv); sum += Math.abs(diff); } float rb = w * (1 - sum / n_rates); float rb_last = rbs.containsKey(u) ? rbs.get(u) : 0f; float e = rb_last - rb; rbs.put(u, rb); err += e * e; } // update users' lns for (String u : users) { for (String v : users) { if (u.equals(v)) continue; Collection<String> rvs = reviews.get(v); Map<String, Float> rts = ratings.row(u); float sum = 0f; int cnt = 0; for (String rv : rvs) { if (rts.containsKey(rv)) { float rt = rts.get(rv); float rq = rqs.get(rv); sum += (rt - rq) / rt; cnt++; } } if (cnt > 0) { float ln = sum / cnt; float ln_last = lns.get(u, v); lns.put(u, v, ln); float e = ln_last - ln; err += e * e; } } } Logs.debug("Iteration: {}, errors: {}", ++iter, err); // check if converged if (err < 1e-5) break; } // global ability as a writer: wbs for (String u : users) { Collection<String> rvs = reviews.get(u); if (rvs.size() == 0) continue; float sum = 0f; int cnt = rvs.size(); for (String rv : rvs) sum += rqs.get(rv); float wb = weight(cnt) * (sum / cnt); wbs.put(u, wb); } // 4. global benevolence float[] mms = minMax(lns.values()); min_lns = mms[0]; max_lns = mms[1]; // compute gls for (String u : users) { float sum = 0; int cnt = 0; for (String v : users) { if (u.equals(v)) continue; if (lns.contains(u, v)) { float ln = lns.get(u, v); sum += (ln - min_lns) / (max_lns - min_lns); cnt++; } } if (cnt > 0) gls.put(u, sum / cnt); } // compute gbs mms = minMax(gls.values()); float min = mms[0], max = mms[1]; for (Entry<String, Float> en : gls.entrySet()) { String u = en.getKey(); float gl = en.getValue(); float gb = (gl - min) / (max - min); gbs.put(u, gb); } if (Debug.ON) { for (String u : users) { // writer integrity Collection<String> rvs = reviews.get(u); float inw = 0f; if (rvs.size() > 0) { List<Float> qs = new ArrayList<>(); for (String rv : rvs) qs.add(rqs.get(rv)); double mean = Stats.mean(qs); double std = Stats.sd(qs, mean); inw = (float) (weight(rvs.size()) * mean * (1 - std)); } // rater integrity Map<String, Float> rts = ratings.row(u); float inr = 0f; if (rts.size() > 0) { List<Float> us = new ArrayList<>(); List<Float> vs = new ArrayList<>(); for (String rv : rts.keySet()) { if (rqs.containsKey(rv)) { us.add(rts.get(rv)); vs.add(rqs.get(rv)); } } if (us.size() > 1) { double sim = Sims.pcc(us, vs); if (!Double.isNaN(sim)) { float w = weight(us.size()); inr = (float) ((1 + sim) / 2.0); inr *= w; } } } float in = eta * inw + (1 - eta) * inr; if (in > 0) ins.put(u, in); } } else if (Debug.OFF) { // similarity between user's ratings w.r.t the real quality for (String u : users) { Map<String, Float> rts = ratings.row(u); List<Float> us = new ArrayList<>(); List<Float> vs = new ArrayList<>(); for (String rv : rts.keySet()) { if (rqs.containsKey(rv)) { us.add(rts.get(rv)); vs.add(rqs.get(rv)); } } if (us.size() > 1) { double sim = Sims.pcc(us, vs); if (!Double.isNaN(sim)) { float w = weight(us.size()); float in = (float) ((1 + sim) / 2.0); ins.put(u, w * in); } } } } else if (Debug.OFF) { // {review: average-rating} Map<String, Float> rrs = new HashMap<>(); for (String rv : rws) { Map<String, Float> rts = ratings.column(rv); if (rts.size() > 0) { float mean = (float) Stats.mean(rts.values()); rrs.put(rv, mean); } } // similarity between user's ratings w.r.t the majority for (String u : users) { Map<String, Float> rts = ratings.row(u); List<Float> us = new ArrayList<>(); List<Float> vs = new ArrayList<>(); for (String rv : rts.keySet()) { if (rrs.containsKey(rv)) { us.add(rts.get(rv)); vs.add(rrs.get(rv)); } } if (us.size() > 1) { double sim = Sims.pcc(us, vs); if (!Double.isNaN(sim)) { float w = weight(us.size()); float in = (float) ((1 + sim) / 2.0); ins.put(u, w * in); } } } } else if (Debug.OFF) { for (String u : users) { Map<String, Integer> uInters = userRates.row(u);// userInters.row(u); int tu = 0, nu = 0; for (Entry<String, Integer> en : uInters.entrySet()) { int n_inter = en.getValue(); if (n_inter > 0) { tu += n_inter; nu++; } } if (nu == 0) continue; float x = (tu + 0.0f) / nu; float in = logic(x, 0.5f, 5); // try 0.1, 0.5 ins.put(u, in); } } // 6. global trustworthiness for (String u : users) { float ab = (wbs.containsKey(u) ? wbs.get(u) : 0f) * gamma + (rbs.containsKey(u) ? rbs.get(u) : 0f) * (1 - gamma); float be = gbs.containsKey(u) ? gbs.get(u) : 0f; float in = ins.containsKey(u) ? ins.get(u) : 0f; if (!isIn) in = 1.0f; float gt = ab * be * in; if (gt > 0) gts.put(u, gt); } Logs.debug("Done!"); } }