scikit-learn:将数据拟合成块然后立即拟合它们

Dar*_*ter 6 python python-2.7 scikit-learn

我正在使用scikit-learn来构建一个分类器,它可以处理(有点大)文本文件.我现在需要一个简单的词袋功能,因此我尝试使用TfidfVectorizer/HashingVectorizer/CountVectorizer来获取特征向量.

然而,一次处理整个列车数据以获得特征向量导致numpy/scipy中的存储器错误(取决于我使用哪个矢量化器).所以我的问题是:

从原始文本中提取文本特征时:如果我将数据以块的形式拟合到矢量化器,那么它是否与一次拟合整个数据相同?

用代码说明这一点,如下:

vectoriser = CountVectorizer() # or TfidfVectorizer/HashingVectorizer
train_vectors = vectoriser.fit_transform(train_data)
Run Code Online (Sandbox Code Playgroud)

与以下内容不同:

vectoriser = CountVectorizer() # or TfidfVectorizer/HashingVectorizer


start = 0
while start < len(train_data):
    vectoriser.fit(train_data[start:(start+500)])
    start += 500

train_vectors = vectoriser.transform(train_data)
Run Code Online (Sandbox Code Playgroud)

如果这个问题完全被推迟,请提前致谢并对不起.

ldi*_*rer 5

这取决于您使用的矢量化器。

CountVectorizer计算文档中单词的出现次数。它为每个文档输出一个(n_words, 1)向量,其中包含每个单词在文档中出现的次数。n_words文档中的单词总数(也就是词汇表的大小)。
它还适合词汇表,以便您可以内省模型(查看哪个词很重要等)。您可以使用vectorizer.get_feature_names().

当您将其放入前 500 个文档时,词汇表将仅由 500 个文档中的单词组成。假设有 30k 个,fit_transform输出一个500x30k稀疏矩阵。
现在你fit_transform再次使用 500 个下一个文档,但它们只包含 29k 个单词,所以你得到了一个500x29k矩阵......
现在,你如何对齐你的矩阵以确保所有文档都有一致的表示?
我目前想不出一个简单的方法来做到这一点。

使用TfidfVectorizer,您还有另一个问题,那就是逆文档频率:为了能够计算文档频率,您需要一次查看所有文档。
但是 aTfidfVectorizer只是 aCountVectorizer后跟 a TfIdfTransformer,因此如果您设法获得CountVectorizer正确的输出,则可以TfIdfTransformer在数据上应用 a 。

随着HashingVectorizer的东西是不同的:这里没有的词汇。

In [51]: hvect = HashingVectorizer() 
In [52]: hvect.fit_transform(X[:1000])       
<1000x1048576 sparse matrix of type '<class 'numpy.float64'>'
 with 156733 stored elements in Compressed Sparse Row format>   
Run Code Online (Sandbox Code Playgroud)

这里的前 1000 个文档中没有 1M+ 个不同的词,但我们得到的矩阵有 1M+ 列。
HashingVectorizer不字存储在内存中。这使得它的内存效率更高,并确保它返回的矩阵始终具有相同的列数。所以你没有和CountVectorizer这里一样的问题。

这可能是您描述的批处理的最佳解决方案。有几个缺点,即您无法获得 idf 权重,并且您不知道单词和特征之间的映射。

HashingVectorizer文件的引用,做一个例子文本数据外的核心分类。它可能有点乱,但它可以做你想做的事。

希望这可以帮助。

编辑:如果你有太多的数据,HashingVectorizer是要走的路。如果您仍想使用CountVectorizer,一个可能的解决方法是自己适应词汇并将其传递给您的向量化器,这样您只需调用tranform.

这是您可以调整的示例:

import re
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

news = fetch_20newsgroups()
X, y = news.data, news.target
Run Code Online (Sandbox Code Playgroud)

现在不起作用的方法:

# Fitting directly:
vect = CountVectorizer()
vect.fit_transform(X[:1000])
<1000x27953 sparse matrix of type '<class 'numpy.int64'>'
with 156751 stored elements in Compressed Sparse Row format>
Run Code Online (Sandbox Code Playgroud)

注意我们得到的矩阵的大小。
“手动”拟合词汇:

def tokenizer(doc):
    # Using default pattern from CountVectorizer
    token_pattern = re.compile('(?u)\\b\\w\\w+\\b')
    return [t for t in token_pattern.findall(doc)]

stop_words = set() # Whatever you want to have as stop words.
vocabulary = set([word for doc in X for word in tokenizer(doc) if word not in stop_words])

vectorizer = CountVectorizer(vocabulary=vocabulary)
X_counts = vectorizer.transform(X[:1000])
# Now X_counts is:
# <1000x155448 sparse matrix of type '<class 'numpy.int64'>'
#   with 149624 stored elements in Compressed Sparse Row format>
#   
X_tfidf = tfidf.transform(X_counts)
Run Code Online (Sandbox Code Playgroud)

在您的示例中,您需要先构建整个矩阵 X_counts(对于所有文档),然后再应用 tfidf 变换。