Matrix Factorization

#Matrix Factorization ###①linearNetwork Hypothesis 机器学习的做用就是要从一堆数据中学习到学习到某种能力,而后用这种skill来预测将来的结果。好比一个电影推荐的例子,咱们手上有不少的电影数据,如今就须要训练一个机器学习的模型来使得这个模型能够预测一个新来的用户会喜欢什么电影,而后推荐过去。或者是对用户没有看过的电影进行评分预测。git

Nefix公司曾经举办过一场比赛,包含了大量的电影数据信息和近一亿个排名信息。用$$x_n = (n)$$那么,问题来了,第几个用户的这个n是没有什么实际意义的,也就是一个抽象特征,意味着只是一个编号,随便给只要不重复便可。可是输出方面就是很正常了:$$y_n = r_{nm}$$表示的就是第n个用户对第m部电影的排名预测。
仔细看一下这些ID特征,一般就是数字表示,好比1126,5566,6211等。这些数字编号并无什么太大的意义,都只是一种ID编号而已。这类特征,被称为类别特征,好比:ID号,blood type,programming languages等等,而许多机器学习模型都是数值特征,好比linear model,都是一串的数据,决策树例外,能够是类别区分。 因此要创建一个推荐系统的机器学习模型,就要把用户的ID号这些categorical features转换成numerical features,这种转换其实就是一个编码的过程了。
一种比较简单的就是binary vector encode。也就是说,若是输入样本有N个,就构造一个维度为N的向量。对应第n个样本那么第n个位置就是1其余都是0,好比下面的一个例子:
有点像one-hot向量,但不是。编码以后,那么用户的ID就是binary vector了。要注意的是用户是不必定对每个电影都会进行评分,能够就是评了一部分而已:
咱们就是要预测那些没有被评分的电影。**对于这个过程,咱们要作的就是掌握每个用户对于不一样电影的喜好程度,掌握这个电影的各类特征factor,好比有多少的喜剧,有多少的悬疑等等。这其实就是一个特征提取的过程。**这里使用的是$$N - d - M$$的网络,N就是输入的个数,d就是隐藏层的个数,也就是提取出特征的个数,M就是最后输出类别的个数。这个结构和以前咱们所看的autoencode很是像,可是不一样的就是autoencode是最后输出尽量的要拟合输入。

中间还有一个小问题,中间有一个非线性的函数,目的就是要使得整个模型nonlinear化,能够处理非线性的数据,**可是在这里需不须要呢?**实际上是不须要的,由于输入的向量是encoding获得的,大部分是0,小部分是1,那么就意味着这后面乘上的W权值其实就是只用一行有用,其余都是0,至关于只有一个权重值进入到tanh函数进行运算。从效果上来讲,tanh(x)与x是无差异的,只是单纯通过一个函数的计算,并不影响最终的结果,修改权重值便可获得一样的效果。由于进入计算以后,修改权值就能够达到效果了,而以前须要的缘由是,以前的结果都是须要多个权值就行组合,不加tanh就是线性组合了,因此加来变成非线性。这里就只有一个,不存在什么组合,因此直接使用便可。 改进一下,就是下面的图像了: github

对于这种结构,天然就是linearNetwork了,这个网络结构里面:$$W_{ni}^{(1)}$$就是Nxd,用V来表示,其实应该是$$V^T$$V的转置,隐藏层到输出层:$$W_{im}^{(2)}$$是dxM,因此进行线性模型以后:算法

h(x) = W^TVx$$若是是单个用户,那么其余的都是0,只有第n个位置才是1,因此,输出的hypothesis:$$h(x_n) = v_n

###②Basic Matrix Factorization 上面的变换VX咱们看作是一种特征转换,φ(x),那么就能够变成这样:

h(x_n) = W^Tφ(x)$$若是是对于单部电影:$$h(x_{nm}) = w_mφ(x)

咱们须要作的就是看看排名WV和y的结果要差很少,也就是作拟合,因此error function就是square error function:
上式中,灰色的部分是常数,并不影响最小化求解,因此能够忽略。接下来,咱们就要求出Ein最小化时对应的V和W解。 根据上式的分解:

r_{nm} = w^T_mv_n = v_n^Tw_m$$矩阵r是R的一个元素,R就是不一样电影的排名状况,这种方法叫作Matrix Factorization。
![](https://upload-images.jianshu.io/upload_images/10624272-9919f2b2f2bfca4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**因此一个电影的评分是能够分红两个部分的,一个是V的部分,一个就是W的部分,V能够看作是用户的部分,W是电影的部分,抽象一下其实就是:V这一行矩阵里面其实就是各类用户的feature,也就是分解出来的factorization,好比这个用户有多喜欢喜剧呀,有多喜欢打戏呀,有多喜欢剧情等等,固然这只是抽象化了而已,毕竟numerical features转成类别特征是须要想象力的,好比男生女生转成0和1,可是0和1想成男生女生就有点难了。对应回上面的,那么W矩阵天然就是有多少喜剧内容,有多少打戏,有多少剧情了。**
![](https://upload-images.jianshu.io/upload_images/10624272-464e0d132a0f3c31.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
最小化Ein函数:
![](https://upload-images.jianshu.io/upload_images/10624272-cbd8b5cd34c7ac19.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这里包含了两组优化的参数,一个是W,一个是V,这种状况有点像SVM的SMO算法,继续沿用它的想法,固定一个W选择更新V。
固定W的时候,对每个用户作linear regression便可。
固定V的时候,对每一部作linear regression便可。VW在结构上对称的,因此这两个东西的优化式子是差很少的,调换一下位置便可。
![](https://upload-images.jianshu.io/upload_images/10624272-54f57313dfe0aabd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
因此这样就获得了算法流程:
![](https://upload-images.jianshu.io/upload_images/10624272-3a52eaabe75d131c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**对于alternating least squares algorithm有两点要注意的:
①intintialize不能选择初始化为0的,由于矩阵是相乘获得,若是是0,那么所有都是0了,优化也是0,没有任何做用。
②converge,收敛性,对于每一步的优化都是冲着减少Ein去的,这就保证了这个算法的收敛性。**
![](https://upload-images.jianshu.io/upload_images/10624272-ea8b15b54011a89c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###④对于Matrix Factorization和Linear Autoencode的比较
![](https://upload-images.jianshu.io/upload_images/10624272-71174b206e0e4399.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
能够看出这二者是有很强的类似性的,因此linear antoencode能够看作是matrix fatorization的一种形式的。
###⑤SGD作优化
以前的迭代是全部的一块儿,SGD就是随机梯度降低,随机找一笔资料,只在这个资料上下作优化,效率很高,程序简单也容易实现,同时扩展到其余的错误也是很简单的。
![](https://upload-images.jianshu.io/upload_images/10624272-90aa25ca801c52b9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
对于每一笔资料如上图
![](https://upload-images.jianshu.io/upload_images/10624272-9369d6e74501fa1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/10624272-3b24a13fbe5efdc2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
若是这个用户没有评价过这部电影,那么就是0,优化也会是0的,这就是为何initial不能为0的缘由。从上述的图片也能够看出W和V是对称的,第一项都是residual。因此当咱们使用了SGD以后,那么这个算法的流程就改变了:
![](https://upload-images.jianshu.io/upload_images/10624272-aef069adad1ae73c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>>还有一个须要知道的,在推荐的过程当中,用户的习惯是可能发生改变的,好比三年前喜欢DC,三年后就喜欢漫威了,因此随着时间的变化,数据也应该随着时间的变化,因此在使用SGD的过程当中,最后的T次迭代咱们可使用时间比较靠近的样本放入optimization中做为优化数据,相对来讲结果也会比较准。
![](https://upload-images.jianshu.io/upload_images/10624272-4e7b0b02e4f3e515.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###⑥summary
总结一下所学过的提取特征:
![](https://upload-images.jianshu.io/upload_images/10624272-3d0a50891219433a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Adaboost是经过每一次选择最好的特征进行划分,也是一种Extraction Model,Network确定是了,隐藏层就是一个提取的方法,k近邻是用距离做为特征提取的工具,MF就是刚刚说的矩阵分解了。
![](https://upload-images.jianshu.io/upload_images/10624272-e5d45deb02d534e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
以上就是对应的技巧了。
>>####优缺点
>>**优势:简单,机器能够自动化的提取特征。powerful,能够处理各类复杂的问题,好比神经网络。
缺点:hard:比较难,有时候会遇到non-convex的问题,容易获得局部最优。overfit:过拟合的问题,其实上面的矩阵分解仍是须要正则化处理的。后面的代码实现加上了。**

![](https://upload-images.jianshu.io/upload_images/10624272-ac0d55916b51013a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###⑦代码实现
####1.数据的获取
咱们处理的数据是一个矩阵,先找到一些movie的数据:
![](https://upload-images.jianshu.io/upload_images/10624272-11fad311b4805963.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
电影的ID名字,事实上名字咱们倒不是特别关心。
还有一个评分的csv:
![](https://upload-images.jianshu.io/upload_images/10624272-9c24506ffdaee4ee.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
咱们要看的其实就是123列而已了。咱们要作的就是合成一个矩阵:
```

def load_Data(moves_name, ratings_name):
    print('loading data ......')
    movies = pd.read_csv('../Data/' + moves_name)
    ratings = pd.read_csv('../Data/' + ratings_name)
    n_movies = len(movies)
    n_ratings = len(ratings)
    last_movies = int(movies.iloc[-1].movieId)
    last_users = int(ratings.iloc[-1].userId)
    dataMat = np.zeros((last_users, last_movies))
    for i in range(len(ratings)):
        rating = ratings.loc[i]
        dataMat[int(rating.userId) - 1, int(rating.movieId) - 1] = rating['rating']
        pass
    return dataMat
```
要注意的是,这里电影的ID不是连在一块儿的,有点坑。
####2.梯度上升作optimization
```
def gradDscent(dataMat, k, alpha, beta, maxIter):
    '''

    :param dataMat:dataSet
    :param k: params of the matrix fatorization
    :param alphs: learning rate
    :param beta: regularization params
    :param maxIter: maxiter
    :return:
    '''
    print('start training......')
    m, n = np.shape(dataMat)
    p = np.mat(np.random.random((m, k)))
    q = np.mat(np.random.random((k, n)))

    for step in range(maxIter):
        for i in range(m):
            for j in range(n):
                if dataMat[i, j] > 0:
                    error = dataMat[i, j]
                    for r in range(k):
                        error = error - p[i, r]*q[r, j]
                    for r in range(k):
                        p[i, r] = p[i, r] + alpha * (2 * error * q[r, j] - beta * p[i, r])
                        q[r, j] = q[r, j] + alpha * (2 * error * p[i, r] - beta * q[r, j])
        loss = 0.0
        for i in range(m):
            for j in range(n):
                if dataMat[i, j] > 0:
                    error = 0.0
                    for r in range(k):
                        error = error + p[i, r] * q[r, j]
                    loss = np.power((dataMat[i, j] - error), 2)
                    for r in range(k):
                        loss = loss + beta * (p[i, r]*p[i, r] + q[r, j]*q[r, j])/2
        if loss < 0.001:
            break
        print('step : ', step, ' loss : ', loss)
    return p, q

```
并无使用SGD,只是彻底迭代。k就是分解的因子了,能够5个10个等等。中间都是循序渐进的根据公式来便可。可是中间加入的正则化,求导也是很容易获得结果的。
```
p, q = gradDscent(dataMat, 10, 0.0002, 0.02, 100000)
```
跑的太慢了,使用直接看loss就行了,毕竟很简单而已。
![](https://upload-images.jianshu.io/upload_images/10624272-6d2824d4c7274bb1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
都是不断减少的。
>>**附上GitHub代码:https://github.com/GreenArrow2017/MachineLearning/tree/master/MachineLearning/MatrixFactorization**
相关文章
相关标签/搜索