如何有效地在python中创建大型列表列表?

alv*_*vas 10 python list matrix nested-lists scipy

我有这样的数据:

data = {'x':Counter({'a':1,'b':45}), 'y':Counter({'b':1, 'c':212})}
Run Code Online (Sandbox Code Playgroud)

我的标签是其中的键,data内部字典的键是功能:

all_features = ['a','b','c']
all_labels = ['x','y']
Run Code Online (Sandbox Code Playgroud)

我需要创建列表列表:

[[data[label][feat] for feat in all_features] for label in all_labels]
Run Code Online (Sandbox Code Playgroud)

[OUT]:

[[1, 45, 0], [0, 1, 212]]
Run Code Online (Sandbox Code Playgroud)

len(all_features)的约为5,000,000,len(all_labels)约为100,000

最终目的是创建scipy稀疏矩阵,例如:

from collections import Counter
from scipy.sparse import csc_matrix
import numpy as np


all_features = ['a','b','c']
all_labels = ['x','y']

csc_matrix(np.array([[data[label][feat] for feat in all_features] for label in all_labels]))
Run Code Online (Sandbox Code Playgroud)

但循环遍历大量列表是相当低效的.

那么如何才能有效地查看大量列表呢?

是否有其他方法可以创建scipy矩阵,而data无需循环遍历所有功能和标签?

Jai*_*ime 8

正如您所经历的那样,将词典字典转换为numpy或scipy数组并不是太有趣.如果你知道all_features并且all_labels事先知道,你可能最好从一开始就使用scipy稀疏COO矩阵来保持你的计数.

无论是否可行,您都希望按排序顺序保留功能和标签列表,以加快查找速度.所以我假设以下内容不会改变任何一个数组:

all_features = np.array(all_features)
all_labels = np.array(all_labels)
all_features.sort()
all_labels.sort()
Run Code Online (Sandbox Code Playgroud)

让我们data按照它们存储在字典中的顺序提取标签,并查看all_labels每个项目的位置:

labels = np.fromiter(data.iterkeys(), all_labels.dtype, len(data))
label_idx = np.searchsorted(all_labels, labels)
Run Code Online (Sandbox Code Playgroud)

现在让我们计算每个标签有多少个特征,并从中计算稀疏数组中非零项的数量:

label_features = np.fromiter((len(c) for c in data.iteritems()), np.intp,
                             len(data))
indptr = np.concatenate(([0], np.cumsum(label_features)))
nnz = indptr[-1]
Run Code Online (Sandbox Code Playgroud)

现在,我们提取每个标签的功能及其相应的计数

import itertools
features_it = itertools.chain(*(c.iterkeys() for c in data.itervalues()))
features = np.fromiter(features_it, all_features.dtype, nnz)
feature_idx = np.searchsorted(all_features, features)
counts_it = itertools.chain(*(c.itervalues() for c in data.itervalues()))
counts = np.fromiter(counts_it, np.intp, nnz)
Run Code Online (Sandbox Code Playgroud)

有了我们所拥有的,我们可以直接创建CSR矩阵,标签为行,功能为列:

sps_data = csr_matrix((counts, feature_idx, indptr),
                      shape=(len(all_labels), len(all_features)))
Run Code Online (Sandbox Code Playgroud)

唯一的问题是这个稀疏数组的行不是按顺序排列all_labels,而是按顺序迭代时出现的顺序排列data.但我们feature_idx告诉我们每个标签最终在哪里,我们可以通过以下方式重新排列行:

sps_data = sps_data[np.argsort(label_idx)]
Run Code Online (Sandbox Code Playgroud)

是的,它是混乱的,令人困惑的,可能不是很快,但它的工作原理,它会比你在你的问题中提出的内存效率更高:

>>> sps_data.A
array([[  1,  45,   0],
       [  0,   1, 212]], dtype=int64)
>>> all_labels
array(['x', 'y'], 
      dtype='<S1')
>>> all_features
array(['a', 'b', 'c'], 
      dtype='<S1')
Run Code Online (Sandbox Code Playgroud)