[PYTHON] Que diriez-vous de l'analyse de polarité avec "ordre" ajouté?

J'ai appris l'analyse de la polarité japonaise (analyse des émotions) avec un peu de rythme, et même si j'étais amateur, j'ai joué avec.

Dans l'analyse générale de la polarité (analyse des émotions), le score de chaque mot par rapport au dictionnaire de polarité est moyenné pour toute la phrase. Mais cela vous donne-t-il toujours un score intuitif ...?

Calendrier de l'Avent 2019 pour le traitement du langage naturel C'est le 4ème jour. Hier kabayan55 [«Une histoire pour« les gens qui veulent étudier le traitement du langage naturel »»](https://kabayan55.hatenablog.com/entry / 2019/12/03/001554) et Kazumasa Yamamoto [«Apprendre la catégorisation des documents avec la CLI spaCy»](https://qiita.com / kyamamoto9120 / items / 84d62c3b33fb77c03fbe) C'était le cas.

C'est la première fois que je participe au calendrier de l'Avent, mais j'ai hâte de travailler avec vous.

Tout d'abord, qu'est-ce que l'analyse de polarité?

Beaucoup de gens pensent qu'il existe des ** mots d'impression positive ** et des ** mots d'impression négative . Par exemple, " brillant " a une impression positive sur de nombreuses personnes, et " sombre **" a une impression négative.

** L'analyse de polarité ** consiste à résumer les impressions (polarité) de chaque mot et à analyser la polarité de chaque mot apparaissant dans la phrase.

L'analyse de polarité est utilisée telle quelle comme tremplin pour ** l'analyse des émotions **. Dans le cas d'une phrase globalement positive, c'est une raison raisonnable pour laquelle l'écrivain (l'orateur) a un sentiment positif. ~~ C'est un peu comme une personne de Kyoto ... ~~

Dans cette série de processus, ** la validité du dictionnaire **, c'est-à-dire si ** la polarité du mot est correctement évaluée ** est un point de vue très important, mais cette fois je n'y toucherai pas et ensuite * * Nous nous concentrerons sur la partie qui considère la polarité de la phrase entière **.

Bibliothèque d'évaluation de polarité pour Python «oseti»

Il existe différents dictionnaires polaires, mais cette fois [Dictionnaires polaires d'évaluation japonais publiés dans le laboratoire Inui Suzuki](http://www.cl.ecei.tohoku.ac.jp/index.php?Open% Je vais utiliser 20Resources% 2FJapanese% 20Sentiment% 20Polarity% 20Dictionary). Ce dictionnaire est noté mot par mot comme 1 pour le positif et -1 pour le négatif.

Une bibliothèque qui rend ce dictionnaire polaire facilement disponible en Python est «oseti», qui est également annoncé dans Qiita. Il calcule le score de la phrase grâce à l'analyse morphologique par MeCab.

Utilisons-le comme un essai. L'installation de MeCab est omise. Puisque oseti est enregistré dans PyPI, vous pouvez l'installer avec la commande pip.

pip install oseti

Vous pouvez calculer le score en créant une instance ʻAnalyzer` et en lui faisant un appel de méthode.

import oseti

analyzer = oseti.Analyzer()

Pour le moment, passons au début de cette fameuse phrase.

Je suis un chat. Il n'y a pas encore de nom. Je n'ai aucune idée d'où je suis né. Je me souviens avoir pleuré dans un endroit sombre et humide. J'ai vu des êtres humains pour la première fois ici. De plus, j'ai entendu plus tard que c'était la pire race d'êtres humains appelée Shosei.

―― «Je suis un chat» ―― Soseki Natsume

iamcat = 'Je suis un chat. Il n'y a pas encore de nom.\n \
Je n'ai aucune idée d'où je suis né.\
Je me souviens avoir pleuré dans un endroit sombre et humide.\
J'ai vu des êtres humains pour la première fois ici.\
De plus, j'ai entendu plus tard que c'était la pire race d'êtres humains appelée Shosei.'

iamcat_score = analyzer.analyze(iamcat)
print(iamcat_score)
[0, 0, 0, -1.0, 0, 1.0]

3e phrase,

Je me souviens avoir pleuré dans un endroit sombre et humide.

Je peux comprendre que cela soit jugé négatif, mais la cinquième phrase,

De plus, j'ai entendu plus tard que c'était la pire race d'êtres humains appelée Shosei.

C'est un peu étrange qui est traité comme positif. Dans ce cas, appelons une méthode qui effectue une analyse détaillée.

iamcat_detail = analyzer.analyze_detail(iamcat)
print(iamcat_detail[3])
print(iamcat_detail[5])
{'positive': [], 'negative': ['faible'], 'score': -1.0}
{'positive': ['Ichiban'], 'negative': [], 'score': 1.0}

Eh bien, cela semble être la raison pour laquelle le mot numéro un est traité positivement.

Passons une phrase avec un mélange de mots positifs et négatifs.

test_text = 'J'ai acheté un nouveau smartphone, et même si cela m'a coûté cher, le fonctionnement est léger et confortable.'
test_score = analyzer.analyze(test_text)
test_detail = analyzer.analyze_detail(test_text)
print(test_score)
print(test_detail)
[0.3333333333333333]
[{'positive': ['Lumière', 'confortable'], 'negative': ['Dépenses'], 'score': 0.3333333333333333}]

Le score de chaque mot est ** moyenné **. Le sens semble être une ** méthode standard ** souvent utilisée dans d'autres articles liés à l'analyse de polarité.

Si vous êtes en difficulté en moyenne

À propos, il y a des personnages fictifs, M. Sato et M. Suzuki. La conversation entre les deux est comme ça.

Sato "Je suis allé dans une ville pour un voyage d'affaires l'autre jour. ** J'étais fatigué car il y avait beaucoup de gens qui se sont perdus, mais la nourriture était délicieuse et le paysage était bon **."

Suzuki "C'était bien. Je suis allé à B City, mais ** le paysage était bon et la nourriture délicieuse, mais j'étais fatigué et perdu partout où j'allais **."

M. Sato semble avoir aimé faire du tourisme **, mais M. Suzuki semble avoir été ** pas bon **.

Cependant, lorsque l'analyse polaire de ces deux remarques est faite, cela devient ainsi.

sato_remark = 'J'étais fatiguée car il y avait beaucoup de gens qui se perdaient souvent, mais la nourriture était délicieuse et le paysage était bon.'
suzuki_remark = 'Le paysage était bon et la nourriture était délicieuse, mais j'étais fatigué et perdu partout où j'allais'

sato_score = analyzer.analyze(sato_remark)
suzuki_score = analyzer.analyze(suzuki_remark)
print(F'Sato: {sato_score}')
print(F'Suzuki: {suzuki_score}')
Sato: [0.0]
Suzuki: [0.0]

Les deux sont devenus ** Pramai Zero ** exactement de la même manière. Vous pouvez voir la raison en appelant la méthode d'analyse détaillée.

sato_detail = analyzer.analyze_detail(sato_remark)
suzuki_detail = analyzer.analyze_detail(suzuki_remark)
print(F'Sato: {sato_detail}')
print(F'Suzuki: {suzuki_detail}')
Sato: [{'positive': ['délicieux', 'vue'], 'negative': ['Foutez le camp', 'Fatigué'], 'score': 0.0}]
Suzuki: [{'positive': ['vue', 'délicieux'], 'negative': ['Fatigué', 'Foutez le camp'], 'score': 0.0}]

Oui, ils utilisent tous les deux les mêmes mots marqués. Bref, ce que vous dites est le même.

Pourtant, nous pensons que les remarques de M. Sato sont positives et les remarques de M. Suzuki sont négatives. Quelle est la raison?

Une hypothèse serait l'ordre des sujets. Au moins, les Japonais semblent plus susceptibles de mettre ce qu'ils veulent dire plus tard que **. Il est naturel pour M. Sato de penser que l'hésitation et la fatigue ne sont pas si importantes comparées à la délicieuse nourriture et à la beauté du paysage, et le contraire pour M. Suzuki.

Poids par ordre d'apparition

Ajoutons donc une méthode qui pondère les mots dans leur ordre d'apparition.

import neologdn
import sengiri
def analyze_with_weight(self, text, weightfunc=None):
    if weightfunc is None:
        weightfunc = lambda x: [1 / x for _ in range(x)]
    text = neologdn.normalize(text)
    scores = []
    for sentence in sengiri.tokenize(text):
        polarities = self._calc_sentiment_polarity(sentence)
        if polarities:
            weights = weightfunc(len(polarities))
            scores.append(sum(weights[i] * p[1] for (i,p,) in enumerate(polarities)))
        else:
            scores.append(0)
    return scores
setattr(oseti.Analyzer, 'analyze_with_weight', analyze_with_weight)

Si vous donnez à weightfunc un entier, vous lui donnez une fonction qui renvoie une séquence unidimensionnelle avec ce nombre d'éléments (une liste, un taple ou un tenseur NumPy) (je m'attends à ce que le total soit 1). Je ne l'ai pas vérifié en particulier). Il s'agit du poids selon l'ordre d'apparition. Si omis, le poids sera uniforme. C'est la même chose que de prendre la moyenne.

Par exemple, donnez ce qui suit comme des poids linéairement croissants:

from fractions import Fraction
def linear_weight(x):
    l = [i for i in range(1, x + 1)]
    s = sum(l)
    return [Fraction(i, s) for i in l]

En utilisant ce poids pour analyser leurs remarques, cela ressemble à ceci.

sato_score = analyzer.analyze_with_weight(sato_remark, linear_weight)
suzuki_score = analyzer.analyze_with_weight(suzuki_remark, linear_weight)
print(F'Sato: {sato_score}')
print(F'Suzuki: {suzuki_score}')
Sato: [Fraction(2, 5)]
Suzuki: [Fraction(-2, 5)]

…… Oups, c'est resté un nombre rationnel.

sato_score = [float(i) for i in sato_score]
suzuki_score = [float(i) for i in suzuki_score]
print(F'Sato: {sato_score}')
print(F'Suzuki: {suzuki_score}')
Sato: [0.4]
Suzuki: [-0.4]

Par conséquent, la remarque de M. Sato a été jugée relativement positive, et la remarque de M. Suzuki a été jugée relativement négative. N'est-ce pas plus intuitif que le premier résultat?

Mais les mots ne sont pas si simples

Cependant, cela ne signifie pas que cette méthode résoudra tout.

score = analyzer.analyze_with_weight('En fait, c'est une agréable fatigue.', linear_weight)
score = [float(i) for i in score]
print(score)
[-0.3333333333333333]

Dans certains cas, comme cet exemple et le slogan, les adjectifs qui précèdent peuvent vraiment signifier. Il peut être assez violent de simplement le rendre plus lourd derrière sans tenir compte de ces subtilités. Vous devez lire «Contexte».

Après tout, si vous voulez obtenir une évaluation plus «correcte», la méthode deviendra de plus en plus compliquée. Mais,

Les méthodes statistiquement sophistiquées ou complexes ne fournissent pas nécessairement des prévisions plus précises que les méthodes plus simples - Les méthodes statistiquement sophistiquées ou complexes ne font pas toujours des prévisions plus précises que les méthodes concises.

――“The M3-Competition: results, conclusions and implications” - Spyros Makridakis, Michele Hibon

De même, prendre une méthode trop compliquée ne donne pas toujours de bons résultats. Au contraire, cela n'a pas de sens de payer un coût qui n'en vaut pas la peine, même si vous obtenez de bons résultats.

En ce sens, «moyen» est extrêmement simple et peut être un bon moyen d'obtenir des résultats décents ...

en conclusion

Donc, c'était une phrase diverse de Tanuki comme ** Je ne connais même pas le caractère du traitement du langage naturel **.

Demain, c'est M. Mona Cat.

Suivant: Utilisons rapidement l'expression distribuée des mots avec fastText!

Recommended Posts

Que diriez-vous de l'analyse de polarité avec "ordre" ajouté?
Remarques sur avec
[Python] Comment comparer la date / heure avec le fuseau horaire ajouté
L'histoire de la gestion de theano avec TSUBAME 2.0
Analyse de données avec python 2
Analyse du panier avec Spark (1)
Analyse de dépendance avec CaboCha
Analyse vocale par python
Analyse vocale par python
Effectuer une analyse de régression avec NumPy
Analyse de données avec Python
Une histoire sur la façon de traiter le problème CORS