J'utilise le Vader SentimentAnalyzer pour obtenir les scores de polarité. J'ai utilisé les scores de probabilité pour positif/négatif/neutre auparavant, mais je viens de réaliser que le score "composé", allant de -1 (le plus négatif) à 1 (le plus pos), fournirait une seule mesure de polarité. Je me demande comment le score "composé" a été calculé. Est-ce calculé à partir du vecteur [pos, neu, neg]?
L'algorithme VADER génère des scores de sentiment dans 4 classes de sentiments https://github.com/nltk/nltk/blob/develop/nltk/sentiment/vader.py#L441 :
neg
: négatifneu
: Neutrepos
: positifcompound
: Composé (c'est-à-dire score agrégé)Parcourons le code, la première instance de compound est à https://github.com/nltk/nltk/blob/develop/nltk/sentiment/vader.py#L421 , où il calcule:
compound = normalize(sum_s)
La fonction normalize()
est définie comme telle à https://github.com/nltk/nltk/blob/develop/nltk/sentiment/vader.py#L107 :
def normalize(score, alpha=15):
"""
Normalize the score to be between -1 and 1 using an alpha that
approximates the max expected value
"""
norm_score = score/math.sqrt((score*score) + alpha)
return norm_score
Il y a donc un hyper-paramètre alpha
.
Quant au sum_s
, Il s'agit d'une somme des arguments de sentiment passés à la fonction score_valence()
https://github.com/nltk/nltk/blob/develop/nltk /sentiment/vader.py#L41
Et si nous remontons cet argument sentiment
, nous voyons qu'il est calculé lors de l'appel de la fonction polarity_scores()
à https://github.com/nltk/nltk/blob/develop /nltk/sentiment/vader.py#L217 :
def polarity_scores(self, text):
"""
Return a float for sentiment strength based on the input text.
Positive values are positive valence, negative value are negative
valence.
"""
sentitext = SentiText(text)
#text, words_and_emoticons, is_cap_diff = self.preprocess(text)
sentiments = []
words_and_emoticons = sentitext.words_and_emoticons
for item in words_and_emoticons:
valence = 0
i = words_and_emoticons.index(item)
if (i < len(words_and_emoticons) - 1 and item.lower() == "kind" and \
words_and_emoticons[i+1].lower() == "of") or \
item.lower() in BOOSTER_DICT:
sentiments.append(valence)
continue
sentiments = self.sentiment_valence(valence, sentitext, item, i, sentiments)
sentiments = self._but_check(words_and_emoticons, sentiments)
En regardant la fonction polarity_scores
, Ce qu'elle fait est de parcourir tout le lexique SentiText et vérifie avec la fonction sentiment_valence()
basée sur des règles pour attribuer le score de valence au sentiment https : //github.com/nltk/nltk/blob/develop/nltk/sentiment/vader.py#L24 , voir la section 2.1.1 de http://comp.social.gatech.edu/ papers/icwsm14.vader.hutto.pdf
Donc, pour en revenir au score composé, nous voyons que:
compound
est un score normalisé de sum_s
etsum_s
Est la somme de la valence calculée sur la base de quelques heuristiques et d'un Lexique des sentiments (aka. Sentiment Intensity) etsum_s
divisé par son carré plus un paramètre alpha qui augmente le dénominateur de la fonction de normalisation.Est-ce calculé à partir du vecteur [pos, neu, neg]?
Pas vraiment =)
Si nous jetons un œil à la fonction score_valence
https://github.com/nltk/nltk/blob/develop/nltk/sentiment/vader.py#L411 , nous voyons que le score composé est calculé avec le sum_s
avant que les scores pos, neg et neu soient calculés à l'aide de _sift_sentiment_scores()
qui calcule les scores inv, pos, neg et neu à l'aide des scores bruts de la fonction sentiment_valence()
sans la somme.
Si nous jetons un coup d'œil à cette alpha
mathémagique, il semble que la sortie de la normalisation soit plutôt instable (si elle n'est pas contrainte), en fonction de la valeur de alpha
:
alpha=0
:
alpha=15
:
alpha=50000
:
alpha=0.001
:
Ça devient génial quand c'est négatif:
alpha=-10
:
alpha=-1,000,000
:
alpha=-1,000,000,000
:
La section "À propos de la notation" du repo github a une description.