scipy.sparse、pandas.sparse、sklearn稀疏矩阵的使用

机器学习︱R+python 同时被 3 个专栏收录
75 篇文章 6 订阅
18 篇文章 0 订阅

单机环境下,如果特征较为稀疏且矩阵较大,那么就会出现内存问题,如果不上分布式 + 不用Mars/Dask/CuPy等工具,那么稀疏矩阵就是一条比较容易实现的路。



1 scipy.sparse

参考:
SciPy 稀疏矩阵笔记
Sparse稀疏矩阵主要存储格式总结
Python数据分析----scipy稀疏矩阵

1.1 SciPy 几种稀疏矩阵类型

SciPy 中有 7 种存储稀疏矩阵的数据结构:

  • bsr_matrix: Block Sparse Row matrix
  • coo_matrix: COOrdinate format matrix
  • csc_matrix: Compressed Sparse Column matrix
  • csr_matrix: Compressed Sparse Row matrix
  • dia_matrix: Sparse matrix with DIAgonal storage
  • dok_matrix: Dictionary Of Keys based sparse matrix
  • lil_matrix: Row-based LInked List sparse matrix

各个类型的用途:

  • 如果想创建一个新的稀疏矩阵,lil_matrix,dok_matrix和coo_matrix会比高效,但是它们不适合做矩阵运算。
  • 如果想做矩阵运算,例如矩阵乘法、求逆等,应该用 CSC 或者 CSR 类型的稀疏矩阵。
  • 由于在内存中存储顺序的差异,csc_matrix 矩阵更适合取列切片,
  • 而 csr_matrix 矩阵更适合用来取行切片。

在这里插入图片描述

1.2 lil_matrix

这里只说lil_matrix,因为笔者用的这款,且比较方便。
lil_matrix 是第二直观的稀疏矩阵存储方式。它的全称是 row-based linked list sparse matrix 。它包含两个要素:rows 和 data

示例代码一:

>>> from scipy.sparse import lil_matrix
>>> l = lil_matrix((6,5))
>>> l[2,3] = 1
>>> l[3,4] = 2
>>> l[3,2] = 3
>>> print l.toarray()
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  3.  0.  2.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]
>>> print l.data
[[] [] [1.0] [3.0, 2.0] [] []]
>>> print l.rows
[[] [] [3] [2, 4] [] []]

示例代码二:

# 原始矩阵为

array([[1., 0., 0., 0., 0.],
       [0., 0., 2., 0., 3.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 4., 0.],
       [0., 0., 0., 0., 5.]])

mat_lil = sparse.lil_matrix(mat_coo) # 几种稀疏矩阵之间可以相互转化

# mat_lil 的两要素

mat_lil.rows

array([list([0]), list([2, 4]), list([]), list([3]), list([4])],
      dtype=object)

mat_lil.data

array([list([1.0]), list([2.0, 3.0]), list([]), list([4.0]), list([5.0])],
      dtype=object)

示例代码三:

# 创建矩阵
lil = sparse.lil_matrix((6, 5), dtype=int)

# 设置数值
# set individual point
lil[(0, -1)] = -1
# set two points
lil[3, (0, 4)] = [-2] * 2
# set main diagonal
lil.setdiag(8, k=0)

# set entire column
lil[:, 2] = np.arange(lil.shape[0]).reshape(-1, 1) + 1

# 转为array
lil.toarray()
'''
array([[ 8,  0,  1,  0, -1],
       [ 0,  8,  2,  0,  0],
       [ 0,  0,  3,  0,  0],
       [-2,  0,  4,  8, -2],
       [ 0,  0,  5,  0,  8],
       [ 0,  0,  6,  0,  0]])
'''

# 查看数据
lil.data
'''
array([list([0, 2, 4]), list([1, 2]), list([2]), list([0, 2, 3, 4]),
       list([2, 4]), list([2])], dtype=object)
'''
lil.rows
'''
array([[list([8, 1, -1])],
       [list([8, 2])],
       [list([3])],
       [list([-2, 4, 8, -2])],
       [list([5, 8])],
       [list([6])]], dtype=object)
'''

1.3 矩阵的通用属性

矩阵属性

from scipy.sparse import csr_matrix

### 共有属性
mat.shape  # 矩阵形状
mat.dtype  # 数据类型
mat.ndim  # 矩阵维度
mat.nnz   # 非零个数
mat.data  # 非零值, 一维数组

### COO 特有的
coo.row  # 矩阵行索引
coo.col  # 矩阵列索引

### CSR\CSC\BSR 特有的
bsr.indices    # 索引数组
bsr.indptr     # 指针数组
bsr.has_sorted_indices  # 索引是否排序
bsr.blocksize  # BSR矩阵块大小

通用方法

import scipy.sparse as sp

### 转换矩阵格式
tobsr()、tocsr()、to_csc()、to_dia()、to_dok()、to_lil()
mat.toarray()  # 转为array
mat.todense()  # 转为dense
# 返回给定格式的稀疏矩阵
mat.asformat(format)
# 返回给定元素格式的稀疏矩阵
mat.astype(t)  

### 检查矩阵格式
issparse、isspmatrix_lil、isspmatrix_csc、isspmatrix_csr
sp.issparse(mat)

### 获取矩阵数据
mat.getcol(j)  # 返回矩阵列j的一个拷贝,作为一个(mx 1) 稀疏矩阵 (列向量)
mat.getrow(i)  # 返回矩阵行i的一个拷贝,作为一个(1 x n)  稀疏矩阵 (行向量)
mat.nonzero()  # 非0元索引
mat.diagonal()   # 返回矩阵主对角元素
mat.max([axis])  # 给定轴的矩阵最大元素

### 矩阵运算
mat += mat     # 加
mat = mat * 5  # 乘
mat.dot(other)  # 坐标点积


resize(self, *shape)
transpose(self[, axes, copy])

1.4 稀疏矩阵存取

存储 - save_npz

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

读取 - load_npz

# 从npz文件中读取
test_x = sparse.load_npz('./data/npz/test_x.npz')

存储大小比较

a = np.arange(100000).reshape(1000,100)
a[10: 300] = 0
b = sparse.csr_matrix(a)

# 稀疏矩阵压缩存储到npz文件
sparse.save_npz('b_compressed.npz', b, True)  # 文件大小:100KB

# 稀疏矩阵不压缩存储到npz文件
sparse.save_npz('b_uncompressed.npz', b, False)  # 文件大小:560KB

# 存储到普通的npy文件
np.save('a.npy', a)  # 文件大小:391KB

# 存储到压缩的npz文件
np.savez_compressed('a_compressed.npz', a=a)  # 文件大小:97KB• 1


2 pandas.sparse

Sparse data structures

2.1 SparseArray

In [1]: arr = np.random.randn(10)

In [2]: arr[2:-2] = np.nan

In [3]: ts = pd.Series(pd.arrays.SparseArray(arr))

In [4]: ts
Out[4]: 
0    0.469112
1   -0.282863
2         NaN
3         NaN
4         NaN
5         NaN
6         NaN
7         NaN
8   -0.861849
9   -2.104569
dtype: Sparse[float64, nan]

pandas中sparse变成一种格式,如dtype: Sparse[float64, nan]

2.2 新建SparseDataFrame

之前Pandas版本有:pd.SparseDataFrame(),不过这个在新版本被移除了。

SparseSeries and SparseDataFrame were removed in pandas 1.0.0. This migration guide is present to aid in migrating from previous versions.

一种方式:

# Previous way
>>> pd.SparseDataFrame({"A": [0, 1]})

# New way
In [31]: pd.DataFrame({"A": pd.arrays.SparseArray([0, 1])})
Out[31]: 
   A
0  0
1  1

The SparseDataFrame.default_kind and SparseDataFrame.default_fill_value attributes have no replacement.

另一种方式:

# Previous way
>>> from scipy import sparse
>>> mat = sparse.eye(3)
>>> df = pd.SparseDataFrame(mat, columns=['A', 'B', 'C'])

# New way
In [32]: from scipy import sparse

In [33]: mat = sparse.eye(3)

In [34]: df = pd.DataFrame.sparse.from_spmatrix(mat, columns=['A', 'B', 'C'])

In [35]: df.dtypes
Out[35]: 
A    Sparse[float64, 0]
B    Sparse[float64, 0]
C    Sparse[float64, 0]
dtype: object

第三种新建:

In [38]: dense = pd.DataFrame({"A": [1, 0, 0, 1]})

In [39]: dtype = pd.SparseDtype(int, fill_value=0)

In [40]: dense.astype(dtype)
Out[40]: 
   A
0  1
1  0
2  0
3  1

2.3 格式转化

# SparseDataFrame -> dataframe
In [36]: df.sparse.to_dense()
Out[36]: 
     A    B    C
0  1.0  0.0  0.0
1  0.0  1.0  0.0
2  0.0  0.0  1.0

# SparseDataFrame -> spacy.coo
In [37]: df.sparse.to_coo()
Out[37]: 
<3x3 sparse matrix of type '<class 'numpy.float64'>'
	with 3 stored elements in COOrdinate format>

2.4 稀疏矩阵的属性

Sparse-specific properties, like density, are available on the .sparse accessor.

In [41]: df.sparse.density
Out[41]: 0.3333333333333333

2.5 scipy.sparse与pandas.sparse

从scipy -> pandas
pd.DataFrame.sparse.from_spmatrix 可以使用

In [47]: from scipy.sparse import csr_matrix

In [48]: arr = np.random.random(size=(1000, 5))

In [49]: arr[arr < .9] = 0

In [50]: sp_arr = csr_matrix(arr)

In [51]: sp_arr
Out[51]: 
<1000x5 sparse matrix of type '<class 'numpy.float64'>'
	with 517 stored elements in Compressed Sparse Row format>

In [52]: sdf = pd.DataFrame.sparse.from_spmatrix(sp_arr)

In [53]: sdf.head()
Out[53]: 
          0    1    2         3    4
0  0.956380  0.0  0.0  0.000000  0.0
1  0.000000  0.0  0.0  0.000000  0.0
2  0.000000  0.0  0.0  0.000000  0.0
3  0.000000  0.0  0.0  0.000000  0.0
4  0.999552  0.0  0.0  0.956153  0.0

In [54]: sdf.dtypes
Out[54]: 
0    Sparse[float64, 0]
1    Sparse[float64, 0]
2    Sparse[float64, 0]
3    Sparse[float64, 0]
4    Sparse[float64, 0]
dtype: object

从pandas -> scipy

In [61]: A, rows, columns = ss.sparse.to_coo(row_levels=['A', 'B'],
   ....:                                     column_levels=['C', 'D'],
   ....:                                     sort_labels=True)
   ....: 

In [62]: A
Out[62]: 
<3x4 sparse matrix of type '<class 'numpy.float64'>'
	with 3 stored elements in COOrdinate format>

In [63]: A.todense()
Out[63]: 
matrix([[0., 0., 1., 3.],
        [3., 0., 0., 0.],
        [0., 0., 0., 0.]])

In [64]: rows
Out[64]: [(1, 1), (1, 2), (2, 1)]

In [65]: columns
Out[65]: [('a', 0), ('a', 1), ('b', 0), ('b', 1)]

3 sklearn

一般情况scipy.sparse可以直接使用,进行train_test_split
如果pandas.sparse不行,那么就转成pandas x = x.sparse.to_dense()应该也是可以的:

fea_datasets = csr_matrix((data, (row, col)), shape=(row_index, max_col+1)).toarray()
#当特征维度过大时,选下面这种方式(加toarray()和不加都是对的),内存不容易爆掉
#fea_datasets = csr_matrix((data, (row, col)), shape=(row_index, max_col+1))

x_train, x_test, y_train, y_test = train_test_split(fea_datasets, target_list, test_size = 0.2, random_state = 0)
return x_train, x_test, y_train, y_test

笔者看到一般scipy中csr_matrix格式一般支持sklearn的模型训练;
如果是pandas.sparse可能会报错,所以,需要变成dataframe

  • 2
    点赞
  • 0
    评论
  • 11
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值