Aprendizaje computacional en grandes volúmenes de texto

Mario Graff (mgraffg@ieee.org, mario.graff@infotec.mx)

Sabino Miranda (sabino.miranda@infotec.mx)

Daniela Moctezuma (dmoctezuma@centrogeo.edu.mx)

Eric S. Tellez (eric.tellez@infotec.mx)

CONACYT, INFOTEC y CentroGEO

https://github.com/ingeotec

Objetivo

El alumno será capaz de crear modelos de texto multilenguaje aplicables a grandes volúmenes de información. Sobre estos modelos, el alumno será capaz de aplicar algoritmos de aprendizaje supervisado para diferentes dominios de aplicación, como por ejemplo, clasificadores de polaridad, determinar la autoría basado en el texto, determinar la temática de un texto, entre otras.

Temas

  • Introducción
    • Motivación (análisis de sentimientos, detección de predadores, spam, género, edad, autoría en general, marketing, prestigio, etc)
    • Estado del arte (competencias)
    • Uso de herramientas: $\mu$TC, Python, numpy, nltk, sklearn
  • Representación vectorial del texto
    • Normalización
    • Tokenización (n-words, q-grams, skip-grams)
    • Pesado de texto (TFIDF)
    • Medidas de similitud
  • Aprendizaje supervisado
    • Modelo general de aprendizaje; Entrenamiento, test, score (accuracy, recall, precision, f1)
    • Máquinas de soporte vectorial (SVM)
    • Programación genética (EvoDAG)
    • Distant supervision
  • $\mu$TC
    • Pipeline de transformaciones
    • Optimización de parámetros
    • Clasificadores
    • Uso del $\mu$TC
  • Aplicaciones
    • Análisis de sentimientos
    • Determinación de autoría
    • Clasificación de noticias
    • Spam
    • Género y edad
  • Conclusiones

Análisis de Polaridad de Tuits GEO Referenciados

  • Análisis de la polaridad de tuits geo-referenciados
  • Recolectados desde 16 de diciembre del 2015 hasta 25 de noviembre de 2016
  • Todos los tuits están escritos en español y están geo-localizados.
  • Servicio Web de Análisis de Polaridad (SWAP)

Metodología

  • Seleccionaron aquellos que indican que su país de origen es México (etiqueta MX)
  • Aproximadamente 37,198,787 tuits
  • Generados por 695,345 usuarios
  • Analizado por SWAP
  • Valor es la positividad del tuit.
  • Eliminar el sezgo que pueden introducir los usuarios más activos
  • Midiendo la positividad promedio por usuario, por día.
  • La positividad es la media el promedio de la positividad promedio de los usuarios por día.

Análisis de Positividad para México

  • El eje de abscisas se encuentran los diferentes días
  • En el eje de las ordenadas está el valor de positividad
  • El máximo valor es 1 y el mínimo valor es 0.
  • En las abscisas se muestran los 10 picos mas significativos así como el valle más pronunciado.
  • 24 y 25 de diciembre del 2015
  • 31 de diciembre y 1 de enero del 2016
  • 14 de febrero
  • 8 de marzo (día de la mujer)
  • 30 de abril
  • 10 de mayo
  • 15 de mayo
  • 19 de junio (día del padre)
  • 9 de noviembre de 2016 (elecciones presidenciales de Estados Unidos)

In [ ]:
%matplotlib inline
import matplotlib.pyplot as plt
import gzip
import json
import numpy as np
def read_data(fname):
    with gzip.open(fname) as fpt:
        d = json.loads(str(fpt.read(), encoding='utf-8'))
        return d

In [ ]:
%matplotlib inline
plt.figure(figsize=(20, 10))
mx_pos = read_data('spanish/polarity_by_country/MX.json.gz')
ticks = [str(x[0])[2:] for x in mx_pos]
mu = [x[1] for x in mx_pos]
plt.plot(mu)
index = np.argsort(mu)
index = np.concatenate((index[:1], index[-10:]))
_ = plt.xticks(index, [ticks[x] for x in index], rotation=90)
plt.grid()
  • Efecto oscilatorio cuyo periodo corresponde a los días de la semana.
  • TGIF (Thanks god, it's friday).
  • Remover este fenómeno
  • Quitar la mediana por día

In [ ]:
def remove_median(pos):
    median = np.array(mx_pos[: -int((len(pos) % 7))])[:, 1]
    median.shape = (int(median.shape[0] / 7), 7)
    median = np.median(median, axis=0)
    median = np.concatenate((np.concatenate([median for x in range(int(len(pos) / median.shape[0]))], axis=0),
                            median[:int(len(mx_pos) % 7)]), axis=0)
    return [(x[0], x[1] - y) for x, y in zip(pos, median)]

In [ ]:
plt.figure(figsize=(20, 10))
nmx_pos = remove_median(mx_pos)
mu = np.array([x[1] for x in nmx_pos])
plt.plot(mu)
index = np.argsort(mu)
index = np.concatenate((index[:1], index[-10:]))
_ = plt.xticks(index, [ticks[x] for x in index], rotation=90)
plt.grid()

In [ ]:
plt.figure(figsize=(20, 20))
for k, D in enumerate([mx_pos, remove_median(mx_pos)]):
    ticks = [str(x[0])[2:] for x in D]
    mu = [x[1] for x in D]
    plt.subplot(4, 1, k+1)
    plt.plot(mu)
    index = np.argsort(mu)
    index = np.concatenate((index[:1], index[-10:]))
    _ = plt.xticks(index, [ticks[x] for x in index], rotation=45)
    plt.grid()

Análisis de polaridad en Estados Unidos, Argentina, México y España

  • Estados Unidos
  • México
  • Argentina
  • España.
  • 19 de marzo
  • 19 de junio es importante para todas las naciones excepto España
  • 20 de julio que se celebra el día del amigo en Argentina.

In [ ]:
pos = [read_data('spanish/polarity_by_country/%s.json.gz' % x) for x in ['US', 'AR', 'ES']]
us_pos, ar_pos, es_pos = pos
plt.figure(figsize=(20, 10))
for code, D, k in zip(['US', 'MX', 'AR', 'ES'], [us_pos, mx_pos, ar_pos, es_pos],
                     range(4)):
    D = remove_median(D)
    ticks = [str(x[0])[2:] for x in D]
    mu = [x[1] for x in D]
    plt.subplot(4, 1, k+1)
    plt.plot(mu)
    plt.title(code)
    index = np.argsort(mu)
    index = np.concatenate((index[:1], index[-10:]))
    _ = plt.xticks(index, [ticks[x] for x in index], rotation=45)
    plt.grid()
    plt.ylim(-0.20, 0.20)

Análisis Descriptivo de los Tweets en Español

A partir de los tweets almacenados se presentan algunas estadísticas básicas que describen algunas características interesantes de los datos como la cantidad de usuarios por país y la movilidad de los usuarios.

Cantidad de usuarios por país

La siguiente figura muestra los usuarios por país, se puede observar que Estados Unidos es el que cuenta con un mayor número de usuarios, seguido por Argentina y en tercer lugar México. Ademas sorpresivamente Brasil es el cuarto y en quinto lugar se encuentra España.


In [ ]:
%matplotlib inline
from glob import glob
from multiprocessing import Pool
from tqdm import tqdm
from collections import Counter
def number_users(fname):
    return fname, len(read_data(fname))

fnames = [i for i in glob('spanish/users_by_country/*.json.gz') if len(i.split('.')[0].split('/')[1]) == 2]
p = Pool(8)
res = [x for x in p.imap_unordered(number_users, fnames)]
p.close()

country_code = Counter()
for name, value in res:
    code = name.split('.')[0].split('/')[1]
    country_code[code] = value
mc = country_code.most_common()
size = 19
first = mc[:size]
extra = ('REST', sum([x[1] for x in mc[size:]]))
first.append(extra)
plt.figure(figsize=(10, 10))
_ = plt.pie([x[1] for x in first], labels=[x[0] for x in first])

Movilidad de los Tuiteros (de habla hispana)

La siguiente figura muestra cuáles son los países que visitan más frecuentemente usuarios de un país en particular. Por ejemplo, la mayoría de los usuarios de Estados Unidos que viajan a otro país viajan a México, en segundo lugar a Puerto Rico y así sucesivamente; los usuarios de Argentina viajan a Brasil en primer lugar; los de México viajan a Estados Unidos; y los de España también viajan a Estados Unidos.


In [ ]:
def migration(country_code='MX'):
    fname = 'spanish/users_by_country/%s.json.gz' % country_code
    d = read_data(fname)
    other = Counter()
    for x in d.values():
        if len(x) == 1:
            continue
        c = Counter(x)
        for xx in c.most_common()[1:]:
            if xx[0] == country_code:
                continue
            other[xx[0]] += 1
    return other

In [ ]:
plt.figure(figsize=(10, 10))
for k, c in enumerate(['US', 'AR', 'MX', 'ES']):
    other = migration(c)
    mc = other.most_common()
    first = mc[:size]
    extra = ('REST', sum([x[1] for x in mc[size:]]))
    first.append(extra)
    plt.subplot(2, 2, k+1)
    _ = plt.pie([x[1] for x in first], labels=[x[0] for x in first])
    plt.title(c)

Agradecimientos

Las ideas presentadas en este documento fueron inspiradas por la colaboración con INEGI (Gerardo Leyva, Alfredo Bustos, Juan Muñoz, Silvia Fraustro y Abel Coronado). Se agradece a Johannes Eichstaedt y Andy Schwartz, quienes sugirieron realizar el análisis por usuario para remover el sezgo entre usuarios.

¿Preguntas?