从文本内容生成标签
我很好奇有没有一种算法或方法,可以从给定的文本中生成关键词或标签,可能会用到一些权重计算、出现频率或者其他工具。
另外,如果你能推荐一些基于Python的解决方案或库,我会非常感激。
谢谢!
5 个回答
http://en.wikipedia.org/wiki/Latent_Dirichlet_allocation 这个方法试图把每个文档看作是多个主题的组合,而这些主题又是将单词和概率联系起来的分布。
我曾经用这个方法分析过一堆产品评论,找出这些评论中提到的潜在想法,比如“客户服务”、“产品易用性”等等。这个基本模型并没有提供一种方法来用一个单词来描述某个主题的内容,但人们在模型训练完成后,想出了各种各样的技巧来做到这一点。
我建议你试试 http://mallet.cs.umass.edu/,看看这个模型是否适合你的需求。
LDA是一种完全不需要监督的算法,这意味着你不需要手动标注任何东西,这点很好,但另一方面,它可能不会给你提供你期待的主题。
首先,处理语言的关键Python库是NLTK(“自然语言工具包”)。这是一个稳定且成熟的库,由专业的计算语言学家创建和维护。它还有丰富的教程、常见问题解答等资源,我非常推荐使用。
下面是一个简单的模板,使用Python代码来解决你提问中的问题;虽然它是一个模板,但可以运行——只需提供任何文本作为字符串(就像我做的那样),它就会返回一个单词频率的列表,以及一个根据非常简单的规则排列的“重要性”(或作为关键词的适用性)排名列表。
给定文档的关键词(显然)是从文档中重要的单词中选择的——也就是说,这些单词能够将该文档与其他文档区分开来。如果你对文本的主题没有任何先验知识,一种常见的技巧是根据单词的出现频率来推断其重要性或权重,公式是:重要性 = 1/频率。
text = """ The intensity of the feeling makes up for the disproportion of the objects. Things are equal to the imagination, which have the power of affecting the mind with an equal degree of terror, admiration, delight, or love. When Lear calls upon the heavens to avenge his cause, "for they are old like him," there is nothing extravagant or impious in this sublime identification of his age with theirs; for there is no other image which could do justice to the agonising sense of his wrongs and his despair! """
BAD_CHARS = ".!?,\'\""
# transform text into a list words--removing punctuation and filtering small words
words = [ word.strip(BAD_CHARS) for word in text.strip().split() if len(word) > 4 ]
word_freq = {}
# generate a 'word histogram' for the text--ie, a list of the frequencies of each word
for word in words :
word_freq[word] = word_freq.get(word, 0) + 1
# sort the word list by frequency
# (just a DSU sort, there's a python built-in for this, but i can't remember it)
tx = [ (v, k) for (k, v) in word_freq.items()]
tx.sort(reverse=True)
word_freq_sorted = [ (k, v) for (v, k) in tx ]
# eg, what are the most common words in that text?
print(word_freq_sorted)
# returns: [('which', 4), ('other', 4), ('like', 4), ('what', 3), ('upon', 3)]
# obviously using a text larger than 50 or so words will give you more meaningful results
term_importance = lambda word : 1.0/word_freq[word]
# select document keywords from the words at/near the top of this list:
map(term_importance, word_freq.keys())
一种方法是找出在文档中出现频率比你预期的要高的词。比如说,在一大堆文档中,'Markov'这个词几乎从未出现过。但是在同一组文档中的某个特定文档里,Markov却频繁出现。这就说明,Markov可能是一个很好的关键词或标签,可以和这个文档关联起来。
要识别这样的关键词,你可以使用关键词和文档之间的点对点互信息。这个计算公式是 PMI(term, doc) = log [ P(term, doc) / (P(term)*P(doc)) ]
。这个公式大致上可以告诉你,在特定文档中遇到这个词时,你的惊讶程度比在大集合中遇到它时要少(或多)多少。
如果你想找出与文档关联的5个最佳关键词,只需根据它们与文档的PMI分数进行排序,选择分数最高的5个即可。
如果你想提取多词标签,可以查看StackOverflow上的问题如何从一系列文本条目中提取常见/重要短语。
借用我对那个问题的回答,NLTK的搭配使用指南介绍了如何用大约7行代码提取有趣的多词表达,使用的是n-gram PMI,例如:
import nltk
from nltk.collocations import *
bigram_measures = nltk.collocations.BigramAssocMeasures()
# change this to read in your data
finder = BigramCollocationFinder.from_words(
nltk.corpus.genesis.words('english-web.txt'))
# only bigrams that appear 3+ times
finder.apply_freq_filter(3)
# return the 5 n-grams with the highest PMI
finder.nbest(bigram_measures.pmi, 5)