python:我可以在不(明确地)使用整数索引的情况下使用稀疏矩阵表示吗?

python: can I have a sparse matrix representation without (explicitly) using integer indices?

我有一个数据集,它本质上是一个表示两组元素之间关系的稀疏二进制矩阵。例如,让第一组是人(用他们的名字表示),例如像这样:

people = set(['john','jane','mike','joe'])

第二组是一组二进制属性,例如

attrs = set(['likes_coffee','has_curly_hair','has_dark_hair','drives_car','man_u_fan'])

数据集由制表符分隔的数据文件表示,该文件为每个人分配了一些属性,例如

john    likes_coffee
john    drives_car
john    has_curly_hair
jane    has_curly_hair
jane    man_u_fan
...

attrs大约有30,000个元素,people可以和6,000,000一样大,但是数据是稀疏的,即每个人最多有30-40个属性

我正在 python 中寻找数据 structure/class,它可以让我:

我当前的实现对两个集合使用一对数组和一个 scipy 稀疏矩阵。所以如果

people = ['john','jane','mike','joe']
attrs = ['likes_coffee','has_curly_hair','has_dark_hair','drives_car','man_u_fan']

然后我将创建一个大小为 4 X 5 的稀疏矩阵 data,上面显示的示例数据将对应于元素

data[0,0]
data[0,3]
data[0,1]
data[1,1]
data[1,4]
...

我还维护了两个反向索引,这样我就不必经常调用 people.index('mike')attrs.index('has_curly_hair')

这工作正常,但我必须明确维护索引。这很麻烦,例如,当我有两个具有不同人 and/or 属性集的数据集并且我需要匹配来自两个稀疏矩阵的相同 person/attribute 对应的 rows/columns 时。

那么有没有一种替代方法可以让我避免使用整数索引,而是使用两个集合的实际元素来提取 rows/columns,即类似

data['john',:]  # give me all attributes of 'john'
data[:,['has_curly_hair','drives_car']] # give me all people who 'has_curly_hair' or 'drives_car'

?

其中一种 sparse 格式实际上是字典。 dok_matrix 是一个字典子类,其中键的形式为 (1,100)(30,334)。这是 i,j 索引的元组。

但我在其他 SO 问题中发现,访问这种格式的元素实际上比常规字典访问要慢。也就是说 d[1,100] 比等效的 dd[(1,100)] 慢。我发现建立一个正则字典是最快的,然后使用 update 将值添加到稀疏 dok.

但是如果您想将矩阵转换为计算友好的格式之一,例如 csrdok 会很有用。当然,您可以使用 d[100,:] 访问稀疏矩阵,这对于常规字典来说是不可能的。

对于某些用途,默认词典可能既快捷又有用。换句话说,一个字典,其中键是 'people',值是列表或其他具有 'attribute' 键的字典。

不管怎么说,稀疏矩阵没有提供词索引。请记住,它的根源在于线性代数,计算矩阵乘积和大型稀疏数字矩阵的逆。它用于文本数据库的时间相对较新。

假设没有库完全符合您的要求,您可以创建自己的 class SparseMatrix 并重载运算符 []。这是一种方法(构造函数可能与您想要的不同):

class SparseMatrix():
    def __init__(self, x_label, y_label):
        self.data = {}
        for x,y in zip(x_label,y_label):
            print x,y
            self.data[x] = {}
            for attr in y:
                self.data[x][attr] = 1
        return

    def __getitem__(self, index):
        x,y = index
        if type(x) is str:
            if type(y) is str:
                return 1 if y in self.data[x] else 0
            if type(y) is slice:
                return self.data[x].keys()
        if type(x) is slice:
            if type(y) is str:
                res = []
                for key in self.data.keys():
                    if y in self.data[key]:
                        res.append(key)
                return res
            if type(y) is list:
                res = []
                for attr in y:
                    res += self.__getitem__((x,attr))
                return res

在 REPL 中,我得到:

> data = SparseMatrix(['john','jane','mike','joe'],[['likes_coffee','has_curly_hair'],['has_dark_hair'],['drives_car'],['man_u_fan']])

> data['john',:]
['has_curly_hair', 'likes_coffee']

> data[:,['has_curly_hair','drives_car']]
['john', 'mike']