day54

本文介绍了名为 MBR 的电影推荐系统,它使用基于 leave-one-out 的方法进行预测,通过计算用户和物品的平均评级以及确定用户邻域来实现个性化推荐。核心内容包括构建rating矩阵、设置用户邻域半径、预测评分以及计算MAE和RSME。
摘要由CSDN通过智能技术生成
package machinelearning.knn;

/**
 * ******************************************
 *
 * @author Michelle Min MitchelleMin@163.com
 * @date 2021-07-14
 * ******************************************
 */

import java.io.*;

public class MBR {

    /*
    Default rating for 1-5 points.
     */
    public static final double DEFAULT_RATING = 3.0;

    /*
    The total number of users.
     */
    private int numUsers;

    /*
    The total numbers of items.
     */
    private int numItems;

    /*
    The total number of ratings (non-zero values)
     */
    private int numRatings;

    /*
    The predictions.
     */
    private double[] predictions;

    /*
    Compressed rating matrix. User-item-rating triples.
     */
    private  int[][] compressedRatingMatrix;

    /*
    The degree of users (how many item he has rated).
     */
    private int[] userDegrees;

    /*
    The average rating of the current user.
     */
    private double[] userAverageRatings;

    /*
    The degree of users (how many item he has rated).
     */
    private int[] itemDegrees;

    /*
    The average rating of the current item.
     */
    private double[] itemAverageRatings;

    /*
    The first user start for 0. Let the first user has x ratings, the second
    user will start for x.
     */
    private int[] userStartingIndices;

    /*
    Number of non-neighbors objects.
     */
    private int numNonNeighbors;

    /*
    The radius (delta) for determining the neighborhood.
     */
    private double radius;

    /**
     *************************
     * Construct the rating matrix.
     *
     * @param paraFilename
     *            the rating filename.
     * @param paraNumUsers
     *            number of users
     * @param paraNumItems
     *            number of items
     * @param paraNumRatings
     *            number of ratings
     *************************
     */
    public MBR(String paraFilename, int paraNumUsers, int paraNumItems, int paraNumRatings) throws Exception {
        // Step 1. Initialize these arrays
        numItems = paraNumItems;
        numUsers = paraNumUsers;
        numRatings = paraNumRatings;

        userDegrees = new int[numUsers];
        userStartingIndices = new int[numUsers + 1];
        userAverageRatings = new double[numUsers];
        itemDegrees = new int[numItems];
        compressedRatingMatrix = new int[numRatings][3];
        itemAverageRatings = new double[numItems];

        predictions = new double[numRatings];

        System.out.println("Reading " + paraFilename);

        // Step 2. Read the data file.
        File tempFile = new File(paraFilename);
        if (!tempFile.exists()) {
            System.out.println("File " + paraFilename + " does not exists.");
            System.exit(0);
        } //of if
        BufferedReader tempBufReader = new BufferedReader(new FileReader(tempFile));
        String tempString;
        String[] tempStrArray;
        int tempIndex = 0;
        userStartingIndices[0] = 0;
        userStartingIndices[numUsers] = numRatings;
        while ((tempString = tempBufReader.readLine()) != null) {
            // Each line has three values
            tempStrArray = tempString.split(",");
            compressedRatingMatrix[tempIndex][0] = Integer.parseInt(tempStrArray[0]);
            compressedRatingMatrix[tempIndex][1] = Integer.parseInt(tempStrArray[1]);
            compressedRatingMatrix[tempIndex][2] = Integer.parseInt(tempStrArray[2]);

            userDegrees[compressedRatingMatrix[tempIndex][0]]++;
            itemDegrees[compressedRatingMatrix[tempIndex][1]]++;

            if (tempIndex > 0) {
                // Starting to read the data of a new user.
                if (compressedRatingMatrix[tempIndex][0] != compressedRatingMatrix[tempIndex - 1][0]) {
                    userStartingIndices[compressedRatingMatrix[tempIndex][0]] = tempIndex;
                } //of if
            } //of if
            tempIndex++;
        } //of while
        tempBufReader.close();

        double[] tempUserTotalScore = new double[numUsers];
        double[] tempItemTotalScore = new double[numItems];
        for (int i = 0; i < numRatings; i++) {
            tempUserTotalScore[compressedRatingMatrix[i][0]] += compressedRatingMatrix[i][2];
            tempItemTotalScore[compressedRatingMatrix[i][1]] += compressedRatingMatrix[i][2];
        } //of for i

        for (int i = 0; i < numUsers; i++) {
            userAverageRatings[i] = tempUserTotalScore[i] / userDegrees[i];
        } //of for i
        for (int i = 0; i < numItems; i++) {
            itemAverageRatings[i] = tempItemTotalScore[i] / itemDegrees[i];
        } //of for i
    }//of the first constructor

    /**
     *************************
     * Set the radius (delta).
     *
     * @param paraRadius
     *            The given radius.
     *************************
     */
    public void setRadius(double paraRadius) {
        if (paraRadius > 0) {
            radius = paraRadius;
        } else {
            radius = 0.1;
        }//of if
    }//of setRadius

    /**
     *************************
     * Leave-one-out prediction. The predicted values are stored in predictions.
     *************************
     */
    public void leaveOneOutPrediction() {
        double tempItemAverageRating;
        // Make each line of the code shorter.
        int tempUser, tempItem, tempRating;
        System.out.println("\r\nLeaveOneOutPrediction for radius " + radius);

        numNonNeighbors = 0;
        for (int i = 0; i < numRatings; i++) {
            tempUser = compressedRatingMatrix[i][0];
            tempItem = compressedRatingMatrix[i][1];
            tempRating = compressedRatingMatrix[i][2];

            // Step 1. Recompute average rating of the current item.
            tempItemAverageRating = (itemAverageRatings[tempItem] * itemDegrees[tempItem] - tempRating)
                    / (itemDegrees[tempItem] - 1);

            // Step 2. Recompute neighbors, at the same time obtain the ratings
            //Neighbors.
            int tempNeighbors = 0;
            double tempTotal = 0;
            int tempComparedItem;
            for (int j = userStartingIndices[tempUser]; j < userStartingIndices[tempUser + 1]; j++) {
                tempComparedItem = compressedRatingMatrix[j][1];
                if (tempItem == tempComparedItem) {
                    continue;
                    //Ignore itself.
                } //of if

                if (Math.abs(tempItemAverageRating - itemAverageRatings[tempComparedItem]) < radius) {
                    tempTotal += compressedRatingMatrix[j][2];
                    tempNeighbors++;
                } //of if
            } //of for j

            // Step 3. Predict as the average value of neighbors.
            if (tempNeighbors > 0) {
                predictions[i] = tempTotal / tempNeighbors;
            } else {
                predictions[i] = DEFAULT_RATING;
                numNonNeighbors++;
            } //of if
        } //of for i
    }//of leaveOneOutPrediction

    /**
     *************************
     * Compute the MAE based on the deviation of each leave-one-out.
     *************************
     */
    public double computeMAE() throws Exception {
        double tempTotalError = 0;
        for (int i = 0; i < predictions.length; i++) {
            tempTotalError += Math.abs(predictions[i] - compressedRatingMatrix[i][2]);
        } //of for i

        return tempTotalError / predictions.length;
    }//of computeMAE

    /**
     *************************
     * Compute the MAE based on the deviation of each leave-one-out.
     *************************
     */
    public double computeRSME() throws Exception {
        double tempTotalError = 0;
        for (int i = 0; i < predictions.length; i++) {
            tempTotalError += (predictions[i] - compressedRatingMatrix[i][2])
                    * (predictions[i] - compressedRatingMatrix[i][2]);
        }//of for i

        double tempAverage = tempTotalError / predictions.length;

        return Math.sqrt(tempAverage);
    }//of computeRSME

    /**
     *************************
     * The entrance of the program.
     *
     * @param args
     *            Not used now.
     *************************
     */
    public static void main(String[] args) {
        try {
            MBR tempRecommender = new MBR("D:/mitchelles/data/movielens-943u1682m.txt", 943, 1682, 100000);

            for (double tempRadius = 0.2; tempRadius < 0.6; tempRadius += 0.1) {
                tempRecommender.setRadius(tempRadius);

                tempRecommender.leaveOneOutPrediction();
                double tempMAE = tempRecommender.computeMAE();
                double tempRSME = tempRecommender.computeRSME();

                System.out.println("Radius = " + tempRadius + ", MAE = " + tempMAE + ", RSME = " + tempRSME
                        + ", numNonNeighbors = " + tempRecommender.numNonNeighbors);
            }//of for tempRadius
        } catch (Exception ee) {
            System.out.println(ee);
        }//of try
    }//of main
}//of class MBR

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值