我正在尝试构建一个算法,根据我之前喜欢的文章来预测我是否会喜欢一篇新文章。
例如:
- 我阅读了50篇文章,喜欢了其中的10篇。我告诉我的程序我喜欢这些文章。
- 然后有20篇新文章到来。我的程序需要根据我之前喜欢的10篇文章,为每篇新文章提供一个“喜欢的百分比”。
我在这里找到了一些线索:Python: tf-idf-cosine: 查找文档相似性
>>> from sklearn.feature_extraction.text import TfidfVectorizer>>> from sklearn.datasets import fetch_20newsgroups>>> twenty = fetch_20newsgroups()>>> tfidf = TfidfVectorizer().fit_transform(twenty.data)
然后,要将数据集中的第一篇文档与数据集中的其他文档进行比较:
>>> from sklearn.metrics.pairwise import linear_kernel>>> cosine_similarities = linear_kernel(tfidf[0:1], tfidf).flatten()>>> cosine_similaritiesarray([ 1. , 0.04405952, 0.11016969, ..., 0.04433602, 0.04457106, 0.03293218])
对于我的情况,我认为我会做的就是将我的10篇文章的文本连接起来,运行TfidfVectorizer,然后将这个大的向量与每篇新来的文章进行比较。
但我不知道比较是如何进行的:
- 大的向量(10篇文章)与小的向量(一篇新文章)进行比较,或者
- 小的向量与大的向量进行比较
我不知道你是否明白我的意思,但在第一种情况下,大向量中90%的词不会出现在小向量中。
所以我的问题是:余弦相似度是如何计算的?你对我这个项目有更好的方法吗?
回答:
朴素贝叶斯分类器应该表现得更好。你的问题类似于经典的垃圾邮件分类问题。在你的情况下,你不是在识别垃圾邮件(你不喜欢的内容),而是识别正常邮件(你喜欢的文章)。
从前50篇标记过的文章中,很容易计算出以下统计数据:
p(word1|like) -- 在我喜欢的所有文章中,word1出现的概率p(word2|like) -- 在我喜欢的所有文章中,word2出现的概率...p(wordn|like) -- 在我喜欢的所有文章中,wordn出现的概率p(word1|unlike) -- 在我不喜欢的所有文章中,word1出现的概率...p(like) -- 我喜欢的文章的比例(在你的例子中应该是0.2)p(unlike) -- 我不喜欢的文章的比例(0.8)
然后,给定第51篇新文章,你应该在其中找到所有已见的词,例如,它只包含word2和word5。朴素贝叶斯的优点之一是它只关心词汇表中的词。即使大向量中超过90%的词不会出现在新文章中,这也不是问题,因为所有不相关的特征会相互抵消,不影响结果。
似然比将是
prob(like|51th article) p(like) x p(word2|like) x p(word5|like) ---------------------------- = ----------------------------------------- prob(unlike|51th article) p(unlike)xp(word2|unlike)xp(word5|unlike)
只要比率大于1,你就可以预测这篇文章为“喜欢”。此外,如果你想提高识别“喜欢”文章的精确度,你可以通过将阈值比率从1.0增加到更大的值来调整精确度-召回率平衡。反之,如果你想提高召回率,你可以降低阈值等。
关于文本领域的朴素贝叶斯分类,请参阅这里的进一步阅读内容。
这个算法可以很容易地修改为在线学习,即一旦用户“喜欢”或“不喜欢”一个新示例,就更新学习模型。因为上述统计表中的所有内容基本上都是归一化的计数。只要你保存每个词的计数和总计数,你就可以在每个实例的基础上更新模型。
要在朴素贝叶斯中使用词的tf-idf权重,我们将权重视为词的计数。即,没有tf-idf时,每个文档中的每个词计数为1;使用tf-idf时,文档中的词按其TF-IDF权重计数。然后你可以使用相同的公式得到朴素贝叶斯的概率。这个想法可以在这篇论文中找到。我认为scikit-learn中的多项式朴素贝叶斯分类器应该可以接受tf-idf权重作为输入数据。
查看MultinomialNB的注释:
多项式朴素贝叶斯分类器适用于具有离散特征的分类(例如,文本分类的词计数)。多项式分布通常需要整数特征计数。然而,在实践中,像tf-idf这样的分数计数也可能有效。