推薦系統為什麼使用稀疏矩陣?使用python的SciPy包處理稀疏矩陣

2021-01-11 deephub

在推薦系統中,我們通常使用非常稀疏的矩陣,因為項目總體非常大,而單個用戶通常與項目總體的一個非常小的子集進行交互。以YouTube為例——用戶通常會觀看數百個(可能是數千個)視頻,而YouTube的語料庫中有數百萬個視頻,這導致了>99%的稀疏性。

這意味著當我們在一個矩陣中表示用戶(行)和行為(列)時,結果是一個由許多零值組成的極其稀疏的矩陣。

在真實的場景中,我們如何最好地表示這樣一個稀疏的用戶-項目交互矩陣?

為什麼我們不能只使用Numpy數組或panda數據流呢?

要理解這一點,我們必須理解計算的兩個主要約束——時間和內存。前者就是我們所知道的「程序運行所需的時間」,而後者是「程序使用了多少內存」。前者非常簡單,但對於後者,確保程序不消耗所有內存非常重要,尤其是在處理大型數據集時,否則會遇到著名的「內存不足」錯誤。

我們PC上的每個程序和應用程式都使用一些內存(見下圖)。當我們運行矩陣計算並希望將這些稀疏矩陣存儲為Numpy數組或panda DataFrame時,它們也會消耗很多內存。

為了形式化這兩個約束,它們通常被稱為時間和空間(內存、硬碟等存儲)複雜性。

空間複雜度

當處理稀疏矩陣時,將它們存儲為一個完整的矩陣(從這裡開始稱為密集矩陣)是非常低效的。這是因為一個完整的數組為每個條目佔用一塊內存,所以一個n x m數組需要n x m塊內存。從簡單的邏輯角度來看,存儲這麼多零是沒有意義的!

從數學的角度來看,如果我們有一個100,000 x 100,000矩陣,這將要求我們有100,000 x 100,000 x 8 = 80gb的內存來存儲這個矩陣(因為每個double使用8位元組)!

時間複雜度

除了空間複雜性之外,密集的矩陣也會加劇運行時。我們將用下面的一個例子來說明。

那麼我們如何表示這些矩陣呢?

SciPy的稀疏模塊介紹

在Python中,稀疏數據結構在scipy中得到了有效的實現。稀疏模塊,其中大部分是基於Numpy數組。實現背後的思想很簡單:我們不將所有值存儲在密集的矩陣中,而是以某種格式存儲非零值(例如,使用它們的行和列索引)。

在我們深入研究CSR之前,讓我們比較一下在使用DataFrames和使用稀疏矩陣時在時間和空間複雜度上的效率差異。

import numpy as np from scipy import sparse from sys import getsizeof# Matrix 1: Create a dense matrix (stored as a full matrix). A_full = np.random.rand(600, 600)# Matrix 2: Store A_full as a sparse matrix (though it is dense). A_sparse = sparse.csc_matrix(A_full)# Matrix 3: Create a sparse matrix (stored as a full matrix). B_full = np.diag(np.random.rand(600))# Matrix 4: Store B_full as a sparse matrix. B_sparse = sparse.csc_matrix(B_full)# Create a square function to return the square of the matrix def square(A): return np.power(A, 2)

然後我們統計這些不同的矩陣以不同的形式存儲以及它們使用了多少內存。

%timeit square(A_full) print(getsizeof(A_full))>>> 6.91 ms ± 84.5 s per loop (mean ± std. dev. of 7 runs, 100 loops each) >>> 2880112%timeit square(A_sparse) print(getsizeof(A_sparse))>>> 409 ms ± 11.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) >>> 56%timeit square(B_full) print(getsizeof(B_full))>>> 2.18 ms ± 56.5 s per loop (mean ± std. dev. of 7 runs, 100 loops each) >>> 2880112%timeit square(B_sparse) print(getsizeof(B_sparse))>>> 187 s ± 5.24 s per loop (mean ± std. dev. of 7 runs, 10000 loops each) >>> 56

顯然,當我們用稀疏模塊存儲一個稀疏矩陣時,可以獲得時間和空間的最佳性能。

壓縮稀疏行(CSR)

儘管在SciPy中有很多類型的稀疏矩陣,比如鍵的字典(DOK)和列表的列表(LIL),但我只討論壓縮稀疏行(CSR),因為它是最常用和最廣為人知的格式。

CSR(以及CSC,又名壓縮稀疏列)用於寫一次讀多任務。為了有效地表示稀疏矩陣,CSR使用三個numpy數組來存儲一些相關信息,包括:

data(數據):非零值的值,這些是存儲在稀疏矩陣中的非零值

indices(索引):列索引的數組,從第一行(從左到右)開始,我們標識非零位置並在該行中返回它們的索引。在下面的圖中,第一個非零值出現在第0行第5列,因此5作為索引數組中的第一個值出現,然後是1(第1行,第1列)。

indptr(指針):表示索引指針,返回一個行開始的數組。這個定義容易把人搞糊塗,我選擇這樣解釋:它告訴我們每行包含多少個值。在下面的例子中,我們看到第一行包含一個值a,因此我們用0:1對它進行索引。第二行包含兩個值b, c,然後我們從1:3開始索引,以此類推。len(indptr) = len(data) + 1 = len(indexes) + 1,因為對於每一行,我們用開始和結束索引表示它(類似於索引列表)。

有哪些方法可以構造csr_matrix?

創建一個完整的矩陣並將其轉換為一個稀疏矩陣

some_dense_matrix = np.random.random(600, 600) some_sparse_matrix = sparse.csr_matrix(some_dense_matrix)

正如前面所看到的,這種方法是有很大問題的,因為我們必須首先獲得這個非常消耗內存的密集矩陣,然後才能將它轉換成一個稀疏矩陣。

創建一個空的稀疏矩陣

# format: csr_matrix((row_len, col_len)) empty_sparse_matrix = sparse.csr_matrix((600, 600))

注意,我們不應該創建一個空的稀疏矩陣,然後填充它們,因為csrmatrix被設計為一次寫、一次讀多。向csrmatrix寫入將是低效的,並且應該考慮其他類型的稀疏矩陣,比如在操作稀疏結構方面更有效的List of lists。

用數據創建一個稀疏矩陣

# method 1 # format: csr_matrix((data, (row_ind, col_ind)), [shape=(M, N)]) # where a[row_ind[k], col_ind[k]] = data[k]data = [3, 9, 5] rows = [0, 1, 1] cols = [2, 1, 2]sparse_matrix = sparse.csr_matrix((data, (rows, cols)), shape=(len(rows), len(cols)) sparse_matrix.toarray()>>> array([[0, 0, 3], [0, 9, 5], [0, 0, 0]], dtype=int64)# method 2 # format: csr_matrix((data, indices, indptr), [shape=(M, N)]) # column indices for row i: indices[indptr[i]:indptr[i+1]] # data values: data[indptr[i]:indptr[i+1]]data = [3, 9, 5] indices = [2, 1, 2] indptr = [0, 1, 3, 3]sparse_matrix = sparse.csr_matrix((data, indices, indptr)) sparse_matrix.toarray()>>> array([[0, 0, 3], [0, 9, 5], [0, 0, 0]], dtype=int64)

推薦使用這種方法

最後推薦兩篇文章,有興趣的可以深入閱讀

Sparse data structures in Python

Complexity and Sparse Matrices

相關焦點

  • 推薦系統 | 矩陣分解(SVD)原理和實戰
    本文收錄在推薦系統專欄,專欄系統化的整理推薦系統相關的算法和框架,並記錄了相關實踐經驗,所有代碼都已整理至推薦算法實戰集合(hub-recsys
  • 【每周一庫】-sprs-用Rust實現的稀疏矩陣庫
    sprs是用純Rust實現的部分稀疏矩陣數據結構和線性代數算法 特性 結構 矩陣 三元組矩陣 稀疏向量 運算
  • [公開課]《Python:從計算到算計》第04講: 科學計算(Scipy)
    : 傅立葉變換scipy.ndimage: n維圖像包scipy.odr: 正交距離回歸scipy.signal: 信號處理scipy.sparse: 稀疏矩陣scipy.spatial: 空間數據結構和算法scipy.special: 一些特殊的數學函數scipy.stats: 統計
  • Python求解特徵向量和拉普拉斯矩陣
    學過線性代數和深度學習先關的一定知道特徵向量和拉普拉斯矩陣,這兩者是很多模型的基礎,有著很重要的地位,那用python要怎麼實現呢?numpy和scipy兩個庫中模塊中都提供了線性代數的庫linalg,scipy更全面些。
  • 定量分析方法第04講:Scipy基礎
    : 優化scipy.cluster: 聚類scipy.constants: 物理和數學常量scipy.fftpack: 傅立葉變換scipy.ndimage: n維圖像包scipy.odr: 正交距離回歸scipy.signal: 信號處理scipy.sparse: 稀疏矩陣scipy.spatial
  • 好程式設計師Python培訓分享numpy簡介
    機器學習模型:在編寫機器學習算法時,需要對矩陣進行各種數值計算。例如矩陣乘法、換位、加法等。numpy scipy matplotlib ipython jupyter pandas sympy nose -i https://pypi.douban.com/simple/ #建議使用用戶安裝,將--user標誌發送給pip。
  • blender python處理矩陣乘法變更符號
    如果對矩陣對象執行任何乘法,要注意一件事情,Python 的最新版本(當然還有包含Blender內置Python版本)為適當的矩陣乘法實現了新的表示方法。用blender腳本編寫器編寫任何矩陣乘法,乘法* 語法仍然有效,這個只能作為 2.8 中嘗試普通乘法,而不是 2.7 中的矩陣乘法。如果你用在矩陣乘法會報出有趣的錯誤,因為這並不一定會拋出一個錯誤,a * ba @ b想要支持 2.7 和 2.8 的相同矩陣乘法樣式?首先,這似乎是一個類似的挑戰,採用前面幾節中提到的欄位注釋。
  • Scipy使用簡介
    [ 0.70622057 -0.6 -2.5 ][0.0, -8.881784197001252e-16, 0.0]在對方程組進行求解時,fsolve()會自動計算方程組在某點對各個未知變量的偏導數,這些偏導數組成一個二維數組,數學上稱之為雅閣比矩陣
  • 使用Python構建一個推薦系統需要幾步
    系統首先將新產品的內容用於推薦,然後最終用戶對該產品執行操作。現在,使用Python中的一個案例研究來鞏固對這些概念的理解。準備好你的電腦,因為這將會很有趣!3.使用MovieLens數據集的Python案例研究我們將處理MovieLens數據集,並建立一個模型來向最終用戶推薦電影。這些數據是由明尼蘇達大學的GroupLens研究項目收集的。
  • 如何在統一架構的同時高效處理各種稀疏度人工神經網絡矩陣?
    由於剪枝和 RELU 等操作,神經網絡的權重和激活矩陣中存在廣泛的稀疏性分布,且不同網絡和同一網絡不同層的稀疏度各不相同,其稀疏度分布範圍高達 4-90%。由於不同稀疏度矩陣運算對於計算和存儲電路要求各不相同,提出一種統一架構同時高效處理各種稀疏度的人工神經網絡矩陣,是人工智慧晶片設計領域的一大難題。
  • 教程| 無監督學習中的兩個非概率模型:稀疏編碼與自編碼器
    和「有監督學習」相比,這種方法的最大優勢就在於其無須給系統進行明確的標註(label)也能夠進行學習。最近,在德國的圖賓根,機器學習夏訓營(MachineLearningSummerSchool)正在如火如荼地進行,其中來自CMU的RuslanSalakhutdinov 教授就帶來了很多關於「無監督學習」的精彩內容。
  • Python裡簡單的矩陣操作
    Python比較牛的一個地方就是庫比較多,數據操作方便,下面的幾個例子是對矩陣的操作1、構建一個矩陣由上圖可見,reshape(3,5)就能構建一個3×5的矩陣2、隨機數生成一個矩陣3 、起始值為0,終點值為2×pi,總共100個值
  • 教程| 基礎入門:深度學習矩陣運算的概念和代碼實現
    神經網絡將權重儲存在矩陣當中。而線性代數特別是在 GPU 上,可以對矩陣進行簡單迅捷的計算處理。實際上,GPU 的設計就是源於向量和矩陣計算處理的基本概念。這和圖像由像素塊陣列構成,視頻遊戲使用巨量、連續展開的矩陣生成引人注目的遊戲體驗是一樣的。
  • 常用的十大 python 圖像處理工具
    Python成為這種圖像處理任務是一個恰當選擇,這是因為它作為一種科學程式語言正在日益普及,並且在其生態系統中免費提供許多最先進的圖像處理工具供大家使用。讓我們看一下可以用於圖像處理任務中的常用 Python 庫有哪些吧。
  • 1.5w字,Scipy使用簡介,碼住!
    [ 0.70622057 -0.6 -2.5 ][0.0, -8.881784197001252e-16, 0.0]在對方程組進行求解時,fsolve()會自動計算方程組在某點對各個未知變量的偏導數,這些偏導數組成一個二維數組,數學上稱之為雅閣比矩陣
  • 斯坦福ICLR 2018錄用論文:高效稀疏Winograd卷積神經網絡| ICLR 2018
    在稀疏卷積神經網絡上使用 Winograd 卷積算法會反而使計算量增大。針對上述問題,本文提出兩點改進。首先,我們將 ReLU 激活函數移至 Winograd 域,使得在乘法操作時神經元是稀疏的;其次,我們對 Winograd 變換之後的權重進行剪枝,使得在乘法操作時權重是稀疏的。
  • 怎樣使用python進行PLS-DA建模
    PLS-DA是計算化學中一種常見的分類算法,那麼它在python中如何實現呢?這裡我們使用scikit-learn包首先,導入需要的package:import pandas as pdfrom sklearn.datasets import load_irisfrom sklearn.metrics import accuracy_scorefrom sklearn.cross_decomposition import PLSRegression
  • 女生頭頂頭髮太稀疏了 頭頂稀疏能恢復濃密麼?
    可是對有些人來說,頭髮稠密純屬奢求,跟著生活壓力的增大,他們的頭髮變得越來越稀疏,不止不好看並且會讓人發生自卑心情。女生頭頂頭髮太稀疏了怎麼辦?頭頂稀疏能恢復濃密麼? 一、女生頭頂頭髮太稀疏的原因
  • 「首席架構師推薦」數值計算庫一覽表
    librsb是一個用於高性能稀疏矩陣計算的開源庫,提供多線程原語來構建迭代求解器(也實現稀疏BLAS標準)。它可以從C、c++、Fortran和專用的GNU Octave包中使用。hypre (High Performance preconditioning)是一個用於線性系統和預處理的可伸縮(並行)解決方案的例程開源庫。