奇異值分解實驗:圖像壓縮與推薦系統

 


奇異值分解

只有方陣(行數等於列數)才能做特徵值分解,非方陣可不可以分解爲 33 個矩陣的乘積呢?

這種方式是【奇異值分解】,這種方法大學裏並不學。

因爲本科的線性代數主要研究方陣(除了線性系統),所以大學裏並沒有介紹非方陣的奇異值分解(SVDSVD),奇異值分解在數據降維、語義分析、圖像等領域都有十分廣泛的應用,比如 PCAPCA 算法裏如果用數據矩陣的奇異值分解代替協方差矩陣的特徵值分解,速度更快。

舉個荔枝,演示一下非方陣的分解步驟。

  • A=[011110]A=\left[ \begin{matrix} 0 & 1 \\ 1 & 1 \\ 1 & 0 \end{matrix} \right]

    1. 求出矩陣 ATAA^{T}AAATAA^{T}

      ATA=[011110][011110]=[2112]A^{T}A=\left[ \begin{matrix} 0 & 1 &1\\ 1 & 1 & 0 \end{matrix} \right]\left[ \begin{matrix} 0 & 1 \\ 1 & 1 \\ 1 & 0 \end{matrix} \right]=\left[ \begin{matrix} 2 & 1 \\ 1 & 2 \end{matrix} \right]
       
      AAT=[011110][011110]=[110121011]AA^{T}=\left[ \begin{matrix} 0 & 1 \\ 1 & 1 \\ 1 & 0 \end{matrix} \right]\left[ \begin{matrix} 0 & 1 &1\\ 1 & 1 & 0 \end{matrix} \right]=\left[ \begin{matrix} 1 & 1 & 0\\ 1 & 2 & 1\\ 0 & 1 & 1 \end{matrix} \right]

      發現 ATAA^{T}AAATAA^{T} 都是實對稱矩陣,必然可以做特徵值分解。

       

    2. 因此,分別求出 ATAA^{T}AAATAA^{T} 的特徵值和特徵向量:

      ATAA^{T}A 有倆組,   λ1=3   v1=[1/21/2]                λ2=1   v2=[1/21/2]~~~\lambda_{1}=3~~~v_{1}=\left[ \begin{matrix} 1/\sqrt{2}\\ 1/\sqrt{2} \end{matrix} \right]~~~~~~~~~~~~~~~~\lambda_{2}=1~~~v_{2}=\left[ \begin{matrix} -1/\sqrt{2}\\ 1/\sqrt{2} \end{matrix} \right]
       
      AATAA^{T} 有三組,   λ1=3   u1=[1/62/61/6]               λ2=1   u2=[1/201/2]                λ3=1   u3=[1/31/31/3]~~~\lambda_{1}=3~~~u_{1}=\left[ \begin{matrix} 1/\sqrt{6}\\ 2/\sqrt{6}\\ 1/\sqrt{6} \end{matrix} \right]~~~~~~~~~~~~~~~\lambda_{2}=1~~~u_{2}=\left[ \begin{matrix} 1/\sqrt{2}\\ 0\\ -1/\sqrt{2} \end{matrix} \right]~~~~~~~~~~~~~~~~\lambda_{3}=1~~~u_{3}=\left[ \begin{matrix} 1/\sqrt{3}\\ -1/\sqrt{3}\\ 1/\sqrt{3} \end{matrix} \right]
       

    3. AATAA^{T} 的特徵向量橫向拼成矩陣 UU

      U=[1/61/21/32/601/31/61/21/3]U=\left[ \begin{matrix} 1/\sqrt{6} & 1/\sqrt{2} & 1/\sqrt{3}\\ 2/\sqrt{6} & 0 & -1/\sqrt{3}\\ 1/\sqrt{6} & -1/\sqrt{2} & 1/\sqrt{3} \end{matrix} \right]

      UU 是正交矩陣,因爲TA的列向量倆倆正交,且都是單位向量。

       

    4. ATAA^{T}AAATAA^{T} 的相同特徵值開方,拼成矩陣\sum
       

      拼成矩陣\sumlambda1=3, lambda2=1   >   σ1=3, σ2=1   >   =[300100]lambda_{1}=3,~lambda_{2}=1~~~->~~~\sigma_{1}=\sqrt{3},~\sigma_{2}=\sqrt{1}~~~->~~~\sum=\left[ \begin{matrix} \sqrt{3} & 0 \\ 0 & \sqrt{1} \\ 0 & 0 \end{matrix} \right]

      P.S. σ1σ2\sigma_{1}、\sigma_{2} 的擺放順序與特徵向量一致。

       

    5. ATAA^{T}A 的特徵向量橫向拼成一個矩陣VV

      V=[1/21/21/21/2]   >   VT=[1/21/21/21/2]V=\left[ \begin{matrix} 1/\sqrt{2}& -1/\sqrt{2}\\ 1/\sqrt{2}& 1/\sqrt{2} \end{matrix} \right]~~~->~~~V^{T}=\left[ \begin{matrix} 1/\sqrt{2}& 1/\sqrt{2}\\ -1/\sqrt{2}& 1/\sqrt{2} \end{matrix} \right]

      P.S. VTV_{T} 也是正交矩陣,因爲TA的列向量倆倆正交,且是單位向量。
       

    6. 最後,將 UVTU·\sum·V^{T} 發現結果等於原矩陣AA,說明 矩陣AA 可以分解爲UVTU \sum V^{T}

      UVT=[1/61/21/32/601/31/61/21/3][300100][1/21/21/21/2]=[011110]=AU·\sum·V^{T}=\left[ \begin{matrix} 1/\sqrt{6} & 1/\sqrt{2} & 1/\sqrt{3}\\ 2/\sqrt{6} & 0 & -1/\sqrt{3}\\ 1/\sqrt{6} & -1/\sqrt{2} & 1/\sqrt{3} \end{matrix} \right]\left[ \begin{matrix} \sqrt{3} & 0 \\ 0 & \sqrt{1} \\ 0 & 0 \end{matrix} \right]\left[ \begin{matrix} 1/\sqrt{2}& 1/\sqrt{2}\\ -1/\sqrt{2}& 1/\sqrt{2} \end{matrix} \right]=\left[ \begin{matrix} 0 & 1 \\ 1 & 1 \\ 1 & 0 \end{matrix} \right]=A

雖然這只是一個 323*2 的矩陣的分解過程,但推廣到 mnm*n 的矩陣,按照這樣的步驟同樣可以分解爲三個矩陣的乘積,這種分解方式就是【奇異值分解】。

  • 奇異值分解:A=UVTA=U \sum V^{T}

    A=mn A=m*n~, 矩陣AA 的尺寸是 mnm*n

    U=mm U=m*m~,矩陣UU 的尺寸是 mmm*m,其列向量稱爲 矩陣AA 的左奇異向量;

    =mn \sum=m*n~,矩陣\sum 的尺寸是 mnm*n,其對角線上的值稱爲 矩陣AA 的奇異值;

    VT=nn V^{T}=n*n~, 矩陣VTV^{T} 的尺寸是 nnn*n,其列向量稱爲 矩陣AA 的右奇異向量。

 


低秩近似

我們可以把矩陣看成一種變換,把矩陣乘法當成線性變換時,找出變換矩陣的特徵值和特徵向量,實際上就是找出變換矩陣的主要變換方向。

也可以說是,特徵值和特徵向量代表了一個方陣的【固有信息】。

特徵值分解是奇異值分解的特例,特徵值分解只能分解方陣,奇異值分解可以分解任意形狀的矩陣。

因此,奇異值及奇異向量可以說是代表了一個 mnm*n 矩陣的【固有信息】。

奇異值越大,代表的信息就越多。

另外,如果我們在奇異值矩陣 \sum 中,將奇異值從大到小排列,就會發現奇異值下降特別快。

很多情況下,前 KK 個奇異值的和就佔了全部奇異值之和的 9090%。

也就是說,前 KK 個奇異值就足以代表整個矩陣的【固有信息】!!

所以,可以用 最大的 KK 個奇異值及對應的左右奇異向量來近似矩陣。

這種理論,就被稱爲【低秩近似】。

來看一個 757*5 的矩陣,使用【低秩近似】的實例!!

  • [11100333004440055500020440005501022]      >   [0.130.020.010.410.070.030.550.090.040.680.110.050.150.590.650.070.730.670.070.290.32][12.40009.50001.3][0.560.5900.560.090.0900.120.020.120.690.690.400.800.400.090.090]\left[ \begin{matrix} 1 & 1 & 1 & 0 & 0 \\ 3 & 3 & 3 & 0 & 0 \\ 4 & 4 & 4 & 0 & 0 \\ 5 & 5 & 5 & 0 & 0 \\ 0 & 2 & 0 & 4 & 4 \\ 0 & 0 & 0 & 5 & 5 \\ 0 & 1 & 0 & 2 & 2 \end{matrix} \right] ~~~奇異值分解後 ~~~->~~~\left[ \begin{matrix} 0.13 & 0.02 & -0.01 \\ 0.41 & 0.07 & -0.03 \\ 0.55 & 0.09 & -0.04 \\ 0.68 & 0.11 & -0.05 \\ 0.15 & -0.59 & 0.65 \\ 0.07 & -0.73 & -0.67 \\ 0.07 & -0.29 & 0.32 \end{matrix} \right]\left[ \begin{matrix} 12.4 & 0 & 0\\ 0 & 9.5 & 0 \\ 0 & 0 & 1.3 \end{matrix} \right]\left[ \begin{matrix} 0.56 & 0.590 & 0.56 & 0.09 & 0.090 \\ 0.12 & -0.02 & 0.12 & -0.69 & -0.69 \\ 0.40 & -0.80 & 0.40 & 0.09 & 0 .090 \end{matrix} \right]

     

    奇異值分解:A=UVTA=U \sum V^{T},看中間的\sum矩陣: [12.40009.50001.3]\left[ \begin{matrix} 12.4 & 0 & 0\\ 0 & 9.5 & 0 \\ 0 & 0 & 1.3 \end{matrix} \right]

     

    發現奇異值有 33 個,分別是 12.49.51.312.4、9.5、1.3,我們只用前面倆個奇異值來算一下,佔總奇異值的比例:

    • 12.4+9.512.4+9.5+1.394.4\frac{12.4+9.5}{12.4+9.5+1.3}\approx94.4%

     
    這個比例很大了,所以我們可以認爲前面倆個奇異值,及其對應的左右奇異向量足以代表原來的矩陣。

    把這些部分截取下來:

    • [0.130.020.410.070.550.090.680.110.150.590.070.730.070.29][12.4009.5][0.560.5900.560.090.0900.120.020.120.690.69][0.920.950.920.010.012.913.012.910.010.013.904.043.900.010.014.825.004.820.030.030.700.530.704.114.110.71.340.74.784.780.320.230.322.012.01]\left[ \begin{matrix} 0.13 & 0.02 \\ 0.41 & 0.07 \\ 0.55 & 0.09 \\ 0.68 & 0.11 \\ 0.15 & -0.59 \\ 0.07 & -0.73 \\ 0.07 & -0.29 \end{matrix} \right]\left[ \begin{matrix} 12.4 & 0 \\ 0 & 9.5 \\ \end{matrix} \right]\left[ \begin{matrix} 0.56 & 0.590 & 0.56 & 0.09 & 0.090 \\ 0.12 & -0.02 & 0.12 & -0.69 & -0.69 \end{matrix} \right]\approx\left[ \begin{matrix} 0.92 & 0.95 & 0.92 & 0.01 & 0.01 \\ 2.91 & 3.01 & 2.91 & -0.01 & -0.01 \\ 3.90 & 4.04 & 3.90 & 0.01 & 0.01 \\ 4.82 & 5.00 & 4.82 & 0.03 & 0.03 \\ 0.70 & 0.53 & 0.70 & 4.11 & 4.11 \\ -0.7 & 1.34 & -0.7 & 4.78 & 4.78 \\ 0.32 & 0.23 & 0.32 & 2.01 & 2.01 \end{matrix} \right]

     

    將截取下來的矩陣相乘,就低秩近似原來的數據矩陣,對比倆個矩陣可以發現,倆者數值非常接近。

    • 原始矩陣: [11100333004440055500020440005501022]\left[ \begin{matrix} 1 & 1 & 1 & 0 & 0 \\ 3 & 3 & 3 & 0 & 0 \\ 4 & 4 & 4 & 0 & 0 \\ 5 & 5 & 5 & 0 & 0 \\ 0 & 2 & 0 & 4 & 4 \\ 0 & 0 & 0 & 5 & 5 \\ 0 & 1 & 0 & 2 & 2 \end{matrix} \right] 近似矩陣:[0.920.950.920.010.012.913.012.910.010.013.904.043.900.010.014.825.004.820.030.030.700.530.704.114.110.71.340.74.784.780.320.230.322.012.01]\left[ \begin{matrix} 0.92 & 0.95 & 0.92 & 0.01 & 0.01 \\ 2.91 & 3.01 & 2.91 & -0.01 & -0.01 \\ 3.90 & 4.04 & 3.90 & 0.01 & 0.01 \\ 4.82 & 5.00 & 4.82 & 0.03 & 0.03 \\ 0.70 & 0.53 & 0.70 & 4.11 & 4.11 \\ -0.7 & 1.34 & -0.7 & 4.78 & 4.78 \\ 0.32 & 0.23 & 0.32 & 2.01 & 2.01 \end{matrix} \right]

 


工程應用:圖像壓縮

基於奇異值分解的【低秩近似】理論在工程中有廣泛的應用,比如圖像壓縮。

圖像本來就是一個矩陣,比如下面的圖片:


假設這張圖片的尺寸是 500395500*395,就需要 500395500*395 個字節來存儲。

就這樣一張不大的灰度圖,都要將近 22 萬字節(20KB20KB)存儲,要是某個應用是圖片爲主的,那您可以想象應用會有多大。

圖像壓縮主要有倆個好處:

  • 存儲空間會小很多
  • 方便網絡傳輸

我們可以用 奇異值分解 來壓縮圖像,算法就是【低秩近似】理論。

圖像壓縮有倆部分:

  • 壓縮圖像

    mnm*n 圖像矩陣做奇異值分解,得到 UmmmnVnnTU_{m*m}、\sum_{m*n}、V^{T}_{n*n}


    選取前 kk 大的奇異值(k<=nk<=n),按照【低秩近似】理論,對 UmmmnVnnTU_{m*m}、\sum_{m*n}、V^{T}_{n*n} 做截取,得到 UmkkkVknTU_{m*k}、\sum_{k*k}、V^{T}_{k*n}

    存儲或者傳輸新的 UmkkkVknTU_{m*k}、\sum_{k*k}、V^{T}_{k*n},新的矩陣不一定比原來的小,一定要選取一個恰當的 kk

  • 圖像重構

    UmkkkVknTU_{m*k}、\sum_{k*k}、V^{T}_{k*n} 按順序乘起來,圖像的主要信息就可以表示出來啦。但


     


完整代碼:

import cv2
# cv 庫用來讀取圖片
import numpy as np
import matplotlib.pyplot as plt
# plt 庫顯示圖片

''' @para: c 是保留奇異值(奇異向量)個數佔總個數比例 '''
def imgCompress(c, img):
    # 1. 圖像壓縮(SVD), 返回的是分解後的 3 個矩陣
    U, sigma, VT = np.linalg.svd(img)
    k = int(c * img.shape[1])                                   # .shape[1] 是列數,也是奇異值的個數
    sig = np.eye(k) * sigma[ :k]                                # sigma矩陣截取,構造新的奇異值矩陣,也是一個對角矩陣

    # 2. 圖像重構
    res_img = (U[:, :k] * sig) * VT[:k, :]                      # U、VT矩陣截取,並相乘
    size = U.shape[0] * k + sig.shape[0] * sig.shape[1] + k * VT.shape[1]
    # 壓縮後的數據量 = 截取後的(U的大小 + sigma的大小 + VT的大小)

    return res_img, size;


if __name__ == '__main__':
    # 1.讀取待壓縮的圖像
    img_path = input("圖片路徑:>  ")
    ori_img = np.mat(cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)) #  cv2.IMREAD_GRAYSCALE:以灰度圖方式讀取

    # 2.圖像壓縮(含重構)
    res_img, size = imgCompress(0.1, ori_img)                    # 0.1 只保留前 10% 的奇異值,比例越小,壓縮的越厲害,重構的圖片就越模糊

    print("壓縮前圖像大小:>  ", str(ori_img.shape[0] * ori_img.shape[1]))
    print("壓縮後圖像大小:>  ", str(size))

    # 顯示圖像(對比)
    fig, ax = plt.subplots(1, 2)
    ax[0].imshow(ori_img, cmap='gray')
    ax[0].set_title("before compress")
    ax[1].imshow(res_img, cmap='gray')
    ax[1].set_title("after compress")
    plt.show()

運行結果:

  • 壓縮前圖像大小:> 50292

  • 壓縮後圖像大小:> 8949

    哈哈,整整壓縮了一個量級(1010倍)。

顯示圖片:

 


工程應用:推薦系統

您看,我正在看電影,右邊會有一個推薦列表。

TA這個是根據什麼推薦呢?

可能是我根據的觀看記錄,這裏我們以評分爲判斷依據吧,簡單起見。


上圖一共 1111 位大佬,一共有 99 部電影,電影評分是 151-500 表示未評分或者未看過。

現在【馮八】大佬又來看電影了,我們應該推薦什麼給【馮八】呢?

因爲每一部電影都有分類的,我們可以在一個類別裏面給【馮八】挑:

  • 科幻:變形金剛、鋼鐵俠、流浪地球
  • 喜劇:喜劇之王、功夫、少林足球
  • 賭博:賭俠、賭神、賭聖

【馮八】給賭博片的打分普遍很高(賭聖5分、賭神4分),所以應該推薦賭博片裏沒看過的賭俠。

不過計算機理解不了這個影片分類,所以我們可以使用降維,使得數據投影變成 33 維,就有了科幻、喜劇、賭博的分類。

介紹一下,推薦系統的流程:

  • 前置準備,把所有用戶的評分數據放入到一個矩陣裏。

  1. 現在爲【馮八】推送服務,尋找【馮八】未打分的電影 — 在這個矩陣的第九行裏尋找等於 00 的元素。

  1. 預測【馮八】會給那些未打分的電影,打多少分。


    科幻類(黃色)打 22 分,喜劇類(藍色)打 22 分,賭博片(紅色)打 44 分。

    這裏的分類,其實是降維操作 — 使用 PCAPCA 算法將高維投影低維。PCAPCA 算法可參考《特徵值分解實驗:人臉識別與PageRank網頁排序》。不過,這裏面的 PCAPCA 算法採用的是特徵值分解(EVD),這篇文章是奇異值分解(SVD),所以我們還是用奇異值分解包裝的 PCAPCA 算法。

    奇異向量也可以構造 降維矩陣,因爲我們現在是對行降維,協方差矩陣維是 AATAA^{T},做奇異值分解時,左奇異矩陣 UU 就是矩陣AATA*A^{T} 的特徵向量拼接而來的 — 所以說,奇異值分解的過程中,本身就包含了特徵值分解。用特徵值來構造降維矩陣,和用奇異向量構造降維矩陣其實是一回事,只是書寫方式不同。

    所以,我們使用 SVDSVD 來構造降維矩陣,那降維矩陣就是從 左奇異矩陣UU 中截取:(Umk)TAmn=Bkn(U_{m*k})^{T}·A_{m*n}=B_{k*n}

    因爲 左奇異矩陣UU 是列向量橫向堆疊而成的,所以要轉置一下。而後將 數據矩陣AA 投影到 UU 所代表的低維空間裏,得到矩陣BB

    如果是對行降維,協方差矩陣維是 AATAA^{T},降維矩陣從左奇異矩陣UU 中截取:(Umk)TAmn=Bkn(U_{m*k})^{T}·A_{m*n}=B_{k*n}

    如果是對列降維,協方差矩陣維是 ATAA^{T}A,降維矩陣從右奇異矩陣VTV^{T} 中截取:(VknT)TAmn=Bmk(V^{T}_{k*n})^{T}·A_{m*n}=B_{m*k}

    在低維空間中,計算出待預測電影與其他電影的相似度。計算相似度,採用相似度算法接口,可參考《向量實驗:相似度算法》。

    而後,逐一將已評分電影的分數 * 相似度,而後求和 — 把相似度當成權重,得到預測分數

  2. 根據預測評分的大小排序,就前 NN 個電影給用戶。


    完整代碼:

import numpy as np
 
def load_dataSet():  # “用戶-電影”矩陣 ,行表示用戶的評分 ,列表示電影
    return np.mat([   [ 5, 4, 5, 4, 0, 0, 0, 0, 1],
                       [0, 0, 0, 0, 5, 4, 1, 4, 0],
                       [0, 0, 0, 0, 0, 0, 0, 5, 4],
                       [3, 3, 5, 0, 5, 0, 0, 0, 0],
                       [0, 0, 0, 0, 1, 1, 0, 0, 0],
                       [1, 2, 3, 0, 0, 0, 0, 0, 0],
                       [2, 0, 0, 5, 4, 5, 0, 0, 0],
                       [0, 0, 5, 0, 0, 0, 0, 1, 0],
                       [1, 0, 2, 0, 1, 0, 0, 4, 5],
                       [0, 5, 0, 0, 0, 0, 0, 1, 0],
                       [4, 4, 4, 0, 0, 0, 0, 1, 2]])
 
def cosSim(inA, inB): 
    return 0.5 + 0.5 * (float(inA.T * inB) / (np.linalg.norm(inA) * np.linalg.norm(inB)))  # 歸一化到[0,1],配合分數的歸一化
    
def scorePredict(dataMat, xformedItems, user_id, unrated_idx):
    rateTotal = 0.0   # 預測分數
    simTotal = 0.0    # 總相似度(權重)
    n = dataMat.shape[1]        # 獲取電影個數
    for i in range(n):         # 遍歷所有電影
        userRating = dataMat[user_id, i]  # 針對該用戶,拿到一個電影得分   [1, 0, 2, 0, 1, 0, 0, 4, 5],
        if userRating == 0 :   # 跳過未評分項
            continue
        similarity = cosSim(xformedItems[:, unrated_idx], xformedItems[:, i])   # 求餘弦相似度
        print( 'the movie_%d and movie_%d similarity is: %f' % (unrated_idx, i, similarity))  
        rateTotal += similarity * userRating  # 預測分數 = 相似度 * 已評分數
        simTotal  += similarity               # 相似度求和
        
    return rateTotal / simTotal  # 評分歸一化:使得評分值在0-5之間    
    
    
def  recommed(dataMat,user_id,N=3):
    # 1. 找出該用戶未評分電影     
    unratedItems = np.nonzero(dataMat[user_id, :]==0)[1]  # “==0”操作將0置爲1,將非0置爲0  [0, 1, 0, 1, 0, 1, 1, 0, 0]
    print("-------- The user -------\n",np.around(dataMat[user_id, :], decimals=3)) 
    print("-------- unratedItems -------\n",np.around(unratedItems , decimals=3)) 
    
    # 2.預測評分
    # 2.1. 降維(提取電影主題)
    U, Sigma, VT = np.linalg.svd(dataMat)
    # U*U.T = E ?若爲E證明U爲正交矩陣,其列向量已經單位正交化,就不用像EVD降維那樣,還要自己單位化
    print("----- U*U.T = E ? -----\n",np.around(U*U.T, decimals=0)) 
    
    # 2.2 自動收縮最適合的k
    k = 0  
    for i in range(len(Sigma)):
        if (np.linalg.norm(Sigma[:i + 1]) / np.linalg.norm(Sigma)) > 0.9:  
            k = i + 1
            break   #剛好找到滿足條件的k,退出循環
    
    # 2.3 截取U,得到降維矩陣
    red_U = U[:, :k]
    
    # 2.4 降維
    xformedItems = red_U.T * dataMat
    print("xformedItems shape:",xformedItems.shape)  # (3, 9)
    print("----- xformedItems -----\n",np.around(xformedItems, decimals=2)) 
    
    # 2.5 對未評分電影逐一進行分數預測
    movScores = [] # 存儲預測到的分數
    for unrated_idx in unratedItems:  # 遍歷所有未評分項的索引,逐項預測
        print ("-------- predict movie_%d -------" % (unrated_idx))
        score = scorePredict(dataMat, xformedItems, user_id, unrated_idx)     # 預測當前未評分項的分數
        movScores.append((unrated_idx, score))  # 以元組方式堆疊到movScores
    print("-------- movScores -------\n",np.around(movScores, decimals=3))
    
    # 3.按照預測分數從大到小排序,並返回前N大分數對應的電影
    return sorted(movScores, key=lambda tmp: tmp[1], reverse=True)[:N]  
    
    
if __name__ == "__main__":
    # 1.加載數據集
    dataMat = load_dataSet()
    print("dataMat shape:",dataMat.shape)
    print("-------- dataMat -------\n",np.around(dataMat, decimals=3))
    
    # 2.輸入一個用戶編號,給他推薦N部電影
    user_id = 8
    N = 4
    recommed_items = recommed(dataMat,user_id,N)
    print("---the recommendation of our system for user_%d are as follows---"%(user_id))
    print(np.around(recommed_items, decimals=3))
    print("done!!!!")

就我們設計的推薦系統,可能面臨的一些問題:

  • 可能會有上億用戶,數據矩陣規模很大,矩陣分解會很耗時間;

    解決:因爲這個矩陣在一段時間之內變換不大,所以一般一天計算一次就好。

  • 電影有成千上萬部,需要多次計算相似度,也很耗時間;

    解決:提前計算各個電影直接的相似度,需要的時候調用即可,不用計算。

  • 很多用戶都沒有給電影打分的習慣,所以矩陣爆00,會影響推薦效果。

    解決:胡歌,請您來打分~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章