LFM矩阵分解,java实现

关于LFM分解理论和python实现见https://www.cnblogs.com/little-horse/p/12489619.html。

以下是java简单实现,完整程序见https://github.com/jiangnanboy/RecomSys/blob/master/src/main/java/com/sy/zhihai/model/LFM.java,数据https://github.com/jiangnanboy/RecomSys/tree/master/src/main/resources

import java.util.Map.Entry;
import java.util.Scanner;

import javolution.util.FastMap;
import javolution.util.FastList;

/**
 * LFM(latent factor model)隐语义推荐模型,矩阵分解,训练得到U,I矩阵
 * 对user-item评分矩阵进行分解为U、I矩阵,再利用随机梯度下降(函数值下降最快的方向)迭代求解出U,I矩阵,最后用U*I预测得出user对item的预测评分
 * 这里U矩阵是user对每个隐因子的偏好程度,I矩阵是item在每个隐因子中的分布
 **/
public class LFM extends AbsMF {

    public LFM() {
    }

    public static void main(String[] args) {
        String dataPath = "resultData.txt";
        LFM lfm = new LFM();
        lfm.loadData(dataPath);
        lfm.initParam(30, 0.02, 0.01, 50);
        lfm.train();

        System.out.println("Input userID...");
        Scanner in = new Scanner(System.in);
        while (true) {
            String userID = in.nextLine();
            FastList<RecommendedItem> recommendedItems = lfm.calRecSingleUser(userID, 50);
            lfm.displayRecoItem(userID, recommendedItems);
            System.out.println("Input userID...");
        }
    }

    /**
     * 初始化F,α,λ,max_iter,U,I
     *
     * @param F        隐因子数目
     * @param α        学习速率
     * @param λ        正则化参数,以防过拟合
     * @param max_iter 迭代次数
     */
    @Override
    public void initParam(int F, double α, double λ, int max_iter) {
        System.out.println("init... " + "F= " + F + "; " + "α= " + α + "; " + "λ= " + λ + "; " + "max_iter= " + max_iter + ";");
        this.F = F;
        this.α = α;
        this.λ = λ;
        this.max_iter = max_iter;
        this.U = new FastMap<String, Double[]>();
        this.I = new FastMap<String, Double[]>();

        String userID = null;
        Double[] randomUValue = null;
        Double[] randomIValue = null;
        //对U,I矩阵随机初始化
        for (Entry<String, FastMap<String, Double>> entry : ratingData.entrySet()) {
            userID = entry.getKey();
            randomUValue = new Double[F];
            for (int i = 0; i < F; i++) {
                double rand = Math.random() / Math.sqrt(F);//随机数填充初始化矩阵,并和1/sqrt(F)成正比
                randomUValue[i] = rand;
            }
            U.put(userID, randomUValue);
            for (String itemID : entry.getValue().keySet()) {
                if (I.containsKey(itemID))
                    continue;
                randomIValue = new Double[F];
                for (int i = 0; i < F; i++) {
                    double rand = Math.random() / Math.sqrt(F);
                    randomIValue[i] = rand;
                }
                I.put(itemID, randomIValue);
            }
        }
    }

    /**
     * 随机梯度下降训练U,I矩阵
     */
    @Override
    public void train() {
        System.out.println("training U,I...");
        for (int step = 0; step < this.max_iter; step++) {
            System.out.println("第" + (step + 1) + "次迭代...");
            for (Entry<String, FastMap<String, Double>> entry : this.ratingData.entrySet()) {
                String userID = entry.getKey();
                for (Entry<String, Double> entry1 : entry.getValue().entrySet()) {
                    String itemID = entry1.getKey();
                    double pui = this.predictRating(userID, itemID);
                    double err = entry1.getValue() - pui;//根据当前参数计算误差
                    Double[] userValue = this.U.get(userID);
                    Double[] itemValue = this.I.get(itemID);
                    for (int i = 0; i < this.F; i++) {
                        double us = userValue[i];
                        double it = itemValue[i];
                        us += this.α * (err * it - this.λ * us);//后一项是来防止过拟合的正则化项,λ需要根据具体应用场景反复实验得到。损失函数的优化使用随机梯度下降算法
                        it += this.α * (err * us - this.λ * it);
                        userValue[i] = us;
                        itemValue[i] = it;
                    }
                }
            }
            this.α *= 0.9;//每次迭代步长要逐步缩小
        }
    }

    /**
     * userID对itemID的评分
     * U每行表示该用户对各个隐因子的偏好程度
     * I每列表示该物品在各个隐患因子中的概率分布
     * rating=P*Q
     *
     * @param userID
     * @param itemID
     * @return
     */
    @Override
    public double predictRating(String userID, String itemID) {
        double p = 0.0;
        Double[] userValue = this.U.get(userID);
        Double[] itemValue = this.I.get(itemID);
        for (int i = 0; i < this.F; i++) {
            p += userValue[i] * itemValue[i];
        }
        return p;
    }

}

原文地址:https://www.cnblogs.com/little-horse/p/12623223.html

时间: 2024-11-03 14:14:33

LFM矩阵分解,java实现的相关文章

用Spark学习矩阵分解推荐算法

在矩阵分解在协同过滤推荐算法中的应用中,我们对矩阵分解在推荐算法中的应用原理做了总结,这里我们就从实践的角度来用Spark学习矩阵分解推荐算法. 1. Spark推荐算法概述 在Spark MLlib中,推荐算法这块只实现了基于矩阵分解的协同过滤推荐算法.而基于的算法是FunkSVD算法,即将m个用户和n个物品对应的评分矩阵M分解为两个低维的矩阵:$$M_{m \times n}=P_{m \times k}^TQ_{k \times n}$$ 其中k为分解成低维的维数,一般远比m和n小.如果大

基于矩阵分解的隐因子模型

推荐系统是现今广泛运用的一种数据分析方法.常见的如,“你关注的人也关注他”,“喜欢这个物品的用户还喜欢..”“你也许会喜欢”等等. 常见的推荐系统分为基于内容的推荐与基于历史记录的推荐. 基于内容的推荐,关键在于提取到有用的用户,物品信息,以此为特征向量来进行分类,回归. 基于历史记录的推荐,记录用户的评分,点击,收藏等等行为,以此来判断. 基于内容的推荐对于用户物品的信息收集度要求比较高,而许多情况下很难得到那么多的有用信息.而基于历史记录的方法,则利用一些常见的历史记录,相比与基于内容的方法

矩阵分解

矩阵分解在推荐系统中的应用 浅谈矩阵分解在推荐系统中的应用 SVD在推荐系统中的应用 用于推荐系统的一种矩阵分解库:LibMF 基于矩阵分解的推荐算法,简单入门 - kobeshow

ALS矩阵分解推荐模型

其实通过模型来预测一个user对一个item的评分,思想类似线性回归做预测,大致如下 定义一个预测模型(数学公式), 然后确定一个损失函数, 将已有数据作为训练集, 不断迭代来最小化损失函数的值, 最终确定参数,把参数套到预测模型中做预测. 矩阵分解的预测模型是: 损失函数是: 我们就是要最小化损失函数,从而求得参数q和p. 矩阵分解模型的物理意义 我们希望学习到一个P代表user的特征,Q代表item的特征.特征的每一个维度代表一个隐性因子,比如对电影来说,这些隐性因子可能是导演,演员等.当然

基于One-Class的矩阵分解方法

在矩阵分解中. 有类问题比較常见,即矩阵的元素仅仅有0和1. 相应实际应用中的场景是:用户对新闻的点击情况,对某些物品的购买情况等. 基于graphchi里面的矩阵分解结果不太理想.调研了下相关的文献,代码主要实现了基于PLSA的分解方法,具体请參考后面的參考文献 #!/usr/local/bin/python #-*-coding:utf-8-*- import sys import math import numpy as np import string import random "&q

【机器学习】K-Means 聚类是特殊的矩阵分解问题

[机器学习]K-Means 聚类是特殊的矩阵分解(Matrix Factorization)问题 原文是:<k-Means Clustering Is Matrix Factorization> 本博客是该论文的阅读笔记,不免有很多细节不对之处. 还望各位看官能够见谅,欢迎批评指正. 更多相关博客请猛戳:http://blog.csdn.net/cyh_24 如需转载,请附上本文链接:http://blog.csdn.net/cyh_24/article/details/50408884 论文

NMath矩阵分解的两种方式

概述:本教程为您介绍.Net唯一的数学与统计学运算库NMath,实现矩阵分解的两种方法. Nmath中包括用于构造和操作矩阵QR和奇异值分解的分解类.QR分解如下表示: 1 AP=QR 其中P是一个可置换矩阵,Q是正交的,且R为上梯形.矩阵A的奇异值分解(SVD)的形式表示为: 1 A=USV* 其中U和V是正交的,S是对角的,和V *表示一个真正的矩阵V或一个复杂的矩阵V的条目沿对角线S的共轭转置的奇异值. 接下来带来一个矩阵分解类的实例,下面代码示例为从FloatMatrix创建FloatQ

推荐系统中的矩阵分解演变方式

推荐算法主要分为基于内容的算法和协同过滤. 协同过滤的两种基本方法是基于邻居的方法(基于内容/物品的协同过滤)和隐语义模型. 矩阵分解乃是实现隐语义模型的基石. 矩阵分解根据用户对物品的评分, 推断出用户和物品的隐语义向量, 然后根据用户和物品的隐语义向量来进行推荐. 推荐系统用到的数据可以有显式评分和隐式评分. 显式评分时用户对物品的打分, 显式评分矩阵通常非常稀疏. 隐式评分是指用户的浏览, 购买, 搜索等历史记录, 表示的是用户行为的有无, 所以是一个密集矩阵. 1. 基本矩阵分解 矩阵分

矩阵分解在推荐系统中的应用

矩阵分解是最近几年比较火的算法,经过kddcup和netflix比赛的多人多次检验,矩阵分解可以带来更好的结果,而且可以充分地考虑各种因素的影响,有非常好的扩展性,因为要考虑多种因素的综合作用,往往需要构造cost function来将矩阵分解问题转化为优化问题,根据要考虑的因素为优化问题添加constraints,然后通过迭代的方法进行矩阵分解,原来评分矩阵中的missing vlaue可以通过分解后得到的矩阵求的. 本文将简单介绍下最近学习到的矩阵分解方法. (1)PureSvd 怎么评价这