为什么TextBlob没有使用/检测否定形式?

4

我正在使用TextBlob执行情感分析任务。我注意到TextBlob能够在某些情况下检测否定,而在其他情况下则不能。

这里有两个简单的例子:

>>> from textblob.sentiments import PatternAnalyzer

>>> sentiment_analyzer = PatternAnalyzer()
# example 1
>>> sentiment_analyzer.analyze('This is good')
Sentiment(polarity=0.7, subjectivity=0.6000000000000001)

>>> sentiment_analyzer.analyze('This is not good')
Sentiment(polarity=-0.35, subjectivity=0.6000000000000001)

# example 2
>>> sentiment_analyzer.analyze('I am the best')
Sentiment(polarity=1.0, subjectivity=0.3)

>>> sentiment_analyzer.analyze('I am not the best')  
Sentiment(polarity=1.0, subjectivity=0.3)

如您在第二个例子中所见,使用形容词“best”时极性不会改变。我怀疑这是因为形容词“best”是一个非常强的指示器,但这似乎不正确,因为否定应该已经反转了极性(在我的理解中)。
有人可以解释一下发生了什么吗?TextBlob是否使用任何否定机制,还是只是单词“not”将负面情感添加到句子中?无论哪种情况,为什么第二个例子在两种情况下的情感完全相同?是否有任何建议如何克服这些障碍?
1个回答

4

(编辑:我的旧回答更多地是关于一般分类器而不是PatternAnalyzer)

TextBlob在您的代码中使用“PatternAnalyzer”。它的行为在该文档中简要说明:http://www.clips.ua.ac.be/pages/pattern-en#parser

我们可以看到:

pattern.en模块捆绑了形容词词汇表(例如,好、坏、惊人、刺激人的...),这些形容词经常出现在产品评论中,带有情感极性(正向↔负向)和主观性(客观↔主观)的分数注释。

sentiment()函数返回给定句子的(极性、主观性)元组,基于它包含的形容词

以下是一个示例,展示了算法的行为。极性直接取决于所使用的形容词。

sentiment_analyzer.analyze('player')
Sentiment(polarity=0.0, subjectivity=0.0)

sentiment_analyzer.analyze('bad player')
Sentiment(polarity=-0.6999998, subjectivity=0.66666)

sentiment_analyzer.analyze('worst player')
Sentiment(polarity=-1.0, subjectivity=1.0)

sentiment_analyzer.analyze('best player')
Sentiment(polarity=1.0, subjectivity=0.3)

专业软件通常使用基于神经网络和分类器的复杂工具,结合词法分析。但对于我来说,TextBlob仅尝试根据语法分析的直接结果(此处是形容词的极性)给出结果。这是问题的根源。
它不会尝试检查一般句子是否是否定的(带有“不”单词)。它会尝试检查形容词是否是否定的(因为它仅适用于形容词,而不适用于一般结构)。在这里,“best”被用作名词,不是否定的形容词。因此,极性是积极的。
sentiment_analyzer.analyze('not the best')
Sentiment(polarity=1.0, subjectivity=0.3)

只需更改单词的顺序即可对形容词进行否定,而不是整个句子。

sentiment_analyzer.analyze('the not best')
Sentiment(polarity=-0.5, subjectivity=0.3)

这里,形容词被否定了。因此,极性是负面的。 这是我对那种“奇怪行为”的解释。


真正的实现定义在文件中: https://github.com/sloria/TextBlob/blob/dev/textblob/_text.py

有趣的部分如下:

if w in self and pos in self[w]:
    p, s, i = self[w][pos]
    # Known word not preceded by a modifier ("good").
    if m is None:
        a.append(dict(w=[w], p=p, s=s, i=i, n=1, x=self.labeler.get(w)))
    # Known word preceded by a modifier ("really good").
    
    ...
    

else:
    # Unknown word may be a negation ("not good").
    if negation and w in self.negations:
        n = w
    # Unknown word. Retain negation across small words ("not a good").
    elif n and len(w.strip("'")) > 1:
        n = None
    # Unknown word may be a negation preceded by a modifier ("really not good").
    if n is not None and m is not None and (pos in self.modifiers or self.modifier(m[0])):
        a[-1]["w"].append(n)
        a[-1]["n"] = -1
        n = None
    # Unknown word. Retain modifier across small words ("really is a good").
    elif m and len(w) > 2:
        m = None
    # Exclamation marks boost previous word.
    if w == "!" and len(a) > 0:
    
    ...

如果我们输入“not a good”或“not the good”,它将匹配else部分,因为它不是一个单一的形容词。
“not a good”部分将匹配elif n and len(w.strip("'")) > 1:,所以它将反转极性。"not the good"不会匹配任何模式,所以极性将与“best”相同。
整个代码是一系列微调、语法指示(例如添加!增加极性,添加笑脸表示讽刺等)。这就是为什么有些特定的模式会给出奇怪的结果。要处理每个特定情况,您必须检查您的句子是否与代码的那部分中的任何if语句匹配。
我希望我能帮到你。

浏览TextBlob文档以了解默认情感分类器的工作方式(PatternAnalyzer是默认分类器),我认为你错了。PatternAnalyzer确实使用语法分析。如果您想了解更多信息,请单击此处查看此处。简而言之,它使用带注释的单词词典,然后在词典中的分数和句子属性之间执行各种映射。它还积极寻找否定,如您可以在此处看到。 - LetsPlayYahtzee
也许你的答案真正描述了TextBlob中其他分类器,比如NaiveBayerClassifier是如何工作的,但我还没有经过这些实现部分。 我怀疑语法分析总是涉及其中,不管是通过特征提取还是其他种类的启发式方法。 - LetsPlayYahtzee
好的,我的错。因此,对于模式分析器,答案将基于该文档:http://www.clips.ua.ac.be/pages/pattern-en#parser(模式分析器文档)。
sentiment()函数返回给定句子的(极性,主观性)元组,基于其中包含的形容词
因此,由于not不是形容词,它不会影响极性。 您可以使用“player”进行检查。它具有空极性。但是,如果您使用“最佳球员”,它将具有一元极性。“最差球员”将得到-1我会将其添加到我的帖子中。
- Alexis Clarembeau
这可能更接近正确答案,但我仍然不完全确定它是否完全正确或更准确。例如,如果您考虑句子“我不是最好的”的情感,则否定成功应用,而根据textblob pos标记器,“a”和“the”在句子中扮演完全相同的角色。 - LetsPlayYahtzee
我认为这是因为它将“not a best”组合成一个负面形容词。对于我来说,“(not a best)player”和“not(the best player)”是不同的。这就是为什么第一种情况是负面的,而第二种情况是正面的原因。但是,这只是我对问题的解释。当然,这很棘手,因为它是一种错误,而不是一个特性。我认为我已经找到了为什么这个句子是一个边缘案例的原因。为了完全解释清楚,我们需要考虑textblob分析器的确切实现: https://github.com/sloria/TextBlob/tree/dev/textblob - Alexis Clarembeau
如果我进一步检查源代码,这里是:https://github.com/sloria/TextBlob/blob/dev/textblob/_text.py我发现在890到900行之间,该库的工作方式如下。如果我们读取一个已知的单词,比如“好”,就取它的极性。如果我们读取“not” + 形容词,将其设置为负面。如果我们读取not + a + 形容词,则将其设置为负面(a可以是任何一个字母的单词;将“not a best player”替换为“not a z player”,它也可以工作)。如果您阅读该代码部分的整个if语句,您会发现没有模式匹配not + the + 形容词。这就是为什么它不起作用的原因 :) - Alexis Clarembeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接