使用Python从基于主题的文本中提取关键短语

2024-05-16 22:48:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个3列的大数据集,列是文本、短语和主题。 我想找到一种基于主题提取关键短语(短语列)的方法。 关键短语可以是文本值的一部分,也可以是整个文本值

import pandas as pd


text = ["great game with a lot of amazing goals from both teams",
        "goalkeepers from both teams made misteke",
        "he won all four grand slam championchips",
        "the best player from three-point line",
        "Novak Djokovic is the best player of all time",
        "amazing slam dunks from the best players",
        "he deserved yellow-card for this foul",
        "free throw points"]

phrase = ["goals", "goalkeepers", "grand slam championchips", "three-point line", "Novak Djokovic", "slam dunks", "yellow-card", "free throw points"]

topic = ["football", "football", "tennis", "basketball", "tennis", "basketball", "football", "basketball"]

df = pd.DataFrame({"text":text,
                   "phrase":phrase,
                   "topic":topic})

print(df.text)
print(df.phrase)

我很难找到这样做的路径,因为我的数据集中有50000多行,约48000个短语的唯一值,以及3个不同的主题

我想建立一个包含所有足球、篮球和网球主题的数据集并不是最好的解决方案。因此,我曾考虑为此制作某种ML模型,但这同样意味着我将有两个特性(文本和主题)和一个结果(短语),但我的结果中将有48000多个不同的类,这不是一个好方法

我正在考虑使用文本列作为特征,并应用分类模型来发现情感。之后,我可以使用预测情绪来提取关键特征,但我不知道如何提取它们

还有一个问题是,当我尝试使用CountVectorizerTfidfTransformer随机森林、决策树或任何其他分类算法对情绪进行分类时,我的准确率仅为66%,如果我使用TextBlob进行情绪分析,则准确率也只有66%

有什么帮助吗


Tags: the数据textfrom文本df主题topic
3条回答

我想你想要的是NLP中的“主题建模”。 您应该尝试使用LDA进行主题建模。这是最容易应用的方法之一。 正如@Mike提到的,将单词转换为向量有很多方法。您应该首先尝试一些简单的方法,比如count vectorizer,然后逐渐转向word-2-vect或手套

我附上一些链接,用于将LDA应用于语料库。 1. https://towardsdatascience.com/nlp-extracting-the-main-topics-from-your-dataset-using-lda-in-minutes-21486f5aa925 2. https://www.machinelearningplus.com/nlp/topic-modeling-visualization-how-to-present-results-lda-models/

这里的一个好方法似乎是使用Latent Dirichlet allocation模型,这是一个被称为topic models的例子


ALDA是一种无监督的模型,可以在一组观察结果中找到类似的组,然后可以使用这些组为每个组分配主题。在这里,我将通过使用text列中的句子训练一个模型来解决这个问题。尽管在这种情况下phrases具有足够的代表性,并且包含了模型捕获的必要信息,但是它们也可能是训练模型的好(可能更好)候选对象,尽管您最好自己判断

在训练模型之前,需要应用一些预处理步骤,包括标记句子、删除停止词、柠檬化和词干分析。为此,您可以使用nltk

from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import lda
from sklearn.feature_extraction.text import CountVectorizer

ignore = set(stopwords.words('english'))
stemmer = WordNetLemmatizer()
text = []
for sentence in df.text:
    words = word_tokenize(sentence)
    stemmed = []
    for word in words:
        if word not in ignore:
            stemmed.append(stemmer.lemmatize(word))
    text.append(' '.join(stemmed))

现在我们有了更合适的语料库来训练模型:

print(text)

['great game lot amazing goal team',
 'goalkeeper team made misteke',
 'four grand slam championchips',
 'best player three-point line',
 'Novak Djokovic best player time',
 'amazing slam dunk best player',
 'deserved yellow-card foul',
 'free throw point']

然后,我们可以通过^{}将文本转换为令牌计数矩阵,这是LDA所期望的输入:

vec = CountVectorizer(analyzer='word', ngram_range=(1,1))
X = vec.fit_transform(text)

注意,可以使用^ {< CD7>}参数来对要考虑的N-gram范围进行空间化来训练模型。例如,通过设置ngram_range=(1,2),您将得到包含所有单个单词以及每个句子中2-grams的功能,下面是一个使用ngram_range=(1,2)训练CountVectorizer的示例:

vec.get_feature_names()
['amazing',
 'amazing goal',
 'amazing slam',
 'best',
 'best player',
 ....

使用n-grams的优点是,您还可以找到Key-Phrases而不仅仅是单个单词

那么我们可以用你想要的任何数量来训练^ {< CD1>},在这种情况下,我只会选择^ {CD15>}主题(注意这与^ {CD16>}列无关),在这个例子中,你可以认为是^ {CD13>}或^ {CD18>}。这里我将使用^{},尽管有几个选项,例如gensim。 每个主题都会关联一组词汇,每个词汇都有一个分数来衡量单词在主题中的相关性

model = lda.LDA(n_topics=3, random_state=1)
model.fit(X)

通过topic_word_我们现在可以获得与每个主题相关的分数。我们可以使用argsort对分数向量进行排序,并使用它对特征名称向量进行索引,我们可以通过vec.get_feature_names获得:

topic_word = model.topic_word_

vocab = vec.get_feature_names()
n_top_words = 3

for i, topic_dist in enumerate(topic_word):
    topic_words = np.array(vocab)[np.argsort(topic_dist)][:-(n_top_words+1):-1]
    print('Topic {}: {}'.format(i, ' '.join(topic_words)))

Topic 0: best player point
Topic 1: amazing team slam
Topic 2: yellow novak card

在这种情况下,打印的结果实际上代表不了多少,因为模型已经用问题中的样本进行了训练,但是通过使用整个语料库进行训练,您应该可以看到更清晰、更有意义的主题

还请注意,对于这个示例,我使用了整个词汇表来训练模型。然而,在您的情况下,似乎更有意义的是,根据您已有的不同topics将文本列分成多个组,并在每个组上训练一个单独的模型。但希望这能给你一个关于如何继续的好主意

看起来您正在按主题对短文本进行分组。您必须以某种方式标记数据。您可以考虑多种编码方式:

单词袋,通过计算词汇表中每个单词的频率进行分类

TF-IDF:执行上述操作,但使出现在更多条目中的单词变得不那么重要

n_grams/bigrams/trigrams本质上是单词袋方法,但也保留了每个单词周围的一些上下文。因此,每个单词都有编码,但也有“great_game”、“game_with”和“great_game_with”等标记

正交稀疏二元图(OSB)还创建了一些将单词分隔得更远的功能,如“great_uuuuwith”

这些选项中的任何一个都非常适合您的数据集(最后两个可能是您的最佳选择)。如果这些选项都不起作用,您还可以尝试以下几个选项:


首先,您可以使用单词嵌入。这些是每个单词的向量表示,与热编码不同,热编码本质上包含单词含义。你可以把一个句子中的单词加起来,得到一个新的向量,这个向量包含了这个句子的大致意思,然后就可以被解码了

您还可以在双向LSTM旁边使用单词嵌入。这是计算最密集的选项,但如果您的其他选项不起作用,这可能是一个不错的选择。BILSTM试图通过观察单词周围的上下文来解释句子,试图理解单词在该上下文中的含义

希望这有帮助

相关问题 更多 >