Example #1
0
        ///
        public virtual void Iterate()
        {
            if (num_learned_factors >= NumFactors)
            {
                return;
            }

            // compute residuals
            for (int index = 0; index < Ratings.Count; index++)
            {
                int u = Ratings.Users[index];
                int i = Ratings.Items[index];
                residuals[index] = Ratings[index] - Predict(u, i);
                int n_ui = Math.Min(Ratings.ByUser[u].Count, Ratings.ByItem[i].Count);                 // TODO use less memory
                residuals[index] *= n_ui / (n_ui + Shrinkage);
            }

            // initialize new latent factors
            MatrixUtils.ColumnInitNormal(user_factors, InitMean, InitStdev, num_learned_factors);
            MatrixUtils.ColumnInitNormal(item_factors, InitMean, InitStdev, num_learned_factors);             // TODO make configurable?

            // compute the next factor by solving many least squares problems with one variable each
            double err     = double.MaxValue / 2;
            double err_old = double.MaxValue;

            while (err / err_old < 1 - Sensibility)
            {
                {
                    // TODO create only once?
                    var user_factors_update_numerator   = new double[MaxUserID + 1];
                    var user_factors_update_denominator = new double[MaxUserID + 1];

                    // compute updates in one pass over the data
                    for (int index = 0; index < Ratings.Count; index++)
                    {
                        int u = Ratings.Users[index];
                        int i = Ratings.Items[index];

                        user_factors_update_numerator[u]   += residuals[index] * item_factors[i, num_learned_factors];
                        user_factors_update_denominator[u] += item_factors[i, num_learned_factors] * item_factors[i, num_learned_factors];
                    }

                    // update user factors
                    for (int u = 0; u <= MaxUserID; u++)
                    {
                        if (user_factors_update_numerator[u] != 0)
                        {
                            user_factors[u, num_learned_factors] = user_factors_update_numerator[u] / user_factors_update_denominator[u];
                        }
                    }
                }

                {
                    var item_factors_update_numerator   = new double[MaxItemID + 1];
                    var item_factors_update_denominator = new double[MaxItemID + 1];

                    // compute updates in one pass over the data
                    for (int index = 0; index < Ratings.Count; index++)
                    {
                        int u = Ratings.Users[index];
                        int i = Ratings.Items[index];

                        item_factors_update_numerator[i]   += residuals[index] * user_factors[u, num_learned_factors];
                        item_factors_update_denominator[i] += user_factors[u, num_learned_factors] * user_factors[u, num_learned_factors];
                    }

                    // update item factors
                    for (int i = 0; i <= MaxItemID; i++)
                    {
                        if (item_factors_update_numerator[i] != 0)
                        {
                            item_factors[i, num_learned_factors] = item_factors_update_numerator[i] / item_factors_update_denominator[i];
                        }
                    }
                }

                err_old = err;
                err     = ComputeFit();
            }

            num_learned_factors++;
        }