交替最小二乘法(ALS)算法将一个给定的$R$矩阵因式分解为 $U$ 和 $V$ 两个因子,例如 $R \approx U^TV$。 未知的行的维度被用作算法的参数,叫做潜在因子。 由于矩阵因式分解可以用在推荐系统的场景,$U$和$V$矩阵可以分别称为用户和商品矩阵。 用户矩阵的第i列用$u_i$表示,商品矩阵的第i列用$v_i$表示。 $R$ 矩阵称为评价矩阵可以用 表示。 为了找到用户和商品矩阵,如下问题得到了解决:
$\lambda$作为正则化因子,作为用户$i$评过分的商品数量, 作为商品$j$被评分的次数。 这个因式分解方案避免了称作加权$\lambda$因式分解的过拟合。 细节可以在Zhou et al.的论文中找到。
通过修复$U$ 和 $V$矩阵,我们获得可以直接解析的二次形式。 问题的解决办法是保证总消耗函数的单调递减。通过对$U$ 或 $V$矩阵的这一步操作,我们逐步的改进了矩阵的因式分解。
$R$ 矩阵作为 $(i,j,r)$ 元组的疏松表示。$i$ 为行索引,$j$ 为列索引,$r$ 为 $(i,j)$ 位置上的矩阵值。
ALS
是一个预测模型(Predictor
)。
因此,它支持拟合(fit
)与预测(predict
)两种操作。
ALS用于评价矩阵的疏松表示过程的训练:
fit: DataSet[(Int, Int, Double)] => Unit
ALS会对每个元组行列的所有索引进行评分预测:
predict: DataSet[(Int, Int)] => DataSet[(Int, Int, Double)]
ALS的实现可以通过下面的参数进行控制:
参数 | 描述 |
---|---|
NumFactors |
底层模型中使用的潜在因子数目。等价于计算用户和商品向量的维度。 (默认值:10) |
Lambda |
因式分解的因子。 该值用于避免过拟合或者由于强生成导致的低性能。 (默认值:1) |
Iterations |
最大迭代次数。 (默认值:10) |
Blocks |
设定用户和商品矩阵被分组后的块数量。块越少,发送的冗余数据越少。然而,块越大意味着堆中需要存储的更新消息越大。如果由于OOM导致算法失败,试着降低块的数量。 (默认值:None) |
Seed |
用于算法生成初始矩阵的随机种子。 (默认值:0) |
TemporaryPath |
导致结果被立即存储到临时目录的路径。如果该值被设定,算法会被分为两个预处理阶段,ALS迭代和计算最后ALS半阶段的处理中阶段。预处理阶段计算给定评分矩阵的OutBlockInformation和InBlockInformation。每步的结果存储在特定的目录。通过将算法分为更多小的步骤,Flink不会在多个算子中分割可用的内存。这让系统可以处理更大的独立消息并提升总性能。 (默认值:None) |
// 从CSV文件读取输入数据集
val inputDS: DataSet[(Int, Int, Double)] = env.readCsvFile[(Int, Int, Double)](
pathToTrainingFile)
// 设定ALS学习器
val als = ALS()
.setIterations(10)
.setNumFactors(10)
.setBlocks(100)
.setTemporaryPath("hdfs://tempPath")
// 通过一个map参数设置其他参数
val parameters = ParameterMap()
.add(ALS.Lambda, 0.9)
.add(ALS.Seed, 42L)
// 计算因式分解
als.fit(inputDS, parameters)
// 从CSV文件读取测试数据
val testingDS: DataSet[(Int, Int)] = env.readCsvFile[(Int, Int)](pathToData)
// 通过矩阵因式分解计算评分
val predictedRatings = als.predict(testingDS)