我正在Python中创建一些带有单词计数的numpy数组:行是文档,列是单词X的计数。如果我有很多零计数,人们建议在进一步处理这些时使用稀疏矩阵,例如在分类器中。然而,当将numpy数组与稀疏矩阵输入Scikit逻辑回归分类器时,似乎没有太大区别。所以我想知道三件事:
-
维基百科称
稀疏矩阵是其中大多数元素为零的矩阵
这是确定何时使用稀疏矩阵的合适方法吗format-只要50%以上的值为零?或者它能以防万一有意义吗?
- 在像我这样的任务中,稀疏矩阵对性能有多大帮助,尤其是与numpy数组或标准列表相比
- 到目前为止,我将数据收集到一个numpy数组中,然后转换为Scipy中的csr_matrix。这样做对吗?我不能找出如何从头开始构建稀疏矩阵可能是不可能的
非常感谢您的帮助!
scipy
稀疏矩阵包以及MATLAB中的类似程序包基于线性代数问题的思想,例如求解大型稀疏线性方程组(例如有限差分和有限元实现)。因此,像矩阵乘积(numpy数组的dot
乘积)和方程求解器这样的东西得到了很好的发展。
我的粗略经验是,稀疏csr
矩阵乘积必须具有1%的稀疏性,才能比等效的稠密dot
运算更快——换句话说,每99个零就有一个非零值。(但请参阅下面的测试)
但是人们也尝试使用稀疏矩阵来节省内存。但请记住,这样的矩阵必须存储3个值数组(至少是coo
格式)。因此稀疏性必须小于1/3才能开始节省内存。显然,如果您首先构建密集数组,然后再从中创建稀疏数组,您将不会节省内存。
scipy
包实现了许多稀疏格式。coo
格式最容易理解和构建。根据文档构建一个,并查看其.data
、.row
和.col
属性(3个1d数组)。
csr
和csc
通常是根据coo
格式构建的,并对数据进行一点压缩,使其更难理解。但它们具有大部分数学功能。
也可以对csr
格式进行索引,尽管通常这比等效的密集矩阵/阵列情况要慢。其他操作,如更改值(尤其是从0到非零)、串联、增量增长,也较慢。
lil
(列表列表)也很容易理解,最适合增量构建。dok
实际上是一个字典子类。
一个关键点是稀疏矩阵被限制为2d,并且在很多方面表现得像np.matrix
类(尽管它不是一个子类)。
使用scikit-learn
和sparse
搜索其他问题可能是找到使用这些矩阵的优缺点的最佳方式。我已经回答了很多问题,但我更了解"稀疏"的一面,而不是"学习"的一面。我认为它们很有用,但我的感觉是,合身并不总是最好的。任何自定义都在learn
一侧。到目前为止,sparse
软件包尚未针对该应用程序进行优化。
我刚刚尝试了一些矩阵乘积测试,使用sparse.random
方法创建了一个具有指定稀疏性的稀疏矩阵。稀疏矩阵乘法的表现比我预期的要好。
In [251]: M=sparse.random(1000,1000,.5)
In [252]: timeit M1=M*M
1 loops, best of 3: 2.78 s per loop
In [253]: timeit Ma=M.toarray(); M2=Ma.dot(Ma)
1 loops, best of 3: 4.28 s per loop
这是一个规模问题;对于较小的矩阵,密集的dot
是更快的
In [255]: M=sparse.random(100,100,.5)
In [256]: timeit M1=M*M
100 loops, best of 3: 3.24 ms per loop
In [257]: timeit Ma=M.toarray(); M2=Ma.dot(Ma)
1000 loops, best of 3: 1.44 ms per loop
但是比较索引
In [268]: timeit M.tocsr()[500,500]
10 loops, best of 3: 86.4 ms per loop
In [269]: timeit Ma[500,500]
1000000 loops, best of 3: 318 ns per loop
In [270]: timeit Ma=M.toarray();Ma[500,500]
10 loops, best of 3: 23.6 ms per loop
@hpaulj您的时间不对,由于将稀疏随机映射到numpy数组(其缓慢),您得到的结果很慢,请记住:
M=sparse.random(1000,1000,.5)
Ma=M.toarray()
%timeit -n 25 M1=M*M
352 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 25 loops each)
%timeit -n 25 M2=Ma.dot(Ma)
13.5 ms ± 2.17 ms per loop (mean ± std. dev. of 7 runs, 25 loops each)
为了接近numpy,我们需要
M=sparse.random(1000,1000,.03)
%timeit -n 25 M1=M*M
10.7 ms ± 119 µs per loop (mean ± std. dev. of 7 runs, 25 loops each)
%timeit -n 25 M2=Ma.dot(Ma)
11.4 ms ± 564 µs per loop (mean ± std. dev. of 7 runs, 25 loops each)
稀疏矩阵是其中大多数元素为零的矩阵这是确定何时使用稀疏矩阵格式的合适方法吗?只要>50%的值为零?或者只是以防万一有意义吗?
没有一般规则。这完全取决于你以后的确切用法。你必须根据稀疏矩阵和无稀疏矩阵来计算模型的复杂性,然后你才能找到"最佳点"。这将取决于样本数量和尺寸。一般来说,它通常归结为形式的矩阵乘法
X' W
其中X是数据矩阵N X d,W是某个权重矩阵d X K。因此,"密集"乘法需要NdK
时间,而稀疏,假设每行的平均稀疏度为p,则为NpdK
。因此,如果你的稀疏度是50%,你可以期待快2倍的操作。较难的部分是估计稀疏访问的开销,而不是高度优化的基于密集的访问。
在像我这样的任务中,稀疏矩阵对性能有多大帮助,尤其是与numpy数组或标准列表相比?
对于LR的特定情况,这可能比密集格式快几倍,但为了观察差异,您需要大量高维(>100)的数据(>1000)。
到目前为止,我将数据收集到一个numpy数组中,然后在Scipy中转换为csr_matrix。这样做对吗?我不知道如何从头开始构建稀疏矩阵,这可能是不可能的。
不,这不是一个好办法。你可以"从头开始"构建它,例如,首先构建一个字典,然后转换它等等。有很多方法可以在没有密集矩阵的情况下构建稀疏矩阵。