保留 TFIDF 结果以使用 Scikit for Python 预测新内容

Posted

技术标签:

【中文标题】保留 TFIDF 结果以使用 Scikit for Python 预测新内容【英文标题】:Keep TFIDF result for predicting new content using Scikit for Python 【发布时间】:2015-06-29 13:10:48 【问题描述】:

我在 Python 上使用 sklearn 进行一些聚类。我已经训练了 200,000 条数据,下面的代码运行良好。

corpus = open("token_from_xml.txt")
vectorizer = CountVectorizer(decode_error="replace")
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
km = KMeans(30)
kmresult = km.fit(tfidf).predict(tfidf)

但是当我有新的测试内容时,我想将它聚集到我训练过的现有集群中。所以我想知道如何保存 IDF 结果,以便我可以为新的测试内容做 TFIDF 并确保新测试内容的结果具有相同的数组长度。

提前致谢。

更新

如果其中一个包含经过训练的 IDF 结果,我可能需要将“transformer”或“tfidf”变量保存到文件(txt 或其他)中。

更新

例如。我有训练数据:

["a", "b", "c"]
["a", "b", "d"]

再做 TFIDF,结果会包含 4 个特征(a,b,c,d)

当我测试

["a", "c", "d"]

查看它属于哪个集群(已经由 k-means 制作)。 TFIDF 只会给出 3 个特征(a,c,d)的结果,因此 k-means 中的聚类会下降。 (如果我测试["a", "b", "e"],可能还有其他问题。)

那么如何存储测试数据的特征列表(更甚者,存储在文件中)?

更新

已解决,请参阅下面的答案。

【问题讨论】:

新内容是什么意思?新的测试内容或培训内容? 新测试内容@user123 我猜您可能无法将新的培训内容附加到以前培训的内容中。你必须用整个训练数据至少训练一次,然后你可以腌制那些训练过的数据,以后可以用它来消除训练延迟。但是当你获得新内容时,你必须至少训练一次 @user123 感谢您的回复。我更新了我的问题。我不会将新的训练内容附加到之前训练的内容中,而是要测试新内容以查看它属于哪个集群,这可能吗? 【参考方案1】:

我通过保存vectorizer.vocabulary_成功保存了功能列表,并被CountVectorizer(decode_error="replace",vocabulary=vectorizer.vocabulary_)重用

代码如下:

corpus = np.array(["aaa bbb ccc", "aaa bbb ddd"])
vectorizer = CountVectorizer(decode_error="replace")
vec_train = vectorizer.fit_transform(corpus)
#Save vectorizer.vocabulary_
pickle.dump(vectorizer.vocabulary_,open("feature.pkl","wb"))

#Load it later
transformer = TfidfTransformer()
loaded_vec = CountVectorizer(decode_error="replace",vocabulary=pickle.load(open("feature.pkl", "rb")))
tfidf = transformer.fit_transform(loaded_vec.fit_transform(np.array(["aaa ccc eee"])))

这行得通。 tfidf 将具有与训练数据相同的特征长度。

【讨论】:

这会保存 tfidf 训练的模型以及生成的 tfidf 矩阵吗? 稍后加载部分是错误的! .. 为什么它是 fit_transform.. 从技术上讲,如果您要转换新的/看不见的数据,它应该只是转换。 如果有人对这里感兴趣是@MANU 所说的解释:fit() 方法计算转换的参数。另一方面,transform() 方法只是根据fit() 方法中计算的参数转换数据集。同样fit_transform() 只是以优化的方式一个接一个地进行。但是在机器学习中,我们根据训练集计算参数。在测试时,我们不计算任何新参数,而是应用从训练集计算的参数来转换测试数据。因此,在测试时我们应该只使用transform() 我尝试了这个例子,因为他们删除了我的一个明显相似的问题,但我总是得到“TF-IDF 矢量化器未安装” @hafiz031 如果你替换 fit_tranform 这个代码不起作用【参考方案2】:

不用CountVectorizer来存储词汇,直接使用tfidfvectorizer的词汇即可。

训练阶段:

from sklearn.feature_extraction.text import TfidfVectorizer

# tf-idf based vectors
tf = TfidfVectorizer(analyzer='word', ngram_range=(1,2), stop_words = "english", lowercase = True, max_features = 500000)

# Fit the model
tf_transformer = tf.fit(corpus)

# Dump the file
pickle.dump(tf_transformer, open("tfidf1.pkl", "wb"))


# Testing phase
tf1 = pickle.load(open("tfidf1.pkl", 'rb'))

# Create new tfidfVectorizer with old vocabulary
tf1_new = TfidfVectorizer(analyzer='word', ngram_range=(1,2), stop_words = "english", lowercase = True,
                          max_features = 500000, vocabulary = tf1.vocabulary_)
X_tf1 = tf1_new.fit_transform(new_corpus)

fit_transform 在这里工作,因为我们使用的是旧词汇。如果您没有存储 tfidf,那么您只需对测试数据使用转换。即使您在那里进行转换,来自测试数据的新文档也正在“适合”火车矢量化器的词汇表。这正是我们在这里所做的。对于 tfidf 矢量化器,我们唯一可以存储和重复使用的是词汇表。

【讨论】:

为什么这里有人说不需要最终的 fit_tranform 并且有人发布代码正在使用它? 顺便说一句,这是唯一有效的方法【参考方案3】:

如果您想存储特征列表以供将来使用的测试数据,您可以这样做:

tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))

#store the content
with open("x_result.pkl", 'wb') as handle:
                    pickle.dump(tfidf, handle)
#load the content
tfidf = pickle.load(open("x_result.pkl", "rb" ) )

【讨论】:

tfidf 不包含功能列表,我已成功保存功能列表以供重复使用,并自己回答了这个问题。谢谢你给了我灵感。【参考方案4】:

一个更简单的解决方案,就像document所说的那样使用joblib库:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.externals import joblib

vectorizer = CountVectorizer()
X = vectorizer.fit_transform(texts)
feature_name = vectorizer.get_feature_names()
tfidf = TfidfTransformer()
tfidf.fit(X)

# save your model in disk
joblib.dump(tfidf, 'tfidf.pkl') 

# load your model
tfidf = joblib.load('tfidf.pkl') 

【讨论】:

【参考方案5】:

您可以在一个阶段完成矢量化和 tfidf 转换:

vec =TfidfVectorizer()

然后对训练数据进行拟合和转换

tfidf = vec.fit_transform(training_data)

并使用tfidf模型进行改造

unseen_tfidf = vec.transform(unseen_data)
km = KMeans(30)
kmresult = km.fit(tfidf).predict(unseen_tfid)

【讨论】:

谢谢。但我想将 tfidf 结果保存到文件(txt 或其他文件)中,稍后再加载。你的意思是重用“vec”变量,但是可以保存吗? 这是 TfidfVectorizer 的标准用法。OP 需要保存和重新加载矢量化器。虽然听起来可能很奇怪,但它对于使用 Amazon Sagemaker 等服务的人很有用,在这些服务中,训练和预测在单独的 ec2 实例上运行。

以上是关于保留 TFIDF 结果以使用 Scikit for Python 预测新内容的主要内容,如果未能解决你的问题,请参考以下文章

如何在 scikit-learn 中的 tfidf 之后查看术语文档矩阵的前 n 个条目

scikit-learn - HashingVectorizer 上的 Tfidf

使用 counts 和 tfidf 作为 scikit learn 的特征

小批量的 Scikit-learn tfidf 矢量化器?

如何使用 scikit-learn 对文本对进行分类?

使用 scikit-learn 进行文本分类:如何从 pickle 模型中获取新文档的表示