【发布时间】:2019-06-03 19:44:25
【问题描述】:
我有一个字典列表,其中的值始终为整数,键为一些字符串。我们可以将其解释为一个矩阵,其中每个字典是一行,每一列对应于至少属于其中一个字典的键。字典表示多项式,其中键是单项式,值是系数。
例如[{'x':1, 'y':1, 'z':2}, {'x': 2}, {'y':1, 'z':3}]对应矩阵:
[ 1 1 2,
2 0 0,
0 1 3 ]
我经常做这个操作,我需要一个高性能的解决方案。矩阵不是很大,所以我需要一个最小化开销的解决方案。目前,一些计算将大约三分之一的时间花在字典的向量化上。
这基本对应sklearn.feature_extraction.DictVectorizer。我在 sagemath 工作,它不附带 sci-kit learn,所以使用它并不理想。此外,DictVectorizer 构建了一个稀疏矩阵,然后将其转换为密集矩阵。我自己尝试了这种方法,但由于额外的开销很大,所以速度较慢。
我目前的算法如下:
def dictionary_vectorizer(list_of_dicts):
# Make a list of all the keys occurring in the dictionaries
keys = set()
for dic in list_of_dicts:
for key in dic.keys():
keys.add(key)
# Create a mapping keys -> column_index
key_map = {key: index for index, key in enumerate(keys)}
output = np.zeros((len(list_of_dicts), len(keys)))
for row_number, dic in enumerate(list_of_dicts):
for key, value in dic.items():
output[row_number, key_map[key]] = value
return output
在我的实际代码中,我使用 sagemath 的 matrix 构造函数而不是 np.zeros,但它并没有太大变化。似乎初始化一个零矩阵,然后编辑行并不是最快的方法。逐行计算矩阵,然后将结果连接起来给出相同的速度。
有没有明显的方法可以加快速度(同时保持低开销)?
【问题讨论】:
-
稀疏矩阵的创建速度并不快。
dok矩阵是dict的子类,但没有实现update(因为它想验证值)。创建后,dok仍需转换为csr格式,然后再转换为toarray()。鉴于您的映射的非传统性质,我认为您的代码与您将获得的一样好。 -
您可以使用
keys = set(itertools.chain.from_iterable(e.keys() for e in a))减少一些开销 -
如何定义键和列索引之间的映射?是字典顺序吗?
-
顺序与具体问题无关。无论如何,填充矩阵似乎是最耗时的,而不是找到键集。