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**
相關文章
相關標籤/搜索