UNPKG

@cagataycali/collaborative-filtering

Version:
151 lines (120 loc) 4.2 kB
module.exports = function () { let app = this; let trained = {}; app.maxRelatedUser = 0; app.maxRelatedItem = 0; // dataset, user col, item col, value app.train = (data, x, y, val) => { if (!x) x = 0; if (!y) y = 1; if (!val) val = 2; let userBase = {}, itemBase = {}, itemRank = {}; for (let i = 0; i < data.length; i++) { let userId = data[i][x]; let itemId = data[i][y]; let feature = data[i][val] * 1; if (!userBase[userId]) userBase[userId] = []; userBase[userId].push({ itemId: itemId, feature: feature }); if (!itemBase[itemId]) itemBase[itemId] = []; itemBase[itemId].push({ userId: userId, feature: feature }); if (!itemRank[itemId]) itemRank[itemId] = 0; itemRank[itemId] += feature; } let ranking = []; for (let itemId in itemRank) ranking.push({ itemId: itemId, play: itemRank[itemId] }); ranking.sort((a, b) => b.play - a.play); trained.userBase = userBase; trained.itemBase = itemBase; trained.ranking = ranking; }; app.getModel = () => trained; app.setModel = (model) => (trained = model); app.recommendByArray = (listenList, count) => { let alreadyIn = {}; let similarUsers = {}; for (let i = 0; i < listenList.length; i++) { alreadyIn[listenList[i].itemId] = true; let similarUserList = trained.itemBase[listenList[i].itemId]; for (let j = 0; j < similarUserList.length; j++) { if (!similarUsers[similarUserList[j].userId]) similarUsers[similarUserList[j].userId] = 0; similarUsers[similarUserList[j].userId] += similarUserList[j].feature * listenList[i].feature; } } let relatedUsers = []; for (let userId in similarUsers) relatedUsers.push({ id: userId, score: similarUsers[userId] }); relatedUsers.sort((a, b) => b.score - a.score); let playlist = {}; let playlistCount = 0; for (let i = 0; i < relatedUsers.length; i++) { if (app.maxRelatedUser !== 0 && i > app.maxRelatedUser) break; let userId = relatedUsers[i].id; let userScore = relatedUsers[i].score; let userList = trained.userBase[userId]; for (let j = 0; j < userList.length; j++) { if (alreadyIn[userList[j].itemId]) continue; if (app.maxRelatedItem !== 0 && j > app.maxRelatedItem) break; if (!playlist[userList[j].itemId]) { playlist[userList[j].itemId] = 0; playlistCount++; } playlist[userList[j].itemId] += userScore; } } let result = []; for (let itemId in playlist) result.push({ itemId: itemId, score: Math.round(Math.log(playlist[itemId] + 1) * 100) / 100, }); result.sort((a, b) => b.score - a.score); result.splice(count); for (let i = 0; i < trained.ranking.length; i++) { if (result.length >= count) break; if (!playlist[trained.ranking[i].itemId]) result.push(trained.ranking[i]); } return result; }; app.recommendToUser = (userId, count) => { let userList = trained.userBase[userId]; if (userList) return app.recommendByArray(userList, count); else return JSON.parse(JSON.stringify(trained.ranking)).splice(0, count); }; app.recommendToUsers = (userIds, count, process) => { let result = {}; for (let i = 0; i < userIds.length; i++) { result[userIds[i]] = app.recommendToUser(userIds[i], count); if (process) process(i + 1); } return result; }; app.recommendGT = (gt, count, process) => { let result = {}, cnt = 0; for (let userId in gt) { result[userId] = app.recommendToUser(userId, count); if (process) process(++cnt); } return result; }; app.gt = (data, x, y, val) => { if (!x) x = 0; if (!y) y = 1; if (!val) val = 2; let userBase = {}; for (let i = 0; i < data.length; i++) { let userId = data[i][x]; let itemId = data[i][y]; let feature = data[i][val] * 1; if (!userBase[userId]) userBase[userId] = []; userBase[userId].push({ itemId: itemId, feature: feature }); } return userBase; }; return app; };