#!/usr/bin/env python
# coding: utf-8
# ![](imgs/miredtwitter_header2.png)
#
#
# Recomendación de Información basada en
# Análisis de Redes Sociales
# y Procesamiento de Lenguaje Natural
#
# Trabajo Final de la Licenciatura en Ciencias de la Computación
# Pablo Gabriel Celayes
# Martes 30 de mayo de 2017
#
# # Resumen
#
# * Introducción
#
# * Herramientas
#
# * Datos
#
# * Predicción social
#
# * Agregando PLN
#
# * Conclusiones
# # Introducción
# ## Idea original
#
# - Recomendador *personalizado* de artículos basado en contenido ( NLP )
# - Mejorarlo con información social ( de fuentes externas o relaciones *inferidas* )
# - Preferencias de usuarios de Cogfor
#
# ![](imgs/cogfor.png)
# ## Mutación
#
# - Set the datos propio ( usuarios, preferencias, conexiones )
# - Predecir preferencias usando información social
# - Combinar con recomendación basada en contenido
#
# # Herramientas
#
# ## Datos
# ![](imgs/tweepy.png)
# ![](imgs/sqlalchemy.png)
#
# ## Grafos
# ![](imgs/networkx.png)
# ![](imgs/graphtool.png)
# ## Análisis
# ![](imgs/numpy.png)
# ![](imgs/pandas.png)
# ![](imgs/jupyter.png)
#
# ## ML + PLN
# ![](imgs/sklearn.png)
# ![](imgs/nltk.png)
# ![](imgs/gensim.png)
# ## Visualización
# ![](imgs/bokeh.png)
# ![](imgs/gephi_small.png)
# # Datos: Grafo social
#
# - Todos los usuarios que sigo en Twitter
# - relación $\texttt{seguir}$ entre ellos
# - $1213$ nodos-usuarios
# - $40489$ aristas-relaciones
# ![](imgs/miredtwitter.png)
#
# # Datos: Contenido
#
# - *timelines* entre 18/3/2017 y 17/4/2017 (+ *retweets* y *favs*)
# - $163173$ tweets totales.
# - $109040$ en español
#
# # Predicción social
#
# ¿ Dado un usuario, cuanto puedo saber de sus preferencias sabiendo las de su entorno ?
#
# - **Contenido** = tweets en español
# - **Preferencias** = retweets
# - **Entorno** = seguidos + seguidos-por-seguidos
#
# ## Selección de usuarios
#
# * Al menos $100$ (re)tweets
# * Al menos $100$ usuarios en su entorno
# * $98$ usuarios
# ## Tweets visibles
#
# * Contenido compartido por $u$ o sus seguidos
# * Excluímos contenido generado por $u$
# * $ T_u := (\bigcup_{x \in \{ u \} \cup \texttt{seguidos}(u)} \texttt{timeline}(x)) - \{ t \in T | \texttt{autor}(t) = u \} $
#
# * máximo $10000$ ( submuestra de negativos si es necesario )
# ## Extracción de características
#
# * Entorno $ E_u = (\bigcup_{x \in \{ u \} \cup \texttt{seguidos}(u)} \texttt{seguidos}(x)) - \{ u \} $
# * $E_u = \{u_1, u_2, \ldots , u_n \}$ y $T_u = \{ t_1, \ldots, t_m \}$
#
# $$
# M_u := [ \verb|tweet_en_tl|(t_i, u_j) ]_{\substack{ 1 \leq i \leq m \\ 1 \leq j \leq n}}
# $$
#
#
# $$
# y_u := [ \texttt{tweet_en_tl}(t_i, u) ]_{ 1 \leq i \leq m }
# $$
#
#
# ## Problema de clasificación
#
# * Predecir $y_u$ en base a filas de $M_u$
# * Particionado:
# * $70\%$ entrenamiento ($M^{en}_u, y^{en}_u$)
# * $10\%$ ajuste ($M^{aj}_u, y^{aj}_u$)
# * $20\%$ evaluación ($M^{ev}_u, y^{ev}_u$)
# ## Support Vector Machines
#
# * Objetivo: **maximizar** margen y **minimizar** errores
# * Funciones *kernel* permiten encontrar fronteras **no lineales**:
# * *Radial Basis Function*
# * Polinómico
#
# ![](imgs/svm_linsep_err.png)
#
#
# ## Calidad de clasificación
#
# $$\texttt{precision} := \frac{|\{x_i | f(x_i) = 1 \text{ y } y_i = 1 \}|}{|\{x_i | f(x_i) = 1 \}|}$$
#
# $$ $$
#
# $$\texttt{recall} := \frac{|\{x_i | f(x_i) = 1 \text{ y } y_i = 1 \}|}{|\{x_i | y_i = 1 \}|}$$
#
# $$ $$
#
# $$\texttt{F1} := \frac{2}{\frac{1}{\texttt{precision}} + \frac{1}{\texttt{recall}}} = \frac{2 * \texttt{precision} * \texttt{recall} }{\texttt{precision} + \texttt{recall}}$$
#
#
# ## Ajuste de parámetros
#
# * Búsqueda exhaustiva $\verb|GridSearchCV|$
# * Validación cruzada en $3$ partes
# * Objetivo: maximizar $F1$
# * Grilla:
# ```
# {
# "C": [ 0.01, 0.1, 1 ],
# "class_weight": [ "balanced", None ],
# "gamma": [ 0.1, 1, 10 ],
# "kernel": [ "rbf", "poly" ]
# }
# ```
# * $C$: controla balance entre margen y errores
# * $class\_weight$: ¿dar más importancia a clase minoritaria?
# * $gamma$: forma de la frontera de decisión
# ## Resultados
#
# * $F1$ sobre $M^{aj}_u$
# * Promedio $0,84$
#
# ![](imgs/f1svalidsocial__.png)
# # *¡Y sin tener en cuenta el contenido!*
#
#
#
# ![](imgs/robot2.png)
# # Agregando PLN
#
# ## Selección de usuarios
#
# * $F1 < 0,75$ en $M^{aj}_u$ ( $23$ usuarios )
#
# * $10$ usuarios más (al azar)
# ## Pre-procesamiento
#
# - Normalización
# - Tokenizado
# - Extracción de frases
# - Diccionario de términos
# - *Bag of terms*
# - LDA
#
# ## Normalización
#
# ![](imgs/normalize.png)
# ## Tokenizado
#
# ![](imgs/tokenize.png)
# ## Extracción de frases
#
# * $\verb|Phraser|$ de $\verb|gensim|$
# * Bigramas $a\ b$ relevantes:
# * $min\_count = 5$
# * $cnt(a, b) \geq min\_count$
# * $ \frac{(cnt(a, b) - min\_count) * N}{cnt(a) * cnt(b)} > 10 $
# * 2 pasadas sobre el corpus tokenizado ( bigramas y trigramas )
# ## Diccionario de términos
#
# * $T$ retokenizado con frases
# * término = palabra o frase
# * significativo ( al menos $3$ veces ).
# * informativo ( en menos del $30\%$ de los tweets ).
#
# * Diccionario $D$ de $26201$ términos.
#
#
# ## *Bag of terms*
#
# - Texto $t$: $\rightarrow$ multiconjunto (*bag*) de los términos en $t$.
# - No importa el orden, pero sí repeticiones.
# - En tweets ( $\leq 140$ caracteres ), en general son *conjuntos* ( $0$ o $1$ ocurrencia).
# - Diccionario fijo $D = \{ t_1, \ldots, t_{26201} \}$ : $\rightarrow$ vector de características enteras (booleanas):
#
# $$ v_{BOT}(tweet) = [count(t_i, tokens(tweet))]_{i=1}^{26201} $$
#
# - $v_{BOT}$ se representa ralo (*sparse*):
#
# ![](imgs/bagofterms.png)
#
# ## LDA
#
# * Descubre temas subyacentes en textos
#
# * Reducción de dimensionalidad ( espacio de *términos* a espacio de *temas* )
#
# * Probamos modelos de $10$ y $20$ temas
#
# ### Ejemplo: LDA 10 temas
#
# ![](imgs/lda10.png)
# ## Extendiendo características
#
# * Características sociales + LDA:
#
# ![](imgs/socialldavec.png)
#
# * Agregamos escalado ( cada columna con media $0$ y varianza $1$ )
# ## Evaluando sobre $M_u^{ev}$
#
# * $LDA10$
# * mejora para $4$ usuarios
# * mejora media de $2,8\%$
# * $LDA20$
# * mejora para $5$ usuarios
# * mejora media de $3,8\%$.
# ![](imgs/f1lda_eval.png)
# ## Sobreajuste
# ![](imgs/f1lda_train.png)
#
# ## Discretizando...
#
# * Sobreajuste puede venir de características *demasiado* descriptivas
# * Asignamos $1$ para cada tema con puntaje $\geq 0,25$ y $0$ en caso contrario
# ## Mejoras?
#
# * $LDAbool10$
# * mejora para $8$ usuarios
# * mejora media de $2,4\%$
# * $LDAbool20$
# * mejora para $7$ usuarios
# * mejora media de $2,5\%$.
#
# Impacta a más usuarios, pero mejora menos
# ![](imgs/f1ldabool_eval.png)
# ## ...pero sigue el sobreajuste
#
# ![](imgs/f1ldabool_train.png)
#
# # Conclusiones
#
# * Predicción social pura mejor de lo esperado
# * LDA mejora casos flojos, pero hay que resolver sobreajuste
# * Twitter es muy buena fuente de datos
# # Próximos pasos
#
# - Reducir sobreajuste
# - Características adicionales
# - Considerar temporalidad
# - Generalizar ( modelo que no dependa del usuario )
#
# # ¿Preguntas?
#
# ![](imgs/twitter.png) @PCelayes
#
# ![](imgs/github.jpg) https://github.com/pablocelayes/sna_classifier
#
#