@Override protected void buildModel() throws Exception { for (int iter = 1; iter <= numIters; iter++) { loss = 0; errs = 0; for (int s = 0, smax = numUsers * 100; s < smax; s++) { // randomly draw (u, i, j) int u = 0, i = 0, j = 0; while (true) { u = Randoms.uniform(numUsers); SparseVector pu = userCache.get(u); if (pu.getCount() == 0) continue; int[] is = pu.getIndex(); i = is[Randoms.uniform(is.length)]; do { j = Randoms.uniform(numItems); } while (pu.contains(j)); break; } // update parameters double xui = predict(u, i); double xuj = predict(u, j); double xuij = xui - xuj; double vals = -Math.log(g(xuij)); loss += vals; errs += vals; double cmg = g(-xuij); for (int f = 0; f < numFactors; f++) { double puf = P.get(u, f); double qif = Q.get(i, f); double qjf = Q.get(j, f); P.add(u, f, lRate * (cmg * (qif - qjf) - regU * puf)); Q.add(i, f, lRate * (cmg * puf - regI * qif)); Q.add(j, f, lRate * (cmg * (-puf) - regI * qjf)); loss += regU * puf * puf + regI * qif * qif + regI * qjf * qjf; } } if (isConverged(iter)) break; } }
/** * Split ratings into k-fold. * * @param kfold number of folds */ private void splitFolds(int kfold) { assert kfold > 0; assignMatrix = new SparseMatrix(rateMatrix); int numRates = rateMatrix.getData().length; numFold = kfold > numRates ? numRates : kfold; // divide rating data into kfold sample of equal size double[] rdm = new double[numRates]; int[] fold = new int[numRates]; double indvCount = (numRates + 0.0) / numFold; for (int i = 0; i < numRates; i++) { rdm[i] = Randoms.uniform(); // Math.random(); fold[i] = (int) (i / indvCount) + 1; // make sure that each fold has each size sample } Sortor.quickSort(rdm, fold, 0, numRates - 1, true); int[] row_ptr = rateMatrix.getRowPointers(); int[] col_idx = rateMatrix.getColumnIndices(); int f = 0; for (int u = 0, um = rateMatrix.numRows(); u < um; u++) { for (int idx = row_ptr[u], end = row_ptr[u + 1]; idx < end; idx++) { int j = col_idx[idx]; // if randomly put an int 1-5 to entry (u, j), we cannot make sure equal size for each fold assignMatrix.set(u, j, fold[f++]); } } }