Python 有人能解释一下字典和矩阵大小的区别吗?

Python 有人能解释一下字典和矩阵大小的区别吗?,python,dictionary,size,Python,Dictionary,Size,我正在为工作创建一个推荐引擎,最终得到了一个8000×8000项的相似性矩阵。矩阵非常稀疏,因此我开始制作一个包含多个键的字典,其中每个键指向一个列表,该列表是产品推荐的排序数组(以元组的形式)。我让它工作,见下文 In [191]: dictionary["15454-M6-ECU2="] Out[191]: [('15454-M-TSCE-K9=', 0.8), ('15454-M2-AC=', 0.52), ('15454-M6-DC-RF', 0.45), ('15454-M6-

我正在为工作创建一个推荐引擎,最终得到了一个8000×8000项的相似性矩阵。矩阵非常稀疏,因此我开始制作一个包含多个键的字典,其中每个键指向一个列表,该列表是产品推荐的排序数组(以元组的形式)。我让它工作,见下文

In [191]: dictionary["15454-M6-ECU2="]
Out[191]: 
[('15454-M-TSCE-K9=', 0.8),
 ('15454-M2-AC=', 0.52),
 ('15454-M6-DC-RF', 0.45),
 ('15454-M6-ECU2=', 0.63)]
然而,我现在在解释结果时遇到了一个问题:

In [204]: sys.getsizeof(dictionary)
Out[204]: 786712

In [205]: sys.getsizeof(similarity_matrix)
Out[205]: 69168

尽管我消除了大量的零(每个零用32位或64位表示),为什么即使我们消除了矩阵中的稀疏性,对象大小还是增加了

sys.getsizeof
只返回容器的大小,而不是容器加上内部项目的大小。无论包含值的大小如何,dict都返回相同的大小,并且每个键/值对仅返回98字节。它存储对键的引用和对值的引用以及散列/存储桶的其他开销

>>> sys.getsizeof(dict((i,'a'*10000) for i in range(8000)))
786712
>>> sys.getsizeof(dict((i,'a'*1) for i in range(8000)))
786712
>>> 786712/8000
98
元组要小得多,只存储引用本身

>>> sys.getsizeof(tuple((i,'a'*10000) for i in range(8000)))
64056
>>> sys.getsizeof(tuple((i,'a'*1) for i in range(8000)))
64056
>>> 64056/8000
8

根据字典的大小,似乎每个可能的键都有一个键/值对(即使没有其他与该键类似的键)

我想您的代码应该是这样的:

# initialise sparse dict with one empty list of similar nodes for each node
sparse_dict = dict((key, []) for key in range(1000))
sparse_dict[0].append((2, 0.5)) # 0 is similar to 2 by 50%

def get_similarity(d, x, y):
    for key, value in d[x]:
        if key == y:
            return value
    return 0

assert get_similarity(sparse_dict, 0, 1) == 0
assert get_similarity(sparse_dict, 0, 2) == 0.5
然而,使用
dict
get
方法,您甚至可以实现更稀疏的字典

# initialise empty mapping -- literally an empty dict
very_sparse_dict = {}
very_sparse_dict[0] = [(2, 0.5)] # 0 is similar to 2 by 50%

def get_similarity2(d, x, y):
    for key, value in d.get(x, ()):
        if key == y:
            return value
    return 0

# 0 not linked to 1, so 0% similarity
assert get_similarity2(very_sparse_dict, 0, 1) == 0
# 0 and 2 are similar
assert get_similarity2(very_sparse_dict, 0, 2) == 0.5
# 1 not similar to anything as it is not even present in the dict
assert get_similarity2(very_sparse_dict, 1, 2) == 0
每个dict的大小为:

>>>> print("sparse_dict:", sys.getsizeof(sparse_dict))
sparse_dict: 49248
>>> print("very_sparse_dict", sys.getsizeof(very_sparse_dict))
very_sparse_dict: 288

字典键可能会占用大量空间,如果问题出在
getsizeof
上,您可以尝试使用数字键,它只返回给定对象的大小,不包括它引用的任何对象。例如,
getsizeof([1,2])>getsizeof([[1,2,3,4,5]])
是正确的,因为第一个列表包含两个元素,而第二个(根)列表只包含一个元素。我想你所展示的是,如果你不实际填写相似性dict,它会小得多。假设所有产品至少有一个相似性,那么您就回到了完整的目录。