在python中存储大量的布尔数据

时间:2012-02-11 18:48:48

标签: python arrays numpy

我需要存储稀疏矩阵数据。 数据大小为10^6 10^4列。 在每一列中,我存储一个0的向量,除了少量的值true

然后我需要对每个矩阵中的列求和,并将每一行乘以标量。 我试过字典,但是当我需要求和时,它们会失败。

你会用什么?

PS。 numpy.zeros太小了

3 个答案:

答案 0 :(得分:4)

两句话怎么样?假设这是矩阵(x的{​​{1}}):

True

您只需要存储

   0  1  2  3  4  5  6  7
0  x     x        x 
1     x
2                       x
3              x
4
5
6        x        x
7

您可以轻松将其转换为

rows = {0: [0, 2, 5], 1: [1], 2: [7], 3: [4], 6: [2, 5]}

使用

之类的东西
columns = {0: [0], 1: [1], 2: [0, 6], 4: [3], 5: [0, 6], 7: [2]}

然后对列(columns = {} for row in rows: for column in rows[row]: columns.setdefault(column, []).append(row) )或行进行求和,并将结果乘以您想要的任何值。

答案 1 :(得分:2)

正如其他人所说,你应该看看scipy.sparse

http://docs.scipy.org/doc/scipy/reference/sparse.html

有许多不同的格式针对各种稀疏操作进行了优化,包括标量乘法和求和。

例如:

import scipy.sparse
import numpy as np

rows = np.array([1,100,1000])
cols = np.array([100,99,1474])
vals = np.ones_like(rows)

A = scipy.sparse.coo_matrix((vals,(rows,cols)),shape=(int(1E6),int(1E6)),dtype=np.bool)

然后乘以标量并取总和:

B = 3*A
B.sum() # 9

答案 2 :(得分:1)

根据您的需要,有数百种方法可以做到这一点。维基百科上的Sparse Matrix条目是一个很好的开端,可以找到一种特别适合您需求的方法。

作为一个非常简单的示例,您可以使用Dictionary of Keys类,如下所示:

class SparseDOK(dict):

    def __init__(self):
        pass

    def __setitem__(self,key,value):
        if value in[0,0.0,False,None]:
            dict.__setitem__(self,key,False)
            dict.__delitem__(self,key)
        else:
            dict.__setitem__(self,key,True)

    def __getitem__(self, key):    
        try: 
            return dict.__getitem__(self, key)

        except KeyError: 
            return False


>>> dok=SparseDOK()
>>> dok[10,20]=55
>>> print dok
{(10, 20): True}
>>> print dok[10,20]
True
>>> print dok[55,300]      
False
>>> dok[10,20]=False
>>> print dok[10,20]
False

任意“矩阵”中的每个条目都假定为False,除非特别设置为True。您需要添加错误检查,但这将非常紧凑和快速。

构建Key of Dictionary的优点是非常有效地构建数据结构。您只需要浏览一次原始数据,就可以轻松添加或删除数据。缺点是,一旦构建了矩阵,就会减少对矩阵的交互处理。

由于字典键是元组,因此按行或列添加索引是微不足道的。由于整个矩阵需要在构造之后进行处理才能执行此操作,我们可以构造一个dict,其中包含一次所需的总和或产品,然后参考已处理数据的dict。

>>> dok[10,20]=True
>>> dok[10,2000]=True
>>> dok[11,2000]=True
>>> dok[35000,2000]=True
>>> dok[10,35000]=True
>>> print dok
{(11, 2000): True, (10, 2000): True, (35000, 2000): True, (10, 20): True, (10, 35000): True}
cols={}
for tup in dok.keys():
    if tup[1] not in cols:
        cols[tup[1]]=1
    else:
        cols[tup[1]]+=1    

>>> print cols
{2000: 3, 35000: 1, 20: 1}

现在,您可以在cols中引用col键来获取行的总和。添加产品等是微不足道的。请记住,如果编辑或更改原始DOK,则需要重新计算总和/产品。如果您预计DOK在首次创建后会经常更改,则可以保持运行总计。

如果您的需求更复杂,请考虑使用SciPyPysparse。如您所见,SciPy中有7种不同的稀疏矩阵格式。不要重新发明别人已经做得更好的事情......