[PYTHON] Essayez une analyse rudimentaire des sentiments sur les données de l'API Twitter Stream.

Je pense que l'analyse des émotions est l'une des choses que j'aimerais faire lors de l'analyse de Twitter. (N'est-ce pas?) Je pense qu'il existe différentes méthodes, mais j'aimerais commencer par l'exemple le plus simple et voir qu'il devient progressivement plus avancé (de préférence).

Les données à analyser seront à nouveau Twitter. Cependant, jusqu'à présent, il a été acquis sur API REST Twitter, mais cette fois, il a été acquis sur API Twitter Stream. (/ streaming / overview) Je souhaite importer les données Twitter, puis numériser les résultats de l'analyse des émotions et les stocker dans la base de données.

Veuillez vous référer à Article précédent pour obtenir des explications sur la façon d'obtenir des données Twitter vers mongodb.

1. Obtenez des données de l'API Twitter Stream et stockez-les dans mongoDB.

1-1. Préparation

Tout d'abord, c'est une préparation. Importe diverses bibliothèques, déclare des fonctions utilitaires et se connecte à la base de données.

from requests_oauthlib import OAuth1Session
from requests.exceptions import ConnectionError, ReadTimeout, SSLError
import json, time, exceptions, sys, datetime, pytz, re, unicodedata, pymongo
import oauth2 as oauth
import urllib2 as urllib
import MeCab as mc
from collections import defaultdict
from pymongo import MongoClient
from httplib import IncompleteRead
import numpy as np

import logging
from logging import FileHandler, Formatter
import logging.config

connect = MongoClient('localhost', 27017)
db = connect.word_info
posi_nega_dict = db.posi_nega_dict
db2 = connect.twitter
streamdata = db2.streamdata

def str_to_date_jp(str_date):
    dts = datetime.datetime.strptime(str_date,'%a %b %d %H:%M:%S +0000 %Y')
    return pytz.utc.localize(dts).astimezone(pytz.timezone('Asia/Tokyo'))

def mecab_analysis(sentence):
    t = mc.Tagger('-Ochasen -d /usr/local/Cellar/mecab/0.996/lib/mecab/dic/mecab-ipadic-neologd/')
    sentence = sentence.replace('\n', ' ')
    text = sentence.encode('utf-8') 
    node = t.parseToNode(text) 
    result_dict = defaultdict(list)
    for i in range(140):  #Puisqu'il s'agit d'un tweet, MAX 140 caractères
        if node.surface != "":  #Exclure les en-têtes et les pieds de page
            word_type = node.feature.split(",")[0]
            if word_type in ["adjectif", "verbe","nom", "adverbe"]:
                plain_word = node.feature.split(",")[6]
                if plain_word !="*":
                    result_dict[word_type.decode('utf-8')].append(plain_word.decode('utf-8'))
        node = node.next
        if node is None:
            break
    return result_dict

def logger_setting():
    import logging
    from logging import FileHandler, Formatter
    import logging.config

    logging.config.fileConfig('logging_tw.conf')
    logger = logging.getLogger('filelogger')
    return logger

logger = logger_setting()

KEYS = { #Répertoriez ci-dessous les clés que vous avez obtenues avec votre compte
        'consumer_key':'**********',
        'consumer_secret':'**********',
        'access_token':'**********',
        'access_secret''**********',
       }

Cette fois, le journal utilise Logger pour sortir le fichier. Le fichier de paramètres de sortie du journal est le suivant.

logging_tw.conf


# logging_tw.conf

[loggers]
keys=root, filelogger

[handlers]
keys= fileHandler 

[formatters]
keys=logFormatter

[logger_root]
level=DEBUG
handlers=fileHandler

[logger_filelogger]
level=DEBUG
handlers=fileHandler
qualname=filelogger
propagate=0

[handler_fileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=logFormatter
args=('logging_tw.log',)

[formatter_logFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

1-2. Téléchargement et persistance du dictionnaire polaire japonais d'évaluation

Créé par le [Laboratoire du professeur Inui et du professeur Okazaki] de l'Université Tohoku (http://www.cl.ecei.tohoku.ac.jp/index.php?Open%20Resources%2FJapanese%20Sentiment%20Polarity%20Dictionary) Puisque les émotions sont quantifiées à l'aide du dictionnaire japonais de polarité d'évaluation disponible, tout d'abord

D'ici Téléchargez et stockez dans le même dossier que .py Faire.

En ce qui concerne le dictionnaire japonais de polarité d'évaluation (mots), le terme positif est quantifié comme 1 et le terme négatif est -1 et importé dans mongodb. Pour le dictionnaire japonais de polarité d'évaluation (édition nomen), le terme p est quantifié comme 1, le terme e est quantifié comme 0 et le terme n est -1 et importé dans mongodb. Ci-dessous le code.

#Importer des mots positifs et négatifs dans mongoDB

#Dictionnaire japonais de polarité d'évaluation (mots) ver.1.Importer 0 (version de décembre 2008) dans mongodb
#Le terme positif est 1,Le terme négatif est-Quantifier comme 1
with open("wago.121808.pn.txt", 'r') as f:
    for l in f.readlines():
        l = l.split('\t')
        l[1] = l[1].replace(" ","").replace('\n','')
        value = 1 if l[0].split('(')[0]=="Positif" else -1
        posi_nega_dict.insert({"word":l[1].decode('utf-8'),"value":value})
        

#Dictionnaire japonais de polarité d'évaluation (édition du nom) ver.1.Importer 0 (version de décembre 2008) dans mongodb
#Le terme p est 1 Le terme e est 0,Le terme n est-Quantifier comme 1
with open("pn.csv.m3.120408.trim", 'r') as f:
    for l in f.readlines():
        l = l.split('\t')
        
        if l[1]=="p":
            value = 1
        elif l[1]=="e":
            value = 0
        elif l[1]=="n":
            value = -1
            
        posi_nega_dict.insert({"word":l[0].decode('utf-8'),"value":value})  

1-3. Traitement pour quantifier le niveau émotionnel

Puisque nous avons pu créer une base de données de valeurs émotionnelles pour chaque mot en 1-2, nous ajouterons un traitement qui peut convertir des phrases en valeurs émotionnelles. Cependant, cette fois c'est "élémentaire" donc rien n'est fait et

  1. Vérifiez simplement si chaque mot contenu dans la phrase existe dans le dictionnaire japonais de polarité d'évaluation
  2. S'il existe, utilisez ce numéro
  3. Calculez la valeur émotionnelle de la phrase selon la formule suivante. ($ X_i $ est la valeur d'émotion du mot dans le dictionnaire japonais de polarité d'évaluation, $ n $ est le nombre de mots dans le dictionnaire japonais de polarité d'évaluation)
{\rm sentiment\, value\, of\, the\, sentence} \, = \, \frac{1}{n}\sum_{i=1}^{n} x_i 

Par conséquent, la valeur émotionnelle peut être dérivée entre -1 et 1 quel que soit le nombre de mots dans la phrase, et la comparaison entre les phrases devient possible.


#Réglage du niveau d'émotion(Inclure dans l'objet dictionnaire pour la recherche par hachage pour accélérer la recherche)
pn_dict = {data['word']: data['value'] for data in posi_nega_dict.find({},{'word':1,'value':1})}

def isexist_and_get_data(data, key):
    return data[key] if key in data else None

# -Renvoie la valeur émotionnelle d'une phrase donnée (liste de mots) comprise entre 1 et 1.(1:Le plus positif,-1:Le plus négatif)
def get_setntiment(word_list):
    val = 0
    score = 0
    word_count = 0
    val_list = []
    for word in word_list:
        val = isexist_and_get_data(pn_dict, word)
        val_list.append(val)
        if val is not None and val != 0: #Si trouvé, ajoutez les scores et comptez les mots
            score += val
            word_count += 1
    
    logger.debug(','.join(word_list).encode('utf-8'))       
    logger.debug(val_list)
    return score/float(word_count) if word_count != 0. else 0.

1-4. Téléchargement de données depuis l'API Twitter Stream

Code pour télécharger les données de tweet depuis l'API Twitter Stream. Lors du téléchargement des tweets, l'analyse morphologique est effectuée avec MeCab, et chaque mot est séparé et répertorié par nomenclature, verbe, adjectif et complément. Soi-disant sac de mots.

Ensuite, la valeur d'émotion est dérivée par la fonction get_setntiment () définie précédemment pour ces mots, et elle est stockée dans mongodb avec ceci.

# -----Importer des données de flux---------#
consumer = oauth.Consumer(key=KEYS['consumer_key'], secret=KEYS['consumer_secret'])
token = oauth.Token(key=KEYS['access_token'], secret=KEYS['access_secret'])

url = 'https://stream.twitter.com/1.1/statuses/sample.json'
params = {}

request = oauth.Request.from_consumer_and_token(consumer, token, http_url=url, parameters=params)
request.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, token)
res = urllib.urlopen(request.to_url())

def get_list_from_dict(result, key):
    if key in result.keys():
        result_list = result[key]
    else:
        result_list = []
    return result_list

cnt = 1
try:
    for r in res:
        data = json.loads(r)
        if 'delete' in data.keys():
            pass
        else:    
            if data['lang'] in ['ja']: #['ja','en','und']:
                result = mecab_analysis(data['text'].replace('\n',''))

                noun_list      = get_list_from_dict(result, u'nom')
                verb_list      = get_list_from_dict(result, u'verbe')
                adjective_list = get_list_from_dict(result, u'adjectif')
                adverb_list    = get_list_from_dict(result, u'adverbe')

                item = {'id':data['id'], 'screen_name': data['user']['screen_name'], 
                        'text':data['text'].replace('\n',''), 'created_datetime':str_to_date_jp(data['created_at']),\
                       'verb':verb_list, 'adjective':adjective_list, 'noun': noun_list, 'adverb':adverb_list}
                if 'lang' in data.keys():
                    item['lang'] = data['lang']
                else:
                    item['lang'] = None
                
                #Ajout des résultats de l'analyse des émotions####################
                word_list = [word for k in result.keys() for word in result[k] ]
                item['sentiment'] = get_setntiment(word_list)
                
                streamdata.insert(item)
                if cnt%1000==0:
                    logger.info("%d, "%cnt)
                cnt += 1
except IncompleteRead as e:
    logger.error( '===contenu de l'erreur===')
    logger.error(  'type:' + str(type(e)))
    logger.error(  'args:' + str(e.args))
    logger.error(  'message:' + str(e.message))
    logger.error(  'e self:' + str(e))
    try:
        if type(e) == exceptions.KeyError:
            logger.error( data.keys())
    except:
        pass
except Exception as e:
    logger.error( '===contenu de l'erreur===')
    logger.error( 'type:' + str(type(e)))
    logger.error( 'args:' + str(e.args))
    logger.error( 'message:' + str(e.message))
    logger.error( 'e self:' + str(e))
    try:
        if type(e) == exceptions.KeyError:
            logger.error( data.keys())
    except:
        pass 
except:
    logger.error( "error.")

logger.info( "finished.")

Jusqu'à présent, la méthode d'analyse était une méthode simple pour attribuer simplement des valeurs émotionnelles à chaque mot et en faire la moyenne. En ce qui concerne le développement futur, nous pensons que la classification du spam sera un problème en tant que prétraitement ultérieur, et dans la situation actuelle, le traitement qui prend en compte les relations entre les mots sera problématique. En particulier, les mots tels que "pas mignon" sont divisés en "mignon" et "pas", et puisque "pas" est refusé, l'expression positive de "mignon" +1.0 doit être annulée avec "pas" pour en faire -1.0. C'est naturel, mais à l'heure actuelle, seul «mignon» est traité et il devient +1,0, ce qui est le résultat inverse.

Afin de gérer cela correctement, il est nécessaire de relier et d'interpréter de quel mot "non" dépend une méthode appelée "analyse de dépendance". Dans la section suivante, j'aimerais expliquer comment installer d'abord la bibliothèque d'analyse de dépendances CaboCha.

2. Analyse des dépendances

2-1. Installation de la bibliothèque d'analyse des dépendances CaboCha

Je souhaite donc gérer l'installation de la bibliothèque d'analyse des dépendances CaboCha http://taku910.github.io/cabocha/ sur Mac. Il a fallu beaucoup de temps pour l'installer, j'espère donc que ce sera utile.

** Télécharger CaboCha ** https://drive.google.com/folderview?id=0B4y35FiV1wh7cGRCUUJHVTNJRnM&usp=sharing#list

Une bibliothèque appelée CRF + est nécessaire pour installer CaboCha. ** Page CRF + ** http://taku910.github.io/crfpp/#install

** CRF + Télécharger ** https://drive.google.com/folderview?id=0B4y35FiV1wh7fngteFhHQUN2Y1B5eUJBNHZUemJYQV9VWlBUb3JlX0xBdWVZTWtSbVBneU0&usp=drive_web#list

Après le téléchargement, décompressez et créez et installez. Puisqu'il existe certaines variables d'environnement et bibliothèques nécessaires, leur application est également décrite ci-dessous.

tar zxfv CRF++-0.58.tar
cd CRF++-0.58
./configure 
make
sudo make install

export LIBRARY_PATH="/usr/local/include:/usr/local/lib:"
export CPLUS_INCLUDE_PATH="/usr/local/include:/opt/local/include"
export OBJC_INCLUDE_PATH="/usr/local/include:/opt/local/lib"

brew tap homebrew/dupes
brew install libxml2 libxslt libiconv
brew link --force libxml2
brew link --force libxslt
brew link libiconv —force

tar zxf cabocha-0.69.tar.bz2
cd cabocha-0.69
./configure --with-mecab-config=`which mecab-config` --with-charset=UTF8
make
make check
sudo make install

#[output: install information]
#.././install-sh -c -d '/usr/local/share/man/man1'
#/usr/bin/install -c -m 644 cabocha.1 '/usr/local/share/man/man1'
#./install-sh -c -d '/usr/local/bin'
#/usr/bin/install -c cabocha-config '/usr/local/bin'
#./install-sh -c -d '/usr/local/etc'
#/usr/bin/install -c -m 644 cabocharc '/usr/local/etc'

cd cabocha-0.69/python
python setup.py install

cp build/lib.macosx-10.10-intel-2.7/_CaboCha.so /Library/Python/2.7/site-packages
cp build/lib.macosx-10.10-intel-2.7/CaboCha.py /Library/Python/2.7/site-packages

La méthode d'installation ci-dessus a été créée en se référant au site suivant.

Site qui a servi de référence pour l'installation de CaboCha

http://qiita.com/nezuq/items/f481f07fc0576b38e81d#1-10 http://hotolab.net/blog/mac_mecab_cabocha/ http://qiita.com/t_732_twit/items/a7956a170b1694f7ffc2 http://blog.goo.ne.jp/inubuyo-tools/e/db7b43bbcfdc23a9ff2ad2f37a2c72df http://qiita.com/t_732_twit/items/a7956a170b1694f7ffc2

2-2. Essai de CaboCha

Essayez l'analyse des dépendances avec le texte d'essai.

import CaboCha

c = CaboCha.Parser()

sentence = "Soseki a remis ce livre à la femme qui a vu Ryunosuke."

tree =  c.parse(sentence)

print tree.toString(CaboCha.FORMAT_TREE)
print tree.toString(CaboCha.FORMAT_LATTICE)

Le résultat de l'exécution de ce code est le suivant.

output


Soseki-----------D
cette-D       |
Livre---D   |
Ryunosuke-D   |
vu-D |
Aux femmes-D
Je l'ai remis.
EOS

* 0 6D 0/1 -2.475106
Soseki substantif,Nomenclature propriétaire,Nom d'une personne,Nom,*,*,Soseki,Souseki,Soseki
Est un assistant,Assistance,*,*,*,*,Est,C,sensationnel
* 1 2D 0/0 1.488413
Cet accessoire,*,*,*,*,*,cette,cette,cette
* 2 4D 0/1 0.091699
Cette nomenclature,Général,*,*,*,*,Livre,Hong,Hong
Auxiliaire,Assistant de cas,Général,*,*,*,À,Wo,Wo
* 3 4D 0/1 2.266675
Ryunosuke substantif,Nomenclature propriétaire,Nom d'une personne,Nom,*,*,Ryunosuke,Ryunosuke,Ryunosuke
Auxiliaire,Assistant de cas,Général,*,*,*,À,Wo,Wo
* 4 5D 0/1 1.416783
Look verbe,Indépendance,*,*,Un pas,Type continu,à voir,Mi,Mi
Verbe auxiliaire,*,*,*,Spécial,Forme basique,Ta,Ta,Ta
* 5 6D 0/1 -2.475106
Nomenclature féminine,Général,*,*,*,*,Femme,Josei,Josei
Auxiliaire,Assistant de cas,Général,*,*,*,À,ré,ré
* 6 -1D 0/1 0.000000
Verbe passant,Indépendance,*,*,Ligne Godan / Sa,Type continu,remettre,je,je
Verbe auxiliaire,*,*,*,Spécial,Forme basique,Ta,Ta,Ta
.. symbole,Phrase,*,*,*,*,。,。,。
EOS

La ligne avec "*" est le résultat de l'analyse, et quelques mots qui suivent sont les clauses.

À côté de * se trouve le "numéro de phrase". Vient ensuite le numéro de clause du contact, qui est -1 s'il n'y a pas de contact. Il semble que vous n'ayez pas à vous soucier de "D".

Les deux nombres suivants sont les positions des mots principaux / mots fonctionnels

Le dernier chiffre indique le degré de score d'engagement. Généralement, plus la valeur est élevée, plus il est facile de s'engager.

Donc, la première phrase est 0 "Soseki est", et le responsable est 6D, donc il est "passé".

Dans cet article, nous avons même installé CaboCha, une bibliothèque d'analyse des dépendances. Je voudrais appliquer cela aux données de tweet dans le prochain article.

Références, etc.

Dictionnaire japonais de la polarité d'évaluation - Laboratoire Inui Okazaki - Université de Tohoku Nozomi Kobayashi, Kentaro Inui, Yuji Matsumoto, Kenji Tateishi, Shunichi Fukushima. Collection d'expressions d'évaluation pour extraire des opinions. Traitement du langage naturel, Vol.12, No.3, pp.203-222, 2005. Masahiko Higashiyama, Kentaro Inui, Yuji Matsumoto, Acquisition of Nomenclature Evaluation Polarity Focusing on Predicate Selection Preference, Proceedings of the 14th Annual Meeting of the Language Processing Society, pp.584-587, 2008.

Recommended Posts

Essayez une analyse rudimentaire des sentiments sur les données de l'API Twitter Stream.
Essayez d'utiliser l'API Twitter
[Python] Notes sur l'analyse des données
Essayez «100 coups sur la science des données» ①
Essayez d'utiliser l'API Twitter
Analyse des données Twitter | Analyse des tendances
Visualisation et analyse des informations de localisation des données Twitter Stava
Environnement d'analyse de données centré sur Datalab (+ GCP)
Analyse émotionnelle des données de tweet à grande échelle par NLTK
Essayez d'importer des données MLB sur Mac et Python
Obtenez une grande quantité de données Twitter de Starba avec python et essayez l'analyse de données Partie 1