scipy稀疏矩阵

稀疏矩阵:当一个矩阵内含有大量0值的时候,可以采用特定的存储方式,大大的降低矩阵存储的空间代价。

python中常用的是scipy.sparse.csr_matrix以及scipy.sparse.csc_matrix。另外就是libsvm格式也比较常用。

scipy.sparse.csr_matrix

这种方法是将矩阵按照行压缩。csr_matrix = Compressed Sparse Row matrix

压缩之后的对象具有三个属性:

  • indices: 用于记录存在非0值得列标
  • data:用于记录非0值的具体数值
  • indptr:用于记录每行对应的data和indices切割起始点

首先看一个具体的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#  示例解读
>>> 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]])
# 按row行来压缩
# 对于第i行,非0数据列是indices[indptr[i]:indptr[i+1]] 数据是data[indptr[i]:indptr[i+1]]
# 在本例中
# 第0行,有非0的数据列是indices[indptr[0]:indptr[1]] = indices[0:2] = [0,2]
# 数据是data[indptr[0]:indptr[1]] = data[0:2] = [1,2],所以在第0行第0列是1,第2列是2
# 第1行,有非0的数据列是indices[indptr[1]:indptr[2]] = indices[2:3] = [2]
# 数据是data[indptr[1]:indptr[2] = data[2:3] = [3],所以在第1行第2列是3
# 第2行,有非0的数据列是indices[indptr[2]:indptr[3]] = indices[3:6] = [0,1,2]
# 数据是data[indptr[2]:indptr[3]] = data[3:6] = [4,5,6],所以在第2行第0列是4,第1列是5,第2列是6
---------------------
作者:爆米花好美啊
来源:CSDN
原文:https://blog.csdn.net/u013010889/article/details/53305595
版权声明:本文为博主原创文章,转载请附上博文链接!

下面我们考虑两个特殊的情况:

  • 矩阵中某一行全部为0
  • 矩阵中有缺失值

矩阵中某一行全部为0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> from scipy.sparse import csr_matrix
>>> a = np.array([[0,0,0], [1,2,0], [0,0,0], [1,2,9]])
>>> print("matrix: ")
>>> print(a)
>>> csr = csr_matrix(a)
>>> print("csr.indices: ", csr.indices)
>>> print("csr.indptr: ", csr.indptr)
>>> print('csr.data: ', csr.data)
matrix:
[[0 0 0]
[1 2 0]
[0 0 0]
[1 2 9]]
csr.indices: [0 1 0 1 2]
csr.indptr: [0 0 2 2 5]
csr.data: [1 2 1 2 9]

可以看到,第一行全部为0,对应的indptr切片范围是0:0。可以看下这样的切片得到的什么?

1
2
3
>>> l = [0, 1]
>>> l[0:0]
[]

可以看到,这样的切片得到的是一个空list。

总结一下,如果某一行为0, 那么indptr属性对应这行的切割索引上下限一致,而data属性和indices属性则没有任何元素占位情况。

矩阵中存在缺失值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> from scipy.sparse import csr_matrix
>>> a = np.array([[0,0,0], [1,2,np.nan], [0,0,0], [1,2,9]])
>>> print("matrix: ")
>>> print(a)
>>> csr = csr_matrix(a)
>>> print("csr.indices: ", csr.indices)
>>> print("csr.indptr: ", csr.indptr)
>>> print('csr.data: ', csr.data)
>>> type(csr.toarray()[1,2])
matrix:
[[ 0. 0. 0.]
[ 1. 2. nan]
[ 0. 0. 0.]
[ 1. 2. 9.]]
csr.indices: [0 1 2 0 1 2]
csr.indptr: [0 0 3 3 6]
csr.data: [ 1. 2. nan 1. 2. 9.]
numpy.float64

可以看到,缺失值是正常视为非0值存储的。但是需要注意,只支持np.nan类型,不支持None。

scipy.sparse.csc_matrix

这种方法是将矩阵按照列压缩。csc_matrix = Compressed Sparse Column matrix

和csr_matrix一致,这里给出一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#  示例解读
>>> 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])
>>> csc_matrix((data, indices, indptr), shape=(3, 3)).toarray()
array([[1, 0, 4],
[0, 0, 5],
[2, 3, 6]])
# 按col列来压缩
# 对于第i列,非0数据行是indices[indptr[i]:indptr[i+1]] 数据是data[indptr[i]:indptr[i+1]]
# 在本例中
# 第0列,有非0的数据行是indices[indptr[0]:indptr[1]] = indices[0:2] = [0,2]
# 数据是data[indptr[0]:indptr[1]] = data[0:2] = [1,2],所以在第0列第0行是1,第2行是2
# 第1行,有非0的数据行是indices[indptr[1]:indptr[2]] = indices[2:3] = [2]
# 数据是data[indptr[1]:indptr[2] = data[2:3] = [3],所以在第1列第2行是3
# 第2行,有非0的数据行是indices[indptr[2]:indptr[3]] = indices[3:6] = [0,1,2]
# 数据是data[indptr[2]:indptr[3]] = data[3:6] = [4,5,6],所以在第2列第0行是4,第1行是5,第2行是6
---------------------
作者:爆米花好美啊
来源:CSDN
原文:https://blog.csdn.net/u013010889/article/details/53305595
版权声明:本文为博主原创文章,转载请附上博文链接!

libsvm

libsvm在机器学习中是更为常见的跨语言的一种稀疏矩阵压缩存储方式。一般可以直接用于模型训练。

1
2
3
4
5
6
7
8
9
10
11
12
13
libsvm使用的训练数据和检验数据文件格式如下:
[label] [index1]:[value1] [index2]:[value2]
[label] [index1]:[value1] [index2]:[value2]

label 目标值,就是说class(属于哪一类),就是你要分类的种类,通常是一些整数。

index 是有顺序的索引,通常是连续的整数。就是指特征编号,必须按照升序排列

value 就是特征值,用来train的数据,通常是一堆实数组成。

例如:
1 1:0.6875 2:0.1875 3:0.015625 4:0.109375
0 1:0.7875 2:0.1875 4:0.109375

这里依旧存在两个问题:

  • 缺失值如何存储
  • 模型拿到这个libsvm文件以后,如何快速的知道它的特征维度

经过测试,Python sklearn.datasets.dump_svmlight_file方法不支持缺失值存储。pyspark的libsvm方法虽然可以支持缺失值,但是在xgb调用的时候会报错。

一个简单的处理方式是填充一个特定值(比如-999)再存储。在调用xgb的时候可以通过如下方式指明缺失值:

1
2
3
import xgboost as xgb
dtrain = xgb.DMatrix("train_libsvm", missing=-999)
clf = xgb.train(params={...}, dtrain)