/** * Iteratively train each feature on the entire data set * Once sufficient progress has been made, move on */ void SvdOrder::calculateFeatures() { qDebug() << "Training"; // Keep looping until you have passed the maximum number // of epochs or have stopped making significant progress double prevRMSE = 1e8; double RMSE = 1e7; Movie movie(currDb); double averageRating = currDb->getAverageRating(); for (unsigned int i = 0; i < MIN_EPOCHS || (i < MAX_EPOCHS && (prevRMSE - RMSE) > MIN_IMPROVEMENT); i++) { prevRMSE = RMSE; RMSE = 0; User user(currDb,6); int numUsers = currDb->totalUsers(); int totalSamples = 0; for (int j = 0; j < numUsers; j++) { for (int k = 0; k < user.votes(); k++) { int movieId = user.movie(k); float rating = user.score(k) - averageRating; int userIndex = j; int movieIndex = movieId - 1; float predict = predictRating(movieIndex, userIndex); float diff = predict - rating; RMSE += diff * diff; // Update all the feature vectors here for (unsigned int l = 0; l < NUM_FEATURES; l++) { float oldUF = userFeatures[userIndex][l]; float oldMF = movieFeatures[movieIndex][l]; userFeatures[userIndex][l] -= LRATE * (diff * oldMF * 2 + REGULARIZE * oldUF); movieFeatures[movieIndex][l] -= LRATE * (diff * oldUF * 2 + REGULARIZE * oldMF); } totalSamples++; } user.next(); } RMSE = sqrt(RMSE / totalSamples); qDebug() << "Epoch" << i + 1 << "RMSE: " << RMSE; } qDebug() << "Done with training"; }
/** * Loop through the entire list of finished features */ double SvdOrder::determine(int user) { int movieIndex = currentMovie - 1; int userIndex = currDb->mapUser(user); return currDb->getAverageRating() + predictRating(movieIndex, userIndex); }