从文本内容生成标记

时间:2010-04-18 09:39:24

标签: python tags machine-learning nlp nltk

我很好奇是否存在通过使用一些权重计算,出现率或其他工具从给定文本生成关键字/标签的算法/方法。

此外,如果您指出任何基于Python的解决方案/库,我将不胜感激。

由于

5 个答案:

答案 0 :(得分:55)

实现此目的的一种方法是提取文档中出现频率高于您预期的文字。例如,在更大的文档集合中,几乎从未见过“马尔可夫”一词。然而,在来自同一集合的特定文档中,马尔科夫经常出现。这表明Markov可能是与文档关联的好关键字或标签。

要识别此类关键字,您可以使用关键字和文档的point-wise mutual information。这由PMI(term, doc) = log [ P(term, doc) / (P(term)*P(doc)) ]给出。这将粗略地告诉您,在特定文档中遇到这个术语时,您会感到多么惊讶(或者更多),因为它会在更大的集合中遇到它。

要确定与文档关联的5个最佳关键字,您只需按照PMI得分对文档进行排序,然后选择得分最高的5。

如果要提取多字标记,请参阅StackOverflow问题How to extract common / significant phrases from a series of text entries

借用我对这个问题的回答,NLTK collocations how-to涵盖了如何做 使用大约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)  

答案 1 :(得分:10)

首先,计算语言学的关键python库是NLTK(“自然语言工具包”)。这是一个由专业计算语言学家创建和维护的稳定,成熟的库。它还有广泛的collection教程,常见问题解答等。我推荐它。

下面是一个简单的模板,在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())

答案 2 :(得分:4)

http://en.wikipedia.org/wiki/Latent_Dirichlet_allocation尝试将训练语料库中的每个文档表示为主题的混合,而这些主题又是将单词映射到概率的分布。

我曾经用它一次将产品评论的内容剖析为所有文件中所涉及的潜在想法,例如“客户服务”,“产品可用性”等。基本模型不提倡将主题模型转换为描述主题内容的单个词的方法......但是一旦他们的模型被训练,人们就会提出各种启发式方法。

我建议您尝试使用http://mallet.cs.umass.edu/并观看此模型是否符合您的需求..

LDA是一种完全无监督的算法,意味着它不需要您手动注释任何伟大的东西,但另一方面,可能无法为您提供您期望它给出的主题。

答案 3 :(得分:0)

解决问题的一个非常简单的方法是:

  • 计算文本中每个单词的出现次数
  • 将最常用的字词视为关键短语
  • 有一个黑名单的'停用词'来删除常见的单词,比如,和它等等

我确信有更聪明,基于统计数据的解决方案。

如果你需要一个解决方案用于更大的项目而不是为了利益,雅虎BOSS有一个关键的术语提取方法。

答案 4 :(得分:0)

Latent Dirichlet allocationHierarchical Dirichlet Process可用于通过从派生主题中提取最重要的词来为更大的语料库(文本主体)中的单个文本生成标签。

一个基本的例子是,如果我们要在一个语料库上运行LDA并将其定义为具有两个主题,并且我们进一步发现该语料库中的文本是一个主题的70%,另一个主题的30%。然后,可以将定义第一个主题的单词的前70%和定义第二个主题的单词的前30%(无重复)视为给定文本的标签。当标签通常代表给定文本的更广泛主题时,此方法可提供强大的结果。

找到here后找到这些代码所需的预处理的一般参考,我们可以使用gensim通过以下过程找到标签。

this answer中找到了一种启发式方法,可为LDA推导最佳主题数。尽管HDP不需要输入主题数,但在这种情况下,标准仍然是将LDA与派生的主题号一起使用,因为HDP可能会出现问题。假设在这里发现语料库有10个主题,并且每个文本需要5个标签:

from gensim.models import LdaModel, HdpModel
from gensim import corpora
num_topics = 10
num_tags = 5

进一步假设我们有一个变量corpus,它是列表的预处理列表,子列表项是单词标记。初始化Dirichlet词典并创建一袋单词,其中将文本转换为其组件标记(单词)的索引:

dirichlet_dict = corpora.Dictionary(corpus)
bow_corpus = [dirichlet_dict.doc2bow(text) for text in corpus]

创建LDA或HDP模型:

dirichlet_model = LdaModel(corpus=bow_corpus,
                           id2word=dirichlet_dict,
                           num_topics=num_topics,
                           update_every=1,
                           chunksize=len(bow_corpus),
                           passes=20,
                           alpha='auto')

# dirichlet_model = HdpModel(corpus=bow_corpus, 
#                            id2word=dirichlet_dict,
#                            chunksize=len(bow_corpus))

以下代码为每个主题的最重要单词生成有序列表(请注意,num_tags在此处定义了每个文本所需的标签):

shown_topics = dirichlet_model.show_topics(num_topics=num_topics, 
                                           num_words=num_tags,
                                           formatted=False)
model_topics = [[word[0] for word in topic[1]] for topic in shown_topics]

然后在各个文本中找到主题的连贯性:

topic_corpus = dirichlet_model.__getitem__(bow=bow_corpus, eps=0) # cutoff probability to 0 
topics_per_text = [text for text in topic_corpus]

从这里开始,我们可以得出每个文本与给定主题的相距百分比以及与每个主题相关的单词,因此我们可以将其与标签结合使用:

corpus_tags = []

for i in range(len(bow_corpus)):
    # The complexity here is to make sure that it works with HDP
    significant_topics = list(set([t[0] for t in topics_per_text[i]]))
    topic_indexes_by_coherence = [tup[0] for tup in sorted(enumerate(topics_per_text[i]), key=lambda x:x[1])]
    significant_topics_by_coherence = [significant_topics[i] for i in topic_indexes_by_coherence]

    ordered_topics = [model_topics[i] for i in significant_topics_by_coherence][:num_topics] # subset for HDP
    ordered_topic_coherences = [topics_per_text[i] for i in topic_indexes_by_coherence][:num_topics] # subset for HDP

    text_tags = []
    for i in range(num_topics):
        # Find the number of indexes to select, which can later be extended if the word has already been selected
        selection_indexes = list(range(int(round(num_tags * ordered_topic_coherences[i]))))
        if selection_indexes == [] and len(text_tags) < num_tags: 
            # Fix potential rounding error by giving this topic one selection
            selection_indexes = [0]
              
        for s_i in selection_indexes:
            # ignore_words is a list of words should not be included
            if ordered_topics[i][s_i] not in text_tags and ordered_topics[i][s_i] not in ignore_words:
                text_tags.append(ordered_topics[i][s_i])
            else:
                selection_indexes.append(selection_indexes[-1] + 1)

    # Fix for if too many were selected
    text_tags = text_tags[:num_tags]

    corpus_tags.append(text_tags)

corpus_tags将是每个文本的标签列表,该列表基于文本与派生主题的一致性。

请参见this answer,以了解其为整个文本语料库生成标签的类似版本。