Scipy稀疏矩阵用法解析

发布时间 2023-11-03 09:35:03作者: 饮一杯天上水

Scipy稀疏矩阵用法解析

1.引言

在矩阵处理中为了减少内存的占用经常用到各种形式的稀疏矩阵存储方式(比如单位阵,会造成空间浪费),这时就采用矩阵压缩的方式来表述,数据不变,存储形式发生改变,省很多空间),scipy(一个Python库)就是一个利器。

引用参考文献地址:【Scipy学习】Scipy中稀疏矩阵用法解析(sp.csr_matrix;sp.csc_matrix;sp.coo_matrix)_一穷二白到年薪百万的博客-CSDN博客

python scipy 稀疏矩阵详解_jefferyLLLLL的博客-CSDN博客

2.csr_matrix

csr_matrix中,csr分成三个单词compress sparse row,因此csr是按行压缩的稀疏矩阵

csr_matrix矩阵返回值有三个属性indptr indices data 可以分别对应 count index data 三个通俗的解释。

  1. 由于csr_matrix是按行压缩的矩阵indptr(count)为每行中元素不为0个数的计数,值得注意的是这个计数是累加的,详细的解释看下面的例子。
  2. indices即index,表示每行中不为0元素的列的索引位置
  3. data 就是压缩矩阵中不为0的元素,返回的值是按照从0行到n行的顺序来的

csr_matrix对象属性

  • dtype :dtype:矩阵中元素的数据类型

  • shape 2-tuple:获取矩阵的shape

  • ndim :int:获取矩阵的维度,当然值是2咯

  • nnz:存储值的个数,包括显示声明的零元素(注意)

  • data:稀疏矩阵存储的值,是一个一维数组,即上面例子中的_data

  • indices:与属性data一一对应,元素值代表在某一行的列号

  • indptr:csr_matrix各行的起始值,length(csr_object.indptr) == csr_object.shape[0] + 1

  • has_sorted_indices:判断每一行的indices是否是有序的,返回bool值

csr_matrix的优点:

高效的算术运算CSR + CSR,CSR * CSR等
高效的行切片
快速矩阵运算

csr_matrix的缺点:

列切片操作比较慢(考虑csc_matrix)
稀疏结构的转换比较慢(考虑lil_matrix或doc_matrix)


   '''
   # 原始矩阵orig样例:
   orig = array([[1, 0, 2],
               [0, 0, 3],
               [4, 5, 6]])

   CSR: 按【行row】来压缩,便于理解,进行重命名
   
       count,就是官方的indptr,是一个递增数组
           含义:【差值】是统计原始矩阵每【行】【非0数据】的【个数】,
               反向理解,就是【累加】原始矩阵每行的【非0数据】的【个数】
               对于count数组,假设索引为i,
               count[i+1] - count[i]就是原始矩阵【第i行】的【非0数据】的【个数】
           样例:
               当i=0时,count[1] - count[0] = 2-0 = 2, 表示原始矩阵【第0行】的【非0数据】有【2个】
               当i=1时,count[2] - count[1] = 3-2 = 1, 表示原始矩阵【第1行】的【非0数据】有【1个】
               当i=2时,count[3] - count[2] = 6-3 = 3, 表示原始矩阵【第2行】的【非0数据】有【3个】
               
       index, 就是官方的indices,是一个【列索引】数组
           含义:对于CSR,这里就是【列】的索引,即表示原始矩阵当前行中的【非0数据】所在的【列索引值】
               对于index和count数组,假设索引为i,
               index[count[i]: count[i+1]]表示原始矩阵中【第i行】的【非0数据】所在的【列索引值】
               ps:注意中间是【冒号】
               
           样例:
               当i=0时,index[count[0]:count[1]] = index[0:2]= [0,2], 
           表示原始矩阵【第0行】的【2个】【非0数据】所在的【列索引值】为0和2,即定位为orig[0,0]和orig[0,2]
               当i=1时,index[count[1]:count[2]] = index[2:3]= [2], 
           表示原始矩阵【第0行】的【1个】【非0数据】所在的【列索引值】为2,即定位为orig[1,2]
               当i=2时,index[count[2]:count[3]] = index[3:6]= [0,1,2], 
           表示原始矩阵【第0行】的【3个】【非0数据】所在的【列索引值】为0,1,2,即定位为orig[2,0], orig[2,1]和orig[2,2]
           
       data,保持不变, 按行顺序,存储【非0数据】的数组
           含义:根据index数组找到每行中【非0数据】的【列索引值】,依次存取数据即可
               对于data和count数组,假设索引为i,
               data[count[i]: count[i+1]]表示原始矩阵中【第i行】的【非0数据】的【值】
           样例:
               当i=0时,data[count[0]:count[1]] = data[0:2]= [1,2], 
           表示原始矩阵【第0行】的【2个】【非0数据】,即定位为orig[0,0] =1 和orig[0,2]=2
               当i=1时,index[count[1]:count[2]] = index[2:3]= [2], 
           表示原始矩阵【第0行】的【1个】【非0数据】,即定位为orig[1,2]=3
               当i=2时,index[count[2]:count[3]] = index[3:6]= [0,1,2], 
           表示原始矩阵【第0行】的【3个】【非0数据】,即定位为orig[2,0]=4, orig[2,1]=5 和orig[2,2]=6
   '''
   
   count = np.array([0, 2, 3, 6])
   index = np.array([0, 2, 2, 0, 1, 2])
   data = np.array([1, 2, 3, 4, 5, 6])

   # 将稀疏矩阵转为原始矩阵
   orig = csr_matrix((data, index, count), shape=(3, 3)).toarray()
   # 将原始矩阵转为稀疏矩阵
   res = csr_matrix(orig)
   
   print(res.indptr) 
   # [0 2 3 6] 
   print(res.indices)
   # [0 2 2 0 1 2]
   print(res.data)
   # [1 4 5 2 3 6]
   print(orig)
   # [[1 0 2]
   #  [0 0 3]    
   # [4 5 6]]
   print(res)
   # (0, 0)        1
   # (0, 2)        2
   # (1, 2)        3
   # (2, 0)        4
   # (2, 1)        5
   # (2, 2)        6

csr_matrix 定义矩阵

import scipy.sparse as sp
# 定义一个空的稀疏矩阵
s = sp.csr_matrix((3, 3))
print(s.shape)
# (3, 3)
根据行列索引建
row = [0, 1, 2]
col = [0, 0, 1]
value = [1, 2, 3]
s = sp.csr_matrix((value, (row, col)), shape=[3, 3])
print(s)
#  (0, 0)        1
#  (1, 0)        2
#  (2, 1)        3

# 上面的解释所建立的方式

矩阵转换

import torch
import scipy.sparse as sp
matrix = torch.tensor([[1, 0, 3, 4],
                       [5, 6, 0, 8],
                       [9, 0, 0, 12]])

print('matrix',matrix)
csr_matrix = sp.csr_matrix(matrix.numpy())
print('csr_matrix',csr_matrix)
############################################################
matrix 
tensor([[ 1,  0,  3,  4],
        [ 5,  6,  0,  8],
        [ 9,  0,  0, 12]])
csr_matrix   
  (0, 0)	1
  (0, 2)	3
  (0, 3)	4
  (1, 0)	5
  (1, 1)	6
  (1, 3)	8
  (2, 0)	9
  (2, 3)	12
###########################################################

# csr_matrix转coo_matrix
coo_matrix = csr_matrix.tocoo()
# csr_matrix转csc_matrix
csc_matrix = csr_matrix.tocsc()
# 转化为torch稠密张量
# csc_matrix为np.matrix类型,不能直接转torch,需要借助toarray方法
torch_dense = torch.from_numpy(csc_matrix.toarray())
# 转稠密矩阵,该矩阵为np.matrix类型
matrix = csc_matrix.todense()
# np.matrix类型转np.ndarray
matrix.A

原则上来说,csr_matrix、csc_matrix、coo_matrix三种不同的稀疏矩阵,都有相应的to方法转化为彼此的格式,但是由于该类型是scipy.sparse库中的,不能与torch库直接相互转化,需要通过np.ndarray类型中转。

既:(scipy.sparse的csr_matrix、csc_matrix、coo_matrix三种方法可以相互转换)->toarray方法转化为np.ndarray类型->torch.from_numpy方法转化为torch稠密张量。

3 csc_matrix

csc分成三个单词compress sparse column,因此csr是按列压缩的稀疏矩阵。其实例化方式、属性、方法、优缺点和csr_matrix基本一致,这里不再赘述,它们之间唯一的区别就是按行或按列压缩进行存储。而这一区别决定了csr_matrix擅长行操作;csc_matrix擅长列操作,进行运算时需要进行合理存储结构的选择。

类比于跟csr的解释csc的解释相同。

  1. csc_matrix矩阵返回值有三个属性indptr indices data 可以分别对应 count index data 三个通俗的解释。
  2. 由于csc_matrix是按列压缩的矩阵indptr(count)为每行中元素不为0个数的计数,值得注意的是这个计数是累加的,详细的解释看下面的例子。
  3. indices即index,表示每列中不为0元素的行的索引位置
  4. data 就是压缩矩阵中不为0的元素,返回的值是按照从0列到n列的顺序来的

  '''
  # 原始矩阵orig样例:
  orig = array([[1, 0, 4],
              [0, 0, 5],
              [2, 3, 6]])

  CSC: 按【列col】来压缩,便于理解,进行重命名
  
      count,就是官方的indptr,是一个递增数组
          含义:【差值】是统计原始矩阵每【列】【非0数据】的【个数】,
              反向理解,就是【累加】原始矩阵每列的【非0数据】的【个数】
              对于count数组,假设索引为i,
              count[i+1] - count[i]就是原始矩阵【第i列】的【非0数据】的【个数】
          样例:
              当i=0时,count[1] - count[0] = 2-0 = 2, 表示原始矩阵【第0列】的【非0数据】有【2个】
              当i=1时,count[2] - count[1] = 3-2 = 1, 表示原始矩阵【第1列】的【非0数据】有【1个】
              当i=2时,count[3] - count[2] = 6-3 = 3, 表示原始矩阵【第2列】的【非0数据】有【3个】
              
      index, 就是官方的indices,是一个【行索引】数组
          含义:对于CSC,这里就是【行】的索引,即表示原始矩阵当前列中的【非0数据】所在的【行索引值】
              对于index和count数组,假设索引为i,
              index[count[i]: count[i+1]]表示原始矩阵中【第i列】的【非0数据】所在的【行索引值】
              ps:注意中间是【冒号】
              
          样例:
              当i=0时,index[count[0]:count[1]] = index[0:2]= [0,2], 
          表示原始矩阵【第0列】的【2个】【非0数据】所在的【行索引值】为0和2,即定位为orig[0,0]和orig[2,0]
              当i=1时,index[count[1]:count[2]] = index[2:3]= [2], 
          表示原始矩阵【第0列】的【1个】【非0数据】所在的【行索引值】为2,即定位为orig[2,1]
              当i=2时,index[count[2]:count[3]] = index[3:6]= [0,1,2], 
          表示原始矩阵【第0列】的【3个】【非0数据】所在的【行索引值】为0,1,2,即定位为orig[0,2], orig[1,2]和orig[2,2]
          
      data,保持不变, 按列顺序,存储【非0数据】的数组
          含义:根据index数组找到每列中【非0数据】的【行索引值】,依次存取数据即可
              对于data和count数组,假设索引为i,
              data[count[i]: count[i+1]]表示原始矩阵中【第i列】的【非0数据】的【值】
          样例:
              当i=0时,data[count[0]:count[1]] = data[0:2]= [1,2], 
          表示原始矩阵【第0列】的【2个】【非0数据】,即定位为orig[0,0] =1 和orig[2,0]=2
              当i=1时,index[count[1]:count[2]] = index[2:3]= [2], 
          表示原始矩阵【第0列】的【1个】【非0数据】,即定位为orig[2,1]=3
              当i=2时,index[count[2]:count[3]] = index[3:6]= [0,1,2], 
          表示原始矩阵【第0列】的【3个】【非0数据】,即定位为orig[0,2]=4, orig[1,2]=5 和orig[2,2]=6
  '''
  
  count = np.array([0, 2, 3, 6])
  index = np.array([0, 2, 2, 0, 1, 2])
  data = np.array([1, 2, 3, 4, 5, 6])

  # 将稀疏矩阵转为原始矩阵
  orig = csc_matrix((data, index, count), shape=(3, 3)).toarray()
  # 将原始矩阵转为稀疏矩阵
  res = csc_matrix(orig)
  
  print(res.indptr) 
  # [0 2 3 6]
  print(res.indices)
  # [0 2 2 0 1 2]
  print(res.data)
  # [1 4 5 2 3 6]
  print(orig)
  # [[1 0 4]
  # [0 0 5]
  # [2 3 6]]
  print(res)
  # (0, 0)        1
  # (2, 0)        2
  # (2, 1)        3
  # (0, 2)        4
  # (1, 2)        5
  # (2, 2)        6

csc_matrix对象属性

  • dtype :dtype:矩阵中元素的数据类型
  • shape 2-tuple:获取矩阵的shape
  • ndim :int:获取矩阵的维度,当然值是2咯
  • nnz:存储值的个数,包括显示声明的零元素(注意)
  • data:稀疏矩阵存储的值,是一个一维数组,即上面例子中的_data
  • indices:与属性data一一对应,元素值代表在某一行的列号
  • indptr:csr_matrix各行的起始值,length(csr_object.indptr) == csr_object.shape[0] + 1
  • has_sorted_indices:判断每一行的indices是否是有序的,返回bool值

csc_matrix的优点:

高效的算术运算CSC + CSC,CSC * CSC等
高效的列切片
快速矩阵运算

csr_matrix的缺点:

行切片操作比较慢(考虑csr_matrix)
稀疏结构的转换比较慢(考虑lil_matrix或doc_matrix)

4 coo_matrix

coo_matrix是坐标格式矩阵,给定存在元素的行列位置和值直接生成矩阵。

coo_matrix是最简单的稀疏矩阵存储方式,采用三元组(row, col, data)(或称为ijv format)的形式来存储矩阵中非零元素的信息。在实际使用中,一般coo_matrix用来创建矩阵,因为coo_matrix无法对矩阵的元素进行增删改操作;创建成功之后可以转化成其他格式的稀疏矩阵(如csr_matrix、csc_matrix)进行转置、矩阵乘法等操作。

coo_matrix对象属性:

  • dtype :dtype:矩阵中元素的数据类型

  • shape 2-tuple:获取矩阵的shape

  • ndim :int:获取矩阵的维度,当然值是2咯

  • nnz:存储值的个数,包括显示声明的零元素(注意)

  • data:稀疏矩阵存储的值,是一个一维数组,即上面例子中的_data

  • row:与data同等长度的一维数组,表征data中每个元素的行号

  • col:与data同等长度的一维数组,表征data中每个元素的列号

四种实例化方式

  1. 通过密集矩阵 D 实例化:可以使用 coo_matrix(D) 来将一个密集矩阵 D 转换为 coo_matrix 稀疏矩阵对象。

  2. 通过其他类型的稀疏矩阵 S 实例化:可以使用 coo_matrix(S) 将其他类型的稀疏矩阵 S 转换为 coo_matrix 稀疏矩阵对象。

  3. 通过指定形状 (M, N) 和数据类型 dtype 实例化空矩阵:可以使用 coo_matrix((M, N), [dtype]) 来创建一个形状为 M*N 的空 coo_matrix 稀疏矩阵对象,默认数据类型是 dtype。

  4. 通过三元组 (row, col, data) 初始化:可以使用 coo_matrix((row, col, data)) 来使用三个数组 row、col 和 data 来初始化 coo_matrix 稀疏矩阵对象。其中,row 和 col 分别表示非零元素的行索引和列索引,data 表示对应的非零元素的值。

import numpy as np
from scipy.sparse import coo_matrix

# 密集矩阵实例化
dense_matrix = np.array([[1, 2, 0], [0, 0, 3], [4, 0, 5]])
sparse_matrix_1 = coo_matrix(dense_matrix)

# 其他类型稀疏矩阵实例化
sparse_matrix_2 = coo_matrix(sparse_matrix_1)

# 空矩阵实例化
shape = (3, 3)
dtype = np.float32
# 空矩阵,所以打印没有任何值
sparse_matrix_3 = coo_matrix(shape, dtype=dtype)

# 三元组初始化
row = np.array([0, 1, 2])
col = np.array([0, 2, 2])
data = np.array([1, 3, 5])
sparse_matrix_4=coo_matrix((data, (row, col)), shape=(3, 3))

print('sparse_matrix_1',sparse_matrix_1)
print('sparse_matrix_2',sparse_matrix_2)
# 空矩阵,所以打印没有任何值
print('sparse_matrix_3',sparse_matrix_3)
print('sparse_matrix_4',sparse_matrix_4)
from scipy.sparse import coo_matrix
import numpy as np
row = np.array([1, 1, 3, 2]) # 行索引
col = np.array([0, 2, 2, 3]) # 列索引
data= np.array([5, 8, 4, 9]) # 索引对应的数值
coo = coo_matrix((data, (row, col)), shape=(4, 4)).todense()
#先看shape,表示这个稀疏矩阵是4x4大小的,所有值初始都为0,即4x4的全0矩阵
#(row, col)行、列组合就表示一个具体的位置,其(1,0),(1,2),(3,2),(2,3)就是4x4矩阵的索引位置。
#data,表示索引位置上的数值,即(1,0)上的数值为5,(1,2)上的数值为8,等等。
#todense,作用可以自己试试,如果没有这个函数,则输出如下结果
#  (1, 0)	5
#  (1, 2)	8
#  (3, 2)	4
#  (2, 3)	9
print(coo)
#打印出coo稀疏矩阵

coo_matrix的优点:

  • 有利于稀疏格式之间的快速转换(tobsr()、tocsr()、to_csc()、to_dia()、to_dok()、to_lil())
  • 允许又重复项(格式转换的时候自动相加)
  • 能与CSR / CSC格式的快速转换

coo_matrix的缺点:

  • 不能直接进行算术运算

5 lil_matrix

lil_matrix,即List of Lists format,又称为Row-based linked list sparse matrix。它使用两个嵌套列表存储稀疏矩阵:data保存每行中的非零元素的值,rows保存每行非零元素所在的列号(列号是顺序排序的)。这种格式很适合逐个添加元素,并且能快速获取行相关的数据。其初始化方式同coo_matrix初始化的前三种方式:通过密集矩阵构建、通过其他矩阵转化以及构建一个一定shape的空矩阵。

​ lil_matrix可用于算术运算:支持加法,减法,乘法,除法和矩阵幂。其属性前五个同coo_matrix,另外还有rows属性,是一个嵌套List,表示矩阵每行中非零元素的列号。LIL matrix本身的设计是用来方便快捷构建稀疏矩阵实例,而算术运算、矩阵运算则转化成CSC、CSR格式再进行,构建大型的稀疏矩阵还是推荐使用COO格式。

coo_matrix对象属性:

  • dtype :dtype:矩阵中元素的数据类型
  • shape 2-tuple:获取矩阵的shape
  • ndim :int:获取矩阵的维度,当然值是2咯
  • nnz:存储值的个数,包括显示声明的零元素(注意)
  • data:稀疏矩阵存储的值,是一个一维数组,即上面例子中的_data
  • rows:是一个嵌套List,表示矩阵每行中非零元素的列号

LIL format优点

  • 支持灵活的切片操作行切片操作效率高,列切片效率低
  • 稀疏矩阵格式之间的转化很高效(tobsr()、tocsr()、to_csc()、to_dia()、to_dok()、to_lil())

LIL format缺点

  • 加法操作效率低 (consider CSR or CSC)
  • 列切片效率低(consider CSC)
  • 矩阵乘法效率低 (consider CSR or CSC)

6.dok_matrix

dok_matrix,即Dictionary Of Keys based sparse matrix,是一种类似于coo matrix但又基于字典的稀疏矩阵存储方式,key由非零元素的的坐标值tuple(row, column)组成,value则代表数据值。dok matrix非常适合于增量构建稀疏矩阵,并一旦构建,就可以快速地转换为coo_matrix。其属性和coo_matrix前四项同;其初始化方式同coo_matrix初始化的前三种:通过密集矩阵构建、通过其他矩阵转化以及构建一个一定shape的空矩阵。对于dok matrix,可用于算术运算:它支持加法,减法,乘法,除法和矩阵幂;允许对单个元素进行快速访问( O(1) ); 不允许重复。

from scipy.sparse import dok_matrix

# 创建一个5x5的空dok_matrix
D = dok_matrix((5, 5), dtype=np.float32)

# 设置一些元素的值
D[0, 0] = 1.0
D[1, 2] = 2.0
D[3, 4] = 3.0

print(D)

7.dia_matrix

dia_matrix,全称Sparse matrix with DIAgonal storage,是一种对角线的存储方式。如下图中,将稀疏矩阵使用offsets和data两个矩阵来表示。offsets表示data中每一行数据在原始稀疏矩阵中的对角线位置k(k>0, 对角线往右上角移动;k<0, 对角线往左下方移动;k=0,主对角线)。该格式的稀疏矩阵可用于算术运算:它们支持加法,减法,乘法,除法和矩阵幂。

>>> data = np.arange(15).reshape(3, -1) + 1
>>> offsets = np.array([0, -3, 2])
>>> dia = sparse.dia_matrix((data, offsets), shape=(7, 5))
>>> dia.toarray()
array([[ 1,  0, 13,  0,  0],
       [ 0,  2,  0, 14,  0],
       [ 0,  0,  3,  0, 15],
       [ 6,  0,  0,  4,  0],
       [ 0,  7,  0,  0,  5],
       [ 0,  0,  8,  0,  0],
       [ 0,  0,  0,  9,  0]])

8.bsr_matrix

bsr_matrix,全称Block Sparse Row matrix,这种压缩方式极其类似CSR格式,但使用分块的思想对稀疏矩阵进行按行压缩。所以,BSR适用于具有dense子矩阵的稀疏矩阵。该种矩阵有五种初始化方式,分别如下

  • bsr_matrix(D, [blocksize=(R,C)])

    • D是一个M*N的二维dense矩阵;blocksize需要满足条件:M % R = 0和N % C = 0,若不给定该参数,内部将会应用启发式的算法自动决定一个合适的blocksize.
  • bsr_matrix(S, [blocksize=(R,C)])

    • S是指其他类型的稀疏矩阵
  • bsr_matrix((M, N), [blocksize=(R,C), dtype])

    • 构建一个shape为M*N的空矩阵
  • bsr_matrix((data, ij), [blocksize=(R,C), shape=(M, N)])

    • data 和ij 满足条件: a[ij[0, k], ij[1, k]] = data[k]
  • bsr_matrix((data, indices, indptr), [shape=(M, N)])

    • data.shape一般是kRC,其中R、C分别代表block的行和列长,k代表有几个小block矩阵;第i行的块列索引存储在indices[indptr[i]:indptr[i+1]],其值是data[ indptr[i]: indptr[i+1] ]。

bsr_matrix可用于算术运算:支持加法,减法,乘法,除法和矩阵幂。如下面的例子,对于许多稀疏算术运算,BSR比CSR和CSC更有效:

>>> from scipy.sparse import bsr_matrix
>>> import numpy

>>> 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]).repeat(4).reshape(6, 2, 2)

>>> bsr_matrix((data,indices,indptr), shape=(6, 6)).toarray()
array([[1, 1, 0, 0, 2, 2],
       [1, 1, 0, 0, 2, 2],
       [0, 0, 0, 0, 3, 3],
       [0, 0, 0, 0, 3, 3],
       [4, 4, 5, 5, 6, 6],
       [4, 4, 5, 5, 6, 6]])

9 稀疏矩阵的运算

9.1 加法

两个稀疏矩阵相加直接加

row = [0, 1, 2]
col = [0, 0, 1]
value = [1, 2, 3]
a = sp.csr_matrix((value, (row, col)), shape=[3, 3])
b = a
c = a+b
print(c)
#   (0, 0)        2
#   (1, 0)        4
#   (2, 1)        6

9.2 乘法

可以是两个稀疏矩阵相乘,乘完后还是稀疏矩阵

row = [0, 1, 2]
col = [0, 0, 1]
value = [1, 2, 3]
a = sp.csr_matrix((value, (row, col)), shape=[3, 3])
b = a
c = a.dot(b)
print(c)
#  (0, 0)        1
#  (1, 0)        2
#  (2, 0)        6

也可以是稀疏矩阵乘以一个稠密矩阵(顺序不能换,不能是稠密矩阵乘以稀疏矩阵,如果需要则先调换二者顺序为 sparse x dense,乘完再转置回来),乘完之后c是稠密矩阵,这类似于tensorflow中的 tf.sparse_tensor_dense_matmul 操作

row = [0, 1, 2]
col = [0, 0, 1]
value = [1, 2, 3]
a = sp.csr_matrix((value, (row, col)), shape=[3, 3])
b = a.todense()
c = a.dot(b)
print(c)
>>> [[1 0 0]
	 [2 0 0]
	 [6 0 0]]

9.3 提取行列

稀疏矩阵提取行列和稠密矩阵提取一样

row = [0, 1, 2]
col = [0, 0, 1]
value = [1, 2, 3]
a = sp.csr_matrix((value, (row, col)), shape=[3, 3])
print('a的第0行\n', a[0], '\n a的第0列\n', a[:, 0])
>>>  a的第0行
	   (0, 0)       1
	 a的第0列
	   (0, 0)       1
	   (1, 0)        2

10 实用函数

  • 稀疏矩阵类型判断

  • scipy.sparse模块还包含一些判断稀疏矩阵类型的函数,这里需要注意的是,issparse() 和 isspmatrix() 是相同的函数,也许是由于历史原因保留下来了两个。

  • isspars(x)

  • isspmatrix(x)

  • isspmatrix_csc(x)

  • isspmatrix_csr(x)

  • isspmatrix_bsr(x)

  • isspmatrix_lil(x)

  • isspmatrix_dok(x)

  • isspmatrix_coo(x)

  • isspmatrix_dia(x)

  • 稀疏矩阵存取

    • load_npz(file) 从.npz文件中读取稀疏矩阵
    • save_npz(file, matrix[,compressed]) 将稀疏矩阵写入.npz文件中
  • 其他

    • find(A) 返回稀疏矩阵中非零元素的索引以及值

11.总结

scipy.sparse库提供了三种类型的稀疏矩阵:csr_matrix、csc_matrix、coo_matrix。

csr_matrix 按照行进行稀疏化
csc_matrix 按照列进行稀疏化
coo_matrix 按照坐标稀疏化

三种稀疏方式矩阵,在torch库中也有,分别是

torch.sparse_coo_tensor()
torch.sparse_csc_tensor()
torch.sparse_csr_tensor()

由于他们不是属于同一个库,所以无法直接转换,需要借助np库中转转换或者是抽离组成的元素构建。但是各自库自己的稀疏方法之间可以相互转化,都提供了to方法。

如下显示了

scipy.sparse库中的转换方法和到torch稠密张量的转化方式

import torch
import scipy.sparse as sp
matrix = torch.tensor([[1, 0, 3, 4],
                       [5, 6, 0, 8],
                       [9, 0, 0, 12]])
# 三种稀疏矩阵互转
csr_matrix = sp.csr_matrix(matrix.numpy())
csc_matrix = csr_matrix.tocsc()
coo_matrix = csc_matrix.tocoo()
# 三种稀疏矩阵都可以通过toarrary方法转化为numpy类型数据在转化为torch类型稠密张量或者稀疏张量
'''
方法1,首先转化为np.ndarray,然后转化为torch张量(稠密),然后由张量转化为各种不同稀疏方式的矩阵
'''
np_array = coo_matrix.toarray()
torch_dense = torch.from_numpy(np_array)
sparse_coo = torch_dense.to_sparse_coo()
sparse_csc = torch_dense.to_sparse_csc()
sparse_csr = torch_dense.to_sparse_csr()
print('sparse_coo',sparse_coo)
print('sparse_csc',sparse_csc)
print('sparse_csr',sparse_csr)
'''
方法2,首先转化为np.matrix,然后由.A方法转化为np.ndarray,在转化为torch张量(稠密),然后由张量转化为各种不同稀疏方式的矩阵
'''
# todense方法转化为的是np.matrix
np_matrix = csr_matrix.todense()
np_array = np_matrix.A
torch_dense = torch.from_numpy(np_array)
print('torch_dense',torch_dense)

经验总结

  • 要有效地构造矩阵,请使用dok_matrix或lil_matrix

    • lil_matrix类支持基本切片和花式索引,其语法与NumPy Array类似;lil_matrix形式是基于row的,因此能够很高效的转为csr,但是转为csc效率相对较低。
  • 强烈建议不要直接使用NumPy函数运算稀疏矩阵

    • 如果你想将NumPy函数应用于这些矩阵,首先要检查SciPy是否有自己的给定稀疏矩阵类的实现,或者首先将稀疏矩阵转换为NumPy数组(使用类的toarray()方法)。
  • 要执行乘法或转置等操作,首先将矩阵转换为CSC或CSR格式,效率高

    • CSR格式特别适用于快速矩阵矢量产品
  • CSR,CSC和COO格式之间的所有转换都是线性复杂度。

scipy、numpy、torch都可以对矩阵和向量进行操作,他们之间的区别和联系是啥?可以相互替代吗

scipy、numpy和torch都是Python中用于科学计算和数据处理的库,它们都可以对矩阵和向量进行操作,但各有其特点和用途:

- numpy:是Python科学计算的基础库,提供了多维数组对象、矩阵操作(如数学运算、逻辑运算、形状操作等)和数学函数等功能。它的计算效率高,易于使用,是很多其他科学计算库的基础。

- scipy:基于numpy,提供了更多的科学计算功能,如线性代数、优化、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理等。它还提供了稀疏矩阵和稀疏线性系统求解算法。

- torch:主要用于深度学习和机器学习,提供了多维数组torch.Tensor和大量操作,支持GPU加速。它还提供了自动求导机制,方便进行神经网络的训练。

它们之间的联系主要是都可以进行矩阵和向量的操作,而区别在于提供的功能和使用场景。numpy和scipy主要用于通用的科学计算,而torch主要用于深度学习。

在某些情况下,它们可以相互替代。例如,如果你只需要进行基本的矩阵和向量操作,那么numpy、scipy和torch都可以满足需求。但在其他情况下,它们可能不能完全替代。例如,如果你需要进行深度学习训练,那么torch的自动求导和GPU支持将非常有用;如果你需要处理大规模的稀疏矩阵,那么scipy的稀疏矩阵支持将更加合适。

总的来说,选择哪个库主要取决于你的具体需求和使用场景。