![](/img/trans.png)
[英]python - Fastest way to find index of an element in list by comparing to elements of another list
[英]Fastest way to find index of elements in a list
我有一组具有某些功能(例如Y)的示例(例如X),我需要在上面运行一些机器学习算法(例如PCA)。 一种方法是生成矩阵(样本,特征)。 我构建矩阵的方法涉及2个步骤:
例如:考虑以下示例
sample1 = A, B, D
sample2 = A, C, E
sample3 = A, C, D
生成矩阵
生成此矩阵的挑战在于数据非常庞大。 行数为465337 ,列数为35526155 。
生成池大约花费了20分钟,即使这很慢,我也很满意。 但是,当生成矩阵的向量(即行)时,我必须考虑样本中的所有值,以得到池中该值的索引。
这花费了大量时间。 有没有更好的方法来查找元素索引? 如果程序本身不是最佳方法,请让我知道生成矩阵的更好方法。
另外,我只是存储索引并从中构造CSR矩阵,而不是密集矩阵。
您可以使用scikit-learn的Count Vectorizer实现这种类型的编码。 请参阅此处的示例用例。 因为您提到了机器学习并且正在使用Python,所以我认为您通常对sklearn熟悉。
但是,由于CountVectorizer用于文本标记,因此将其用于您的问题有点麻烦。
例如,如果您使用以下格式输入数据:
samples = [['A', 'B', 'D'],
['A', 'C', 'E'],
['A', 'C', 'D']]
您应该首先将内部列表转换为字符串:
samples_s = ["".join(l) for l in samples]
这使
['ABD', 'ACE', 'ACD']
现在,您可以适合CountVectorizer的实例。 您只需要定义什么构成令牌。 在这里,我使用了一个简单的正则表达式来定义任何单个字符(例如“ A”,“ B”或“ C”)作为标记。 您还可以提供静态词汇表。
vec = CountVectorizer(token_pattern='.')
X = vec.fit_transform(samples_s)
调用X.toarray()
返回
array([[1, 1, 0, 1, 0],
[1, 0, 1, 0, 1],
[1, 0, 1, 1, 0]], dtype=int64)
使用sklearn的实现应该比自己进行编码要快得多。
正如我在评论中提到的那样,您希望为此使用sklearn.feature_extraction.text.CountVectorizer
,并带有binary=True
参数,因为您实际上并不希望计数。 您将创建编码并输出稀疏矩阵以启动!
但是,如果您对方法的基本问题感兴趣,从根本上讲,问题是您使用的是序列类型 , list
,其中.index
方法是线性时间操作。 当您尝试使用列表时,您会感到这一事实的痛苦。 以下是仅使用字典即可如何更有效地执行此操作的示意图 :
In [15]: tokens = list('qwertydfgndjfkgnf')
In [16]: pool = {}
In [17]: for t in tokens:
...: pool.setdefault(t, len(pool))
...:
In [18]: pool
Out[18]:
{'d': 6,
'e': 2,
'f': 7,
'g': 8,
'j': 10,
'k': 11,
'n': 9,
'q': 0,
'r': 3,
't': 4,
'w': 1,
'y': 5}
In [19]: tokens.index('g') # ew, O(n) time complexity
Out[19]: 8
In [20]: pool['g'] # nice! O(1) time complexity
Out[20]: 8
现在,该池包含从标记到索引的编码。 在这里访问索引是一个固定时间的操作。 这将大大提高性能。 事实上,因为我们只是做一个dict
,首先,从一个不转换set
到一个list
,这将通过大量的减少您的持续性因素。
请注意,以上内容实质上是sklearn
对象正在执行的操作。
https://github.com/scikit-learn/scikit-learn/blob/ab93d65/sklearn/feature_extraction/text.py#L745
但是请注意,它们使用defaultdict
,它通过以下令人愉悦的小方法针对此类情况进行了优化:
In [24]: from collections import defaultdict
In [25]: pool = defaultdict()
In [26]: pool.default_factory = pool.__len__
In [27]: for t in tokens:
...: pool[t]
...:
In [28]: pool
Out[28]:
defaultdict(<method-wrapper '__len__' of collections.defaultdict object at 0x1088aa9f8>,
{'d': 6,
'e': 2,
'f': 7,
'g': 8,
'j': 10,
'k': 11,
'n': 9,
'q': 0,
'r': 3,
't': 4,
'w': 1,
'y': 5})
当它们在文档上循环时,它们还会构建稀疏表示,因此它们实际上仅对数据集进行一次传递。 因此,sklearn对象的优化程度与您将要获得的优化程度一样。 sklearn的源代码实际上是很容易上手的,值得检查一下它们仅使用不带Cython扩展或任何内容的纯python完成的工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.