稀疏矩陣在Python中的表示方法


對於一個矩陣而言,若數值為零的元素遠遠多於非零元素的個數,且非零元素分布沒有規律時,這樣的矩陣被稱作稀疏矩陣;與之相反,若非零元素數目占據絕大多數時,這樣的矩陣被稱作稠密矩陣。

稀疏矩陣在工程應用中經常被使用,尤其是在通信編碼和機器學習中。若編碼矩陣或特征表達矩陣是稀疏矩陣時,其計算速度會大大提升。對於機器學習而言,稀疏矩陣應用非常廣,比如在數據特征表示、自然語言處理等領域。用稀疏表示和工作在計算上代價很高,需要專門處理稀疏矩陣的表示和操作等,但是這些操作可以大幅提升性能。

Python中的稀疏矩陣

SciPy使用多個數據結構為創建稀疏矩陣提供了工具,以及將稠密矩陣轉化為稀疏矩陣的工具。許多在Numpy數組上運行的線性代數Numpy和SciPy函數可以在SciPy稀疏數組上操作。此外,使用Numpy數據結構的機器學習庫也可以在Scipy稀疏數組上操作,例如,用於機器學習的scikit-learning和用於深度學習的Keras。

Scipy中有可以表示的7種稀疏矩陣類型:

  1. csc_matrix: Compressed Sparse Column format
  2. csr_matrix: Compressed Sparse Row format
  3. bsr_matrix: Block Sparse Row format
  4. lil_matrix: List of Lists format
  5. dok_matrix: Dictionary of Keys format
  6. coo_matrix: COOrdinate format (aka IJV, triplet format)
  7. dia_matrix: DIAgonal format

下面介紹常用的幾種稀疏矩陣類型:

coo_matrix

coo_matrix是最簡單的存儲方式。采用三個數組row、col和data保存非零元素的行下標,列下標與值。這三個數組的長度相同。一般來說,coo_matrix主要用來創建矩陣,因為coo_matrix無法對矩陣的元素進行增刪改等操作,一旦創建之后,除了將之轉換成其它格式的矩陣,幾乎無法對其做任何操作和矩陣運算

>>> row = [0, 1, 2, 2]
>>> col = [0, 1, 2, 3]
>>> data = [1, 2, 3, 4]
# 生成coo格式的矩陣
>>> coo_mat = sparse.coo_matrix((data, (row, col)), shape=(4, 4))
>>> coo_mat
<4x4 sparse matrix of type '<class 'numpy.int32'>'
    with 4 stored elements in COOrdinate format>
>>> coo_mat.toarray()
array([[1, 0, 0, 0],
       [0, 2, 0, 0],
       [0, 0, 3, 4],
       [0, 0, 0, 0]])

優點:

  • 轉換成其它存儲格式很快捷簡便,轉換成csr/csc很快
  • 允許重復的索引(例如在1行1列處存了值2.0,又在1行1列處存了值3.0,則轉換成其它矩陣時就是2.0+3.0=5.0)

缺點:

  • 不支持切片和算術運算操作

dok_matrix與lil_matrix

dok_matrix和lil_matrix適用的場景是逐漸添加矩陣的元素。dok_matrix的策略是采用字典來記錄矩陣中不為0的元素。所以字典的key存的是記錄元素的位置信息的元祖,value是記錄元素的具體值。

>>> S = sparse.dok_matrix((5, 5), dtype=np.float32)
>>> for i in range(5):
      for j in range(5):
        S[i,j] = i+j    # 更新元素

>>> S.toarray()
[[0. 1. 2. 3. 4.]
 [1. 2. 3. 4. 5.]
 [2. 3. 4. 5. 6.]
 [3. 4. 5. 6. 7.]
 [4. 5. 6. 7. 8.]]

優點:

  • 對於遞增的構建稀疏矩陣很高效,比如定義該矩陣后,想進行每行每列更新值,可用該矩陣。當訪問某個單元,只需要O(1)

缺點:

  • 不允許重復索引(coo中適用),但可以很高效的轉換成coo后進行重復索引

lil_matrix則是使用兩個列表存儲非0元素。data保存每行中的非零元素,rows保存非零元素所在的列。這種格式也很適合逐個添加元素,並且能快速獲取行相關的數據。

>>> l = sparse.lil_matrix((4, 4))
>>> l[1, 1] = 1
>>> l[1, 3] =2
>>> l[2, 3] = 3
>>> l.toarray()
array([[0., 0., 0., 0.],
       [0., 1., 0., 2.],
       [0., 0., 0., 3.],
       [0., 0., 0., 0.]])

優點:

  • 適合遞增的構建成矩陣
  • 轉換成其它存儲方式很高效
  • 支持靈活的切片

缺點:

  • 當矩陣很大時,考慮用coo
  • 算術操作,列切片,矩陣向量內積操作慢

csr_matrix與csc_matrix

csr_matrix是按行對矩陣進行壓縮的,csc_matrix是按列對矩陣進行壓縮的。通過row_offsets,column_indices,data來確定矩陣。column_indices,data與coo格式的列索引與數值的含義完全相同,row_offsets表示元素的行偏移量。
用如下例子說明:

>>> indptr = np.array([0, 2, 3, 6]) # 元素的行偏移量
>>> indices = np.array([0, 2, 2, 0, 1, 2])  # 列索引
>>> data = np.array([1, 2, 3, 4, 5, 6])
>>> csr_matrix((data, indices, indptr), shape=(3, 3)).toarray()
array([[1, 0, 2],
       [0, 0, 3],
       [4, 5, 6]])

以官方文檔為例,此時data代表的是存儲的值的數組,indices代表的是每一行中第幾列有對應data中的元素,即從indices中可以推斷出列的信息,indptr則用來推斷出行的信息,默認元素開始為0,第一個元素為2,則證明第一行中有2-0=2個元素,所以將data數組中前另個元素寫入第一行中,而indices前兩個元素為0,2,則代表第0列和第2列。前兩第二個元素為3,證明第二行中有3-2=1個元素,該元素為data[2]=3,且存儲在indices[2] = 2列中。依次類推。

CSR格式常用於讀入數據后進行稀疏矩陣計算。

CSR:
優點:

  • 高效的稀疏矩陣算術操作
  • 高效的行切片
  • 快速地矩陣向量內積操作

缺點:

  • 緩慢地列切片操作(可以考慮csc)
  • 轉換到稀疏結構代價較高(可以考慮lil,dok)

CSC:
優點:

  • 高效的稀疏矩陣算術操作
  • 高效的列切片
  • 快速地矩陣向量內積操作(不如csr,bsr塊)

缺點:

  • 緩慢地行切片操作(可以考慮csr)
  • 轉換到稀疏結構代價較高(可以考慮lil,dok)

稀疏矩陣的存取

用save_npz保存單個稀疏矩陣

>>> scipy.sparse.save_npz('sparse_matrix.npz', sparse_matrix)
>>> sparse_matrix = scipy.sparse.load_npz('sparse_matrix.npz')

參考:
python稀疏矩陣的存儲與表示
機器學習稀疏矩陣簡介


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM