从文本内容生成标签

Posted

技术标签:

【中文标题】从文本内容生成标签【英文标题】:tag generation from a text content 【发布时间】:2011-02-09 08:17:56 【问题描述】:

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

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

谢谢

【问题讨论】:

【参考方案1】:

执行此操作的一种方法是提取文档中出现频率高于您预期的单词。例如,假设在更大的文档集合中,“马尔可夫”一词几乎从未见过。但是,在同一集合中的特定文档中,马尔可夫非常频繁地出现。这表明马尔科夫可能是与文档相关联的一个很好的关键字或标签。

要识别这样的关键字,您可以使用关键字和文档的point-wise mutual information。这是由PMI(term, doc) = log [ P(term, doc) / (P(term)*P(doc)) ] 给出的。这将粗略地告诉您,在特定文档中遇到该术语与在更大的集合中遇到它相比,您有多少(或更多)感到惊讶。

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

如果您想提取多字标签,请参阅 *** 问题 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)  

【讨论】:

我在这里提出了一个类似的问题:***.com/questions/2764116/…我想知道这个算法在这么小的文本块上是否成功。 但它不返回单个单词【参考方案2】:

首先,计算语言学的关键 Python 库是 NLTK(“Natural Language Toolkit”)。这是一个由专业计算语言学家创建和维护的稳定、成熟的库。它还有大量的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())

【讨论】:

【参考方案3】:

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

我曾经用它来剖析产品评论语料库中的潜在想法,这些想法贯穿所有文档,例如“客户服务”、“产品可用性”等。基本模型不提倡将主题模型转换为描述主题内容的单个单词的方法..但是一旦他们的模型经过训练,人们就会想出各种启发式方法来做到这一点。

我建议你试试http://mallet.cs.umass.edu/,看看这个模型是否符合你的需求。

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

【讨论】:

【参考方案4】:

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

统计每个单词在文本中出现的次数 将最常用的术语视为关键短语 有一个“停用词”黑名单来删除常用词,例如 the、and、it、is 等

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

如果您需要在更大的项目中使用解决方案而不是为了利益,Yahoo BOSS 有一个关键术语提取方法。

【讨论】:

【参考方案5】:

Latent Dirichlet allocation 或 Hierarchical 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 以获取类似的版本,它会为整个文本语料库生成标签。

【讨论】:

以上是关于从文本内容生成标签的主要内容,如果未能解决你的问题,请参考以下文章

js处理富文本编辑器转义去除转义去除HTML标签

Vue根据富文本内容生成目录

Vue根据富文本内容生成目录

Vue :将头像/文本生成二维码

如果可以从 UITableView 生成 PDF 文件?

设置从 HTML 字符串生成的 UITableViewCell 标签