 $$ \newcommand{\R}{\mathbb{R}} \newcommand{\E}{\mathbb{E}} \newcommand{\x}{\mathbf{x}} \newcommand{\y}{\mathbf{y}} \newcommand{\wv}{\mathbf{w}} \newcommand{\av}{\mathbf{\alpha}} \newcommand{\bv}{\mathbf{b}} \newcommand{\N}{\mathbb{N}} \newcommand{\id}{\mathbf{I}} \newcommand{\ind}{\mathbf{1}} \newcommand{\0}{\mathbf{0}} \newcommand{\unit}{\mathbf{e}} \newcommand{\one}{\mathbf{1}} \newcommand{\zero}{\mathbf{0}} \newcommand\rfrac[2]{^{#1}\!/_{#2}} \newcommand{\norm}[1]{\left\lVert#1\right\rVert} $$

# 交替最小二乘

## 说明

交替最小二乘（ALS）算法将给定矩阵 $R$ 分解为两个因子 $U$ 和 $V$，使得 $R 约等于 U^TV$。未知行维度作为算法的参数给出，称为潜在因子。由于矩阵分解可以在推荐的上下文中使用，因此矩阵$U$和$V$可以分别称为user和item矩阵。user矩阵的第$i$t列用$u_i$表示，item矩阵的$i$t列用$v_i$表示。矩阵$R$可以称为评级矩阵。

为了找到user和item 矩阵，下面的问题就解决了：

其中$\lambda$是正则化因子，表示用户$i$已评级的项数，以及项$j$已评级的次数。这种避免过度拟合的正则化方案称为加权-$\lambda$-正则化。详细信息可以在[Zhou et al.](http://dx.doi.org/10.1007/978-3-540-6888-8_32)的著作中找到。

通过固定其中一个矩阵$U$或$V$，我们得到了一个可以直接求解的二次形式。修正问题的解保证了总成本函数的单调递减。通过将此步骤交替应用于矩阵$U$和$V$，我们可以迭代地改进矩阵分解。

矩阵$R$的稀疏表示形式是$(i,j, R)$的元组，其中$i$表示行索引，$j$表示列索引，$R$表示位置$(i,j)$的矩阵值。

## 操作

ALS是一个预测因子。因此，它支持“拟合”和“预测”操作。

### 拟合

ALS针对评分矩阵的稀疏表示进行训练:

*   `fit: DataSet[(Int, Int, Double)] =&gt; Unit`

### 预测

ALS预测每一行和列索引的元组的评级:
*   `predict: DataSet[(Int, Int)] =&gt; DataSet[(Int, Int, Double)]`

## 参数

交替最小二乘实现可由以下参数控制:

| 参数 | 描述 |
| --- | --- |
| **NumFactors** | 用于基础模型潜在因素的数量。它等价于计算user和item向量的维数。(默认值:  **10**) |
| **Lambda** | 正则化因子。调整此值，以避免过度拟合或由于强泛化而导致性能低下。 (默认值:  **1**) |
| **Iterations** | 最大迭代次数 (默认值:  **10**)|
| **Blocks** | 将user和item矩阵分组到其中的块数。使用的块越少，冗余发送的数据就越少。然而，更大的块意味着必须存储在堆上的更新消息更大。如果算法因为OutOfMemoryException而失败，则尝试增加块的数量。(默认值:**None**)|
| **Seed** | 用于生成算法初始item矩阵的随机种子。(默认值:  **0**) |
| **TemporaryPath** | 存储中间结果的临时目录的路径。如果设置了这个值，那么算法将分为两个预处理步骤，ALS迭代和一个后处理步骤，后者计算最后一个ALS半步。预处理步骤计算给定评级矩阵的“OutBlockInformation”和“InBlockInformation”。各个步骤的结果存储在指定的目录中。通过将算法分割成多个较小的步骤，Flink不必在太多的操作之间分割可用内存。这允许系统处理更大的单个消息，并提高整体性能 (默认值:**None**)|

## 例子

```
// Read input data set from a csv file val inputDS: DataSet[(Int, Int, Double)] = env.readCsvFile[(Int, Int, Double)](
  pathToTrainingFile)

// Setup the ALS learner val als = ALS()
.setIterations(10)
.setNumFactors(10)
.setBlocks(100)
.setTemporaryPath("hdfs://tempPath")

// Set the other parameters via a parameter map val parameters = ParameterMap()
.add(ALS.Lambda, 0.9)
.add(ALS.Seed, 42L)

// Calculate the factorization als.fit(inputDS, parameters)

// Read the testing data set from a csv file val testingDS: DataSet[(Int, Int)] = env.readCsvFile[(Int, Int)](pathToData)

// Calculate the ratings according to the matrix factorization val predictedRatings = als.predict(testingDS)
```



