package happy.research.cf;
import happy.coding.system.Debug;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Merge: merge the ratings of trusted neighbours and form a new rating profile for active users
*
* @author guoguibing
*/
public class Merge_mt extends DefaultCF_mt
{
public Merge_mt() throws Exception
{
methodId = "Merge" + params.TRUST_PROPERGATION_LENGTH;
}
@Override
protected Performance runMultiThreads() throws Exception
{
if (Debug.OFF)
{
boolean batchTest = true;
List<String> cases = new ArrayList<>();
if (batchTest)
{
for (int a = 1; a <= 2; a++)
{
for (int b = 1; b <= 2; b++)
{
for (int c = 1; c <= 3; c++)
{
for (int d = 1; d <= 3; d++)
{
String cs = "A" + a + "B" + b + "C" + c + "D" + d;
cases.add(cs);
}
}
}
}
} else
{
// the best pattern
String pattern = "A2B1C3D3";
// String pattern = "A2B2C1D3E3";
cases.add(pattern);
}
for (String cs : cases)
{
printSettings.add("Pattern = " + cs);
if (batchTest) pf = new Performance(methodId);
for (int i = 0; i < ratingArrays.length; i++)
{
threads[i] = new Thread(Merge_t.newMergeCase(i, cs));
threads[i].start();
}
for (Thread tr : threads)
tr.join();
if (batchTest) printPerformance(pf);
}
if (batchTest) pf = null;
return pf;
} else if (Debug.OFF)
{
/**
* considering the similarity of trusted neighbors here is very important to filter out some trusted
* neighbors with low similarity
*/
for (int i = 0; i < ratingArrays.length; i++)
{
threads[i] = new Thread(new Merge_t(i, "A2B1C3D3"));
threads[i].start();
}
for (Thread tr : threads)
tr.join();
return pf;
} else
{
List<Double> alphas = params.readDoubleList("merge.alpha");
List<Double> betas = params.readDoubleList("merge.beta");
double alpha = alphas.get(0);
double beta = betas.get(0);
double lambda = params.readDouble("merge.weight.lambda");
// printSettings.add("merge.num.confidence = " + params.readInt("merge.num.confidence"));
// printSettings.add("merge.infer.trust = " + params.readInt("merge.infer.trust"));
if (params.readParam("merge.params.batch").equalsIgnoreCase("off"))
{
int size = alphas.size();
for (int j = 0; j < size; j++)
{
if (size > 1) pf = new Performance(methodId);
alpha = alphas.get(j);
beta = betas.get(j);
Merge_tj.alpha = alpha;
Merge_tj.beta = beta <= 1 - alpha ? beta : 1 - alpha;
Merge_tj.lambda = lambda;
methodSettings.add("" + (float) alpha);
methodSettings.add("" + (float) beta);
methodSettings.add("" + (float) lambda);
for (int i = 0; i < ratingArrays.length; i++)
{
threads[i] = new Thread(new Merge_tj(i, null));
threads[i].start();
}
for (Thread tr : threads)
tr.join();
if (size > 1) printPerformance(pf);
}
if (size > 1) return null;
else return pf;
} else
{
for (int j = params.readInt("merge.alpha.start"); j <= 10; j++)
{
alpha = j * 0.1;
Merge_tj.alpha = alpha;
for (int k = 0; k <= 10 - j; k++)
{
beta = k * 0.1;
Merge_tj.beta = beta;
Merge_tj.lambda = lambda;
methodSettings.add("" + (float) alpha);
methodSettings.add("" + (float) beta);
methodSettings.add("" + (float) lambda);
pf = new Performance(methodId);
for (int i = 0; i < ratingArrays.length; i++)
{
threads[i] = new Thread(new Merge_tj(i, null));
threads[i].start();
}
for (Thread tr : threads)
tr.join();
printPerformance(pf);
}
}
return null;
}
}
}
/**
* predict user B's rating on test item based on ratings of trusted neighbors
*
* @param testRating
* @param userB
* @return
*/
protected double predictionByTNs(Rating testRating, String userB)
{
String user = testRating.getUserId();
String item = testRating.getItemId();
Map<String, Double> tns = userTNsMap.get(userB);
if (tns == null) return 0.0;
double sum = 0.0;
double weights = 0.0;
for (String tn : tns.keySet())
{
if (tn.equals(user) || tn.equals(userB)) continue;
Map<String, Rating> tnRatings = userRatingsMap.get(tn);
if (tnRatings != null && tnRatings.containsKey(item))
{
sum += tnRatings.get(item).getRating();
weights += 1.0;
}
}
if (weights <= 0.0) return 0.0;
return sum / weights;
}
}