我有一组样本(比如X)和一些特征(比如说Y),我需要运行一些机器学习算法(比如说PCA)。一种方法是生成矩阵(样本,特征)。我构建矩阵的方法包括两个步骤:
例如:考虑以下示例
sample1 = A, B, D
sample2 = A, C, E
sample3 = A, C, D
生成矩阵
生成此矩阵的挑战在于,数据非常庞大。行数 465337 ,列数 35526155 。
生成池需要大约20分钟,即使这很慢,我也很好。但是当生成矩阵的向量(即行)时,我必须得到所考虑的池中该值的索引的所有值。
这需要很长时间。有没有更好的方法来找到元素的索引?如果程序本身不是最佳的,请告诉我生成矩阵的更好方法。
另外,我只是存储索引并从中构建CSR矩阵而不是密集矩阵。
答案 0 :(得分:1)
您可以使用scikit-learn Count Vectorizer来实现此类编码。有关示例用例,请参阅here。因为你提到机器学习并且正在使用Python,所以我认为你一般都熟悉sklearn。
但是,由于CountVectorizer用于文本标记化,因此将它用于您的问题有点麻烦。
例如,如果您的输入数据采用以下格式:
samples_s = ["".join(l) for l in samples]
您应该首先将内部列表转换为字符串:
['ABD', 'ACE', 'ACD']
给出了
vec = CountVectorizer(token_pattern='.')
X = vec.fit_transform(samples_s)
现在您可以安装CountVectorizer的实例。您只需定义构成令牌的内容即可。在这里,我使用一个简单的正则表达式来定义任何单个字符(例如" A"," B"或" C")作为标记。您还可以提供静态词汇表。
X.toarray()
调用array([[1, 1, 0, 1, 0],
[1, 0, 1, 0, 1],
[1, 0, 1, 1, 0]], dtype=int64)
返回
{{1}}
使用sklearn的实现应该比自己编码快得多。
答案 1 :(得分:1)
正如我在评论中提到的那样,您希望使用sklearn.feature_extraction.text.CountVectorizer
来使用binary=True
参数,因为您实际上并不需要计数。你创建你的编码和输出一个稀疏矩阵来启动!
但是,如果您对方法的根本问题感兴趣,那么从根本上说问题是您使用序列类型,list
,其中.index
方法是线性时间操作。当您尝试使用列表时,您会感受到这种事实的痛苦。这是一个 sketch ,它是如何使用字典更有效地实现这种方式的:
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完成的任务。