cosine similarity evaluation for whyd
JavaScript
var tags = ["world", "World"];
var maxProportion = 0, minProportion = 1;
var avgProportion = 1 / tags.length; // ideal proportions for 2 tags: {tag1:0.5, tag2:0.5}
var avgProportionSimilDenom = Math.sqrt(Math.pow(avgProportion, 2) * tags.length);
function sum (a, b){
return a + b;
}
function evalProportion(userTagSet) { // cosine similarity with ideal proportion vector
var denomSum = 0;
var numer = tags.map(function(tag){ // sum of (Ai * Bi)
var taggedTracks = (userTagSet[tag] || {}).c || 0;
var tagProportion = taggedTracks / userTagSet._t;
denomSum += Math.pow(tagProportion, 2);
//console.log("tag proportion", tag, tagProportion, " -> denom: ", denomSum);
return tagProportion * avgProportion;
}).reduce(sum);
//console.log("=> user proportion", {numer: numer, 'Math.sqrt(denomSum)':Math.sqrt(denomSum)}, numer / (Math.sqrt(denomSum) * avgProportionSimilDenom));
return !denomSum ? 0 : numer / (Math.sqrt(denomSum) * avgProportionSimilDenom);
}
function evalProportion(userTagSet) {
var error = 0;
var sumWeights = 0;
for (var tag in userTagSet)
if (tag != "_t")
sumWeights += (userTagSet[tag] || {c:0}).c;
return tags.map(function(tag){
var p = (userTagSet[tag] || {c:0}).c / sumWeights;
error += Math.abs(p - avgProportion)
return p;
}).reduce(sum) - error / tags.length;
}
userTagSets =Â [
{ "_t": 40 },
{ "_t": 40, "Jazz":{c:20} },
{ "_t": 40, "World":{c:10} },
{ "_t": 40, "Jazz":{c:10}, "World":{c:20} },
{ "_t": 40, "Jazz":{c:10}, "World":{c:10} },
{ "_t": 40, "Jazz":{c:20}, "World":{c:20} }
];
userTagSets.map(function(userTagSet){
var score = evalProportion(userTagSet);
delete userTagSet._t;
console.log(JSON.stringify(userTagSet), "=>", score);
});