2010-03-29 115 views
40

所以,我正在做一些Kmeans分类,使用非常稀疏的numpy数组 - 很多很多的零。我想我会用scipy的'sparse'包来减少存储开销,但是我对如何创建数组而不是矩阵有些困惑。Scipy稀疏...数组?

我已经通过本教程了关于如何创建稀疏矩阵: http://www.scipy.org/SciPy_Tutorial#head-c60163f2fd2bab79edd94be43682414f18b90df7

要模仿一个数组,我只创建一个1×N个矩阵,但正如你可能已经猜到,Asp.dot(BSP)没有按”因为你不能乘以两个1xN矩阵,所以很有效。我不得不将每个数组转换为Nx1,这是非常蹩脚的,因为我会为每个点积计算做这件事。

接下来,我试着创建一个NxN矩阵,其中第1行==第1行(这样您可以乘以两个矩阵,只需将左上角作为点乘积),但事实证明这是真的效率低下。

我很乐意使用scipy的稀疏包作为numpy的数组()的魔术替代品,但是至今我并不确定该怎么做。

有什么建议吗?

+0

请参见下面的注释,但我最终只是滚动了我自己的稀疏矢量实现,一个“dok”矩阵 – spitzanator 2010-03-30 18:55:41

+0

原始问题链接似乎已经死亡。@spitzanator。 – Mark 2016-07-26 13:14:06

回答

31

使用基于行或列的scipy.sparse格式:csc_matrixcsr_matrix

这些使用高效的C语言实现(包括乘法),并且移位是无操作的(特别是如果您调用transpose(copy=False)),就像numpy数组一样。

编辑:通过ipython一些计时:

import numpy, scipy.sparse 
n = 100000 
x = (numpy.random.rand(n) * 2).astype(int).astype(float) # 50% sparse vector 
x_csr = scipy.sparse.csr_matrix(x) 
x_dok = scipy.sparse.dok_matrix(x.reshape(x_csr.shape)) 

现在x_csrx_dok 50%疏:

print repr(x_csr) 
<1x100000 sparse matrix of type '<type 'numpy.float64'>' 
     with 49757 stored elements in Compressed Sparse Row format> 

而且时机:

timeit numpy.dot(x, x) 
10000 loops, best of 3: 123 us per loop 

timeit x_dok * x_dok.T 
1 loops, best of 3: 1.73 s per loop 

timeit x_csr.multiply(x_csr).sum() 
1000 loops, best of 3: 1.64 ms per loop 

timeit x_csr * x_csr.T 
100 loops, best of 3: 3.62 ms per loop 

所以它看起来像我说谎。转置非常便宜,但没有有效的C实现csr * csc(在最新的scipy 0.9.0中)。新的CSR对象在:-(

每个呼叫作为一个黑客构建的(尽管SciPy的相对稳定,这些天),您可以在稀疏的数据直接做点积:

timeit numpy.dot(x_csr.data, x_csr.data) 
10000 loops, best of 3: 62.9 us per loop 

注意这最后一种方法再次进行了一次numpy密集乘法运算,其稀疏性为50%,所以它实际上比dot(x, x)快了2倍。

+5

+1 for plain numpy.dot。对于kmeans,您需要argmax(点(k x N个中心,每个Nvec x));无论如何,中心都会变得密集,所以不妨保持密集。 (虽然为新中心平均许多稀疏的xs是非常缓慢的。) – denis 2011-07-23 16:53:51

+0

好吧,如果我们把乘法速度放在一边,OP可能会使用'scipy.cluster.kmeans' ... – Radim 2011-07-23 20:41:07

+3

合理。我更喜欢(advt)[this code](http://stackoverflow.com/questions/5529625/is-it-possible-to-specify-your-own-distance-function-using-scikits-learn-k-means) ,它可以使用scipy.spatial.distance中的任何20多个度量标准;度量对于高维kmeans比算法更重要。 – denis 2011-07-24 09:58:50

1

您可以创建现有的2D稀疏阵列中的一个子类

from scipy.sparse import dok_matrix 

class sparse1d(dok_matrix): 
    def __init__(self, v): 
     dok_matrix.__init__(self, (v,)) 
    def dot(self, other): 
     return dok_matrix.dot(self, other.transpose())[0,0] 

a=sparse1d((1,2,3)) 
b=sparse1d((4,5,6)) 
print a.dot(b) 
+0

不幸的是,这个问题是你必须在飞行中改变dang的东西,当你进行数百万次比较时,这并没有什么意义。我尝试缓存点产品,但不幸的是,我们不会经常做同样的点产品,所以没有多大帮助。 – spitzanator 2010-03-30 18:53:44

0

我不知道它是真的要好得多或更快,但你可以这样做是为了避免使用转:

Asp.multiply(Bsp).sum() 

这只需要两个矩阵的元素和元素的乘积并对产品进行求和。你可以制作你使用的任何矩阵格式的子类,它具有上述语句作为点积。

但是,它可能只是更容易TRANSPOSE(移调)他们:

Asp*Bsp.T 

似乎并不像这么多的事,但你也可以做一个子类,并修改MUL()方法。

+0

我也尝试,对于一个矢量[1,2,3],从而形成矩阵: [1,2,3] [2,0,0] [3,0,0] 以两个这些和乘以(以任何顺序)在结果矩阵的左上角给出所需的点积。不幸的是,这种速度严重受到负面影响。 – spitzanator 2010-03-30 18:55:12