如何根据现有模型标记(预测)一组看不见的数据?

数据挖掘 分类 scikit-学习 多标签分类
2022-03-03 10:03:59

我正在从事一个学习多标签分类项目,为此我采用了 16K 行文本并手动对它们进行分类,实现了大约 94% 的准确率/召回率(在三个模型中)。

我会说好的结果。

然后我虽然已经准备好使用我的模型来预测一组新的相似文本的标签,但以前没有看到/预测过。但是,似乎 - 至少对于 sklearns 模型 - 我不能简单地对新数据集运行预测,因为预测标签数组的大小不同。

我肯定错过了一些东西,但在这个阶段我想知道考虑到我一直认为分类会对这样的任务有所帮助。如果我需要知道“答案”,我很难理解这种方法的好处。

下面简而言之采取的方法:

from gensim import corpora

corpus = df_train.Terms.to_list()

# build a dictionary
texts = [
    word_tokenizer(document, False)
    for document in corpus
]

dictionary = corpora.Dictionary(texts)

from gensim.models.tfidfmodel import TfidfModel

# create the tfidf vector
new_corpus = [dictionary.doc2bow(text) for text in texts]
tfidf_model = TfidfModel(new_corpus, smartirs='Lpc')
corpus_tfidf = tfidf_model[new_corpus]

# convert into a format usable by the sklearn
from gensim.matutils import corpus2csc

X = corpus2csc(corpus_tfidf).transpose()


# Let fit and predict

from sklearn.naive_bayes import ComplementNB
clf = ComplementNB()
clf.fit(X.toarray(), y) 

y_pred = clf.predict(X.toarray())

# At this stage I have my model with the 16K text label.

# Running again almost the above code till X = corpus2csc(corpus_tfidf).transpose().
# Supplying a new dataframe should give me a new vector that I can predict via the clf.predict(X.toarray())

corpus = df.Query.to_list()

# build a dictionary
.....
.....

X = corpus2csc(corpus_tfidf).transpose()
y_pred = clf.predict(X.toarray()) # here I get the error

在此处输入图像描述

所以在使用df_train(shape (16496, 2)) 时一切正常,当我用我的新数据集df(shape (831, 1) 重复上述操作时,我得到了上面提到的错误。当然,第二维第一个数据集是包含标签的数据集,与 fit 方法一起使用,因此问题不存在。

错误是由于一个小得多的语料库只生成了 778 列,而第一组 16k 行的数据生成了 3226 列。这是因为我在使用 TF-IDF 赋予术语一些重要性之后,对我的语料库进行了矢量化处理。也许这是错误?

我知道有像 PCS 这样的模型可以降低维度,但我不确定相反的情况。

任何人都可以解释一下吗?

更新

Nicholas 帮助找出了错误在哪里,尽管现在总是出现一个新错误,这与一些缺失的列有关。

请参阅下面的代码和错误。

from gensim import corpora

corpus = df_train.Terms.to_list()

# build a dictionary
texts = [
    word_tokenizer(document, False)
    for document in corpus
]

dictionary = corpora.Dictionary(texts)

from gensim.models.tfidfmodel import TfidfModel

# create the tfidf vector
new_corpus = [dictionary.doc2bow(text) for text in texts]
tfidf_model = TfidfModel(new_corpus, smartirs='Lpc')
corpus_tfidf = tfidf_model[new_corpus]

# convert into a format usable by the sklearn
from gensim.matutils import corpus2csc

X = corpus2csc(corpus_tfidf).transpose()


# Let fit and predict

from sklearn.naive_bayes import ComplementNB
clf = ComplementNB()
clf.fit(X.toarray(), y) 

y_pred = clf.predict(X.toarray())

# At this stage I have my model with the 16K text label.

corpus = df.Query.to_list()

unseen_tokens = [word_tokenizer(document, False) for document in corpus]
unseen_bow = [dictionary.doc2bow(t) for t in unseen_tokens]
unseen_vectors = tfidf_model[unseen_bow]
X = corpus2csc(unseen_vectors).transpose() # here I get the errors in the first screenshot

y_pred = clf.predict(X.toarray()) # here I get the errors in the second screenshot

在此处输入图像描述

在此处输入图像描述

更新 2

我还尝试了第二种方法,使用来自 sklearn 的 TfidfVectorizer。我这样做是为了以防我在之前的实现中遗漏了一些明显的东西(你知道...... KISS 方法)。

在那种情况下,输出符合预期,我得到了一个预测。corpus2csc所以不确定,但我怀疑图书馆的某个地方有问题。

更新 3如果您想尝试,请在此处此处 上传数据集。这里也有一个要点

干杯

2个回答

当您将模型应用于看不见的数据时,您需要使用在训练期间用于创建 tfidf 矩阵的相同预处理元素(字典等)。

不要为看不见的数据创建新的字典、tfidf_model 等,否则

  • 您传递给模型的数据的维度可能不同。
  • 您将丢失通过对训练数据执行 tfidf 获得的信息

直线后

corpus = df.Query.to_list()

你想要类似的东西

unseen_tokens = [word_tokenizer(document, False) for document in corpus]
unseen_bow = [dictionary.doc2bow(t) for t in unseen_tokens]
unseen_vectors = tfidf_model[unseen_bow]

即不创建新的 tfidf 模型或新字典 - 使用您在训练中创建和使用的那些。

感谢@Nicholas 让自己走上了正确的道路。

关于为什么这不适用于 Corpora 模型的具体答案取决于我随着时间的推移所猜测的内容。corpus2csc是一种压缩/忘记一些细节的方式。

解决方案是在转置值时指定字典的长度。
因此,从X = corpus2csc(unseen_vectors).transpose()代码必须成为X = corpus2csc(unseen_vectors, num_terms=len(dictionary)).transpose().

希望有一天这可以帮助某人。

所以