Análisis de sentimiento de mercado

El análisis de sentimiento de mercado determina el grado de consenso en la actitud de los inversores hacia un determinado activo o al mercado en su conjunto. Mide la sensación o sentimiento de mercado, o su psicología, revelada a través del movimiento del precio.

El sentimiento puede ser clasificado como alcista, bajista o neutral. Se usan herramientas procedentes del procesamiento del lenguaje natural, minería de datos y aprendizaje automático. No siempre se basa en aspectos fundamentales, ya que los inversores podrían tener una visión particular basada en lo que sienten y no en lo que ven. Compra el rumor, vende con la noticia… Si el sentimiento bajista prevalece los activos caen y viceversa.

El sentimiento es un indicador retardado. Se observará algún cambio en el indicador después de un movimiento y no antes. Por eso debe ser una herramienta adicional y no usada como única referencia.

Existen al menos cinco (5) enfoques principales para medir la atención de los inversionistas:

  • Medidas basadas en el mercado financiero.
  • Índices de sentimiento basados en encuestas.
  • Sentimiento textual de recursos en línea especializados.
  • Comportamiento de búsqueda en Internet y
  • Factores no económicos.

Entre los indicadores basados en encuestas, son conocidos: el AAII Toro y Oso (Bull and Bear), el más popular que se realiza en Wall Street; el Índice de Miedo y Codicia de CNN (CNN Fear and Greed index), toma en cuenta diferentes variables que se refieren al sentimiento del mercado como el índice VIX de volatilidad, sus resultados se muestran en una escala de 0 a 100; y el Sentimiento de mercado de XTB, el cual se puede comprobar también en la plataforma xStation 5 para distintas acciones.

Sentimiento textual de recursos en línea especializados

Ciertas investigaciones reportan el poder predictivo de los datos con respecto al comportamiento de los precios de las acciones. Las redes sociales como Facebook y Twitter, las plataformas de medios de comunicación relacionadas con las finanzas, las revistas y los periódicos pueden ser una fuente valiosa de datos de sentimientos. Basado en este conocimiento, hace unos años una empresa, Derwent Capital Markets pretendió sacar provecho y creó el fondo Absolute Return, el primer fondo de cobertura de Twitter del mundo, pero cerró al cabo de trece meses.

Para analizar la influencia de los datos de las plataformas de micro-blogging en el comportamiento de las cotizaciones bursátiles se construyen índices especiales de seguimiento del estado de ánimo. La manera más fácil es contando el número de palabras “positivas” y “negativas” en cada tweet relevante y construir un indicador combinado basado en estos datos.

Otros enfoques se basan en vincular el número de tweets con los movimientos esperados de las acciones. Con estos datos se construye un modelo de aprendizaje automático para la predicción el cual muestra una correlación significativa con los rendimientos anormales acumulados.

Existen diferentes métodos:

  • Búsqueda de palabras clave,
  • Afinidad léxica y
  • Métodos estadísticos.

Búsqueda de palabras claves

Incluye el desarrollo de una lista de palabras claves que se relacionan con un cierto sentimiento. Estas palabras, conocidas como palabras afectivas, suelen ser adjetivos positivos o negativos porque tales palabras pueden ser fuertes indicadores de sentimiento. Clasifica el texto por categorías de afecto basadas en la presencia de palabras afectivas inequívocas como alegre, triste, temerosa y aburrida.

Limitaciones

  • 􏰀Escaso reconocimiento de los afectos cuando la negación está involucrada. Mientras clasifica correctamente la frase hoy fue un día feliz como ser feliz, es probable que fracase en una frase como hoy no fue un día feliz.

  • 􏰀Dependencia en características superficiales. El enfoque se basa en la presencia de palabras afectivas obvias que son sólo rasgos superficiales de la prosa.

Afinidad léxica

Es ligeramente más sofisticada que la anterior. Más que detectar palabras obvias de afecto, asigna a las palabras una afinidad para una emoción en particular. Por ejemplo, a accidente podría asignársele un 75% de probabilidad de estar indicando un efecto negativo, como en accidente de auto o herido por accidente.

Limitaciones

Aunque con frecuencia se desempeña mejor que la búsqueda de palabras, la afinidad léxica operando únicamente al nivel de las palabras, puede fácilmente fallar con frases como evité un accidente (negación) y me encontré con mi novia por accidente (otros sentidos de la palabra).

Métodos estadísticos

Se alimenta un algoritmo de aprendizaje automático con un gran corpus de textos comentados afectivamente. El sistema aprende la valencia afectiva de las palabras claves de afecto y toma en cuenta la valencia de otras palabras claves arbitrarias, la puntuación y las frecuencias de co-ocurrencia de palabras. La polaridad se identifica estudiando las frecuencias de ocurrencias de la palabras en un gran corpus de textos anotados. Si la palabra ocurre con más frecuencia entre textos positivos entonces su polaridad es positiva y viceversa. Si son iguales, entonces es neutra. Si dos palabras aparecen juntas frecuentemente dentro del mismo contexto, es probable que tengan la misma polaridad. La polaridad de una palabra desconocida puede determinarse calculando la frecuencia relativa de co-ocurrencia con otra palabra.

Limitaciones

Los métodos estadísticos tradicionales son por lo general semánticamente débiles, así que, con la excepción de palabras claves de afecto obvio, otros elementos léxicos o de co-ocurrencia en un modelo estadístico tienen poco valor predictivo individualmente. Como resultado sólo funcionan con una precisión aceptable cuando se les da una entrada de texto suficientemente grande. Si bien podrían ser capaces de clasificar afectivamente el texto del usuario a nivel de página o párrafo, no lo hacen bien en unidades de texto más pequeñas como oraciones o frases, como en Twitter porque estas son breves y suelen contener jerga, emoticones, hash tags y otros términos específicos de twitter.

El problema

El objetivo es detectar el sentimiento del mercado en los tweets. Un tweet contiene expresiones de sentimiento si tiene un sentimiento alcista o bajista asociado. Por lo tanto, la tarea es distinguir los tweets alcistas o bajistas de los tweets neutros. Formalmente, dada una muestra de formación de tweets y etiquetas, la etiqueta 1 denotará que el tweet es alcista y la etiqueta 2 que el tweet es bajista, y la 0 que es neutral. El objetivo es predecir las etiquetas en el conjunto de datos de prueba dado.

Preprocesamiento y limpieza

  1. Selección de la muestra representativa.
  2. Seleccionar las variables que son relevantes de las 88 que trae cada twitter:
    • Fecha/Hora
    • Contenido
    • autor
    • tweet_id
    • País
    • Código de país
    • Georeferencia
    • Coordenadas
    • Lugar según usuario

Del contenido se limpia el ruido de lo que sea menos relevante, como la puntuación, caracteres especiales, números y términos que no tienen mucho peso en el contexto del texto. También se eliminan palabras pequeñas que no añaden mucho valor. Por ejemplo, en inglés: pdx, his, all.

Se extraen las características numéricas de los datos de texto. Este espacio de características se crea utilizando todas las palabras únicas presentes en todos los datos. Por lo tanto, si se preprocesan bien los datos, se obtiene un espacio de características de mejor calidad.

  • Primero se leen los datos y se cargan las librerías necesarias según se use R o Phyton.

  • Se crean los conjuntos de datos para entrenamiento (train) y para pruebas (tests).

  • Se analizan los primeros tweets para identificar las palabras con contenido. En nuestro caso es obligatoria la mención a las etiquetas de las acciones, por ejemplo BABA, correspondiente a la empresa de compras china por internet Alibaba. además de palabras que contengan una carga afectiva relacionada con esta empresa o sus acciones.

  • Remoción de identificadores de twitter, es decir términos similares a @loquesea.

  • Una vez removidos los términos indeseados, se crea una columna adicional en la cual se almacena el contenido en limpio de los tweets.

  • Se tokenizan (tokenizar un conjunto de datos significa tratar de substituirlos por otro conjunto) todos los tweets limpios. Los tokens son términos o palabras individuales, y la tokenización es el proceso de dividir una cadena de texto en tokens.

  • Derivación (stemming) Proceso basado en reglas para quitar los sufijos (en inglés: ing, ly, es, s, etc.) de una palabra. Por ejemplo: jugar, jugador, jugado, jugadas y jugando son las diferentes variaciones de la palabra: jugar.

Extracción de características de tweets limpios

Se convierte los datos en características. Dependiendo del uso, éstas se construyen utilizando diversas técnicas: bolsa de palabras (Bag-of-Words) la cual representa texto en características numéricas; TF-IDF (Term Frequency - Inverse Document Frequency) e incrustaciones de palabras (Word Embeddings).

El TF-IDF se basa en el método de frecuencia y tiene en cuenta, la aparición de una palabra en todo los documentos. Penaliza las palabras comunes al asignarles pesos más bajos al tiempo que da importancia a las palabras que son raras en todo el corpus pero que aparecen con frecuencia en pocos documentos:

Incrustación de palabras: Conjunto de modelos de lenguaje y técnicas de aprendizaje de características en el procesamiento del lenguaje natural, donde las palabras o frases del vocabulario se asignan a vectores de números reales. La idea subyacente es que una palabra se caracteriza por la compañía que tiene.

Construcción de Modelos: Análisis de Sentimientos

Se usa la regresión logística para construir los modelos. Se entrena el modelo de regresión logística en las características de la Bolsa de Palabras y el puntaje obtenido para el conjunto de validación, se utiliza para predecir los datos de la prueba. Se repiten los mismos pasos anteriores pero con la matriz obtenida TF-IDF.

Consideremos ahora las operaciones necesarias para construir una app que le indique al usuario el sentimiento de mercado respecto a una o varias acciones de bolsa.

Pasos para resolver un problema general de análisis de sentimientos

  1. Comprender el problema
  2. Preparación
  3. Extracción de tweets con la aplicación Twitter Archiver de Google Sheets
  4. Preprocesamiento y limpieza de los tweets para análisis posteriores
  5. Obtener puntuación de sentimiento para cada tweet
  6. Extracción de tweets con sentimientos positivos, negativos y neutros
  7. Presentación de resultados

El problema

Recordemos que el objetivo es detectar el sentimiento del mercado en los tweets. Un tweet contiene expresiones de sentimiento si tiene un sentimiento alcista (positivo) o bajista (negativo) asociado con él. Por lo tanto, la tarea es distinguir los tweets alcistas o bajistas de los tweets neutros.

Preparación

Cargamos los paquetes que se utilizarán en el análisis de sentimiento. Los más importantes en R son:

  • tidyverse: para importar múltiples paquetes que facilitarán el análisis y manipulación de datos
  • tidytext: herramientas para manipular texto
  • tm: herramientas de minería de textos
  • lubridate: para manejar fechas de manera consistente, y
  • zoo y scales: para realizar tareas comunes de análisis y presentación de datos.
  • SnowballC: minería y análisis de textos
  • rtweet: Para extraer tweets de Twitter
  • Syuzhet: para el análisis de sentimientos(

Extracción de tweets con el complemento Twitter Archiver de Google Sheets

Aunque es posible registrarse en Twitter como desarrollador una alternativa es utilizar directamente la app de Google Sheets Twitter Archiver en su versión gratuita:

  1. Se buscan tweets que contengan las etiquetas que identifica las acciones en las que se está interesado. La recuperación se recomienda efectuarla en períodos de tiempo reciente para que sean relevantes al estudio, por ejemplo tomando muestras de las 12/24 horas anteriores a la publicación del análisis. Se pueden abrir varias cuentas de Gmail y Twitter como acciones se deseen consultar. Como prueba elegimos las acciones de Apple: $AAPL.

  2. Selección de las variables relevantes de las 88 que trae cada twitter:

    • Fecha/Hora: Date
    • Contenido: Tweet Text
    • Autor: Screen Name
    • Identificación del tweet: Tweet ID
    • Localización según usuario: location

Aplicando los criterios anteriores se extraen los datos con los tweets, por palabra (una etiqueta para cada acción) e idioma (inglés), obtenidos usando Twitter Archiver. Los datos se descargan en el directorio del proyecto, como archivos de texto separados por coma (csv) y para identificarlos, se denotan con la etiqueta de cada acción. Para acelerar el proceso se selecciona solo la columna con el texto de los tweets.

La función siguiente realiza el proceso de extracción de los tweets en inglés para el caso de las acciones de la empresa Apple, identificada con la etiqueta AAPL:

l <- read.csv2("$AAPL.csv",header = TRUE,sep = ",",skip=1)
l <- as.data.frame(l)

Preprocesamiento y limpieza de los tweets para análisis posteriores

El campo text contiene la parte de tweet, hashtags y URLs.

  1. Se eliminan los hashtags, URLs y otros caracteres especiales con la función gsub del campo de texto para que sólo quede la parte principal del tweet para ejecutar el análisis de sentimientos:
tweets.df2 <- gsub("http.*","",l$Tweet.Text)
tweets.df2 <- gsub("https.*","",tweets.df2)
tweets.df2 <- gsub("#.*","",tweets.df2)
tweets.df2 <- gsub("@.*","",tweets.df2)
  1. Se procede a la limpieza los tweets:
head(tweets.df2)
  1. Ahora, sólo queda la parte relevante de los tweets con lo cual se puede ejecutar la parte de análisis de sentimientos sobre los datos.

Obtener puntuación de sentimiento para cada tweet

  1. Primero se obtiene la puntuación de emoción para cada uno de los tweets. Syuzhet divide la emoción en 10 emociones diferentes: ira, anticipación, asco, miedo, alegría, tristeza, sorpresa, confianza, negativo y positivo.
word.df <- as.vector(tweets.df2)
emocion.df <- get_nrc_sentiment(word.df) #Conteo de las palabras con emociones por cada tweet
emocion.df2 <- cbind(tweets.df2, emocion.df) #Combinación de los tweets limpios con el conteo de las palabras que implican emociones 
head(emocion.df2)
tweets.df2                                                                            

….

# anger anticipation disgust fear joy sadness surprise trust negative positive
1 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 1 0
3 0 0 0 0 0 0 0 0 0 0
4 1 0 1 1 0 1 0 0 1 0
5 0 0 0 0 1 0 0 1 0 1
6 0 1 0 0 0 0 0 0 0 1

El resultado muestra las diferentes emociones presentes en cada uno de los tweets.

  1. Ahora, se usa la función get_sentiment para extraer la puntuación de sentimiento para cada uno de los tweets. Primero el más positivo:
sent.value <- get_sentiment(word.df)
mas.positivo <- word.df[sent.value == max(sent.value)]
mas.positivo

[1] “$AAPL $ADP $AFL NEW ARTICLE : Many Happy Returns As The Dividend Growth 50 Celebrates Its 5th Birthday Get all the latest $AAPL related news here :”

y ahora el más negativo:

 
sent.value <- get_sentiment(word.df)
mas.negativo <- word.df[sent.value == min(sent.value)]
mas.negativo

[1] “$SPY $QQQ $TVIX $AAPL Welp here’s the horrible bears not blaming their performance and gambling skills so they blame manipulation. HOLD LONG, PAIN PUMP coming. Heading out to catch some bass.”

Obsérvese cómo se ha calculado la puntuación de cada uno de los tweets. En total, aparecerán tantas puntuaciones positivas/negativas como tweets analizados, una para cada uno de los tweets.

head(sent.value)

[1] 0.00 -0.40 0.00 -1.00 1.05 0.40

Extracción de tweets con sentimientos positivos, negativos y neutros

Se separan los tweets positivos y negativos en función de la puntuación asignada a cada uno de los tweets.

Tweets positivos

tweets.positivos <- word.df[sent.value > 0]
head(tweets.positivos)

[1] “Boris Johnson Will Test Out His New Parliamentary Majority | Quadruple Witching: $KMX, $WGO, $SCHL, $BB, $NKE, $AAPL, $BIIB & more… “
….

Tweets negativos

tweets.negativos <- word.df[sent.value < 0]
head(tweets.negativos)

[1] “I had the craziest dream!! $AAPL did a 20/1 split… is it true?!!!!? HahahHa…! Lol. Because that would be the most bullish event ever for $AAPL. Almost as bullish as this upcoming $BABA split”
….

Tweets neutrales

tweets.neutrales <- word.df[sent.value == 0]
head(tweets.neutrales)

[1] “”
[2] “$DIS $NFLX $CMCSA $AAPL: Apple Likely to Add James Bond & College Sports to Apple TV+:”

Alternativa para clasificar los tweets como Positivos, Negativos o Neutros

category_senti <- ifelse(sent.value < 0, "Negativo", ifelse(sent.value > 0, "Positivo", "Neutral"))
category_senti<-as.data.frame(category_senti)
head(category_senti)

   category_senti
 1        Neutral
 2       Negativo
 3        Neutral
 4       Negativo
 5       Positivo
 6       Positivo

Presentación de resultados al usuario con App de Shiny

Para la presentación de resultados se diseña un app con Shinydashboard. Con ella el usuario obtiene una calificación del sentimiento del mercado respecto a una acción determinada. Para ello deberá seleccionarla a partir de los nombres de los archivos *.csv. El resultado serán tres pestañas: la primera indicará cuan positivo percibe el mercado a la acción elegida con ayuda de un odómetro; la segunda distribuye la totalidad de tweets según su calificación de sentimiento en un gráfico de barras; y la tercera, presentará el encabezado o la totalidad de los tweets de la muestra. Para la construcción de la app haremos uso de r en la interfaz gráfica de rstudio y utilizaremos rmarkdown para documentar y generar la app de shiny

Librerías

Primero nos aseguramos de tener instaladas las siguientes librerías de r:

library(shiny)
library(shinythemes)
library(tidyverse)
library(tidytext)
library(tm)
library(lubridate) #Para arreglos de fechas
library(zoo)
library(scales)
library(rtweet)
library(SnowballC)
library(twitteR)
library(syuzhet)# Puntea las palabras emocionales
library(shinythemes )
library(flexdashboard)
library(grid) #Añade texto estático a gráficos
library(tools) #Extrae el nombre del archivo sin la extensión
library(reshape2) #Convierte tablas de formato ancho a largo y viceversa
library(shinydashboard)

Construcción de la app de shiny

Cada app de shiny se compone como mínimo de 2 archivos (opcionalmente contiene archivos extra): la interfaz de usuario o ui^, la cual contiene la secuencia de comandos que controla el diseño y aspecto de la aplicación; y el *server, el cual consta de las instrucciones que constituyen los componentes de R del app, en otras palabras, contiene las instrucciones que el equipo necesita para construir su aplicación. A continuación se describen los códigos para cada sección de la app:

I. Interfaz de usuario o ui

ui <- dashboardPage(skin = "green",
                    dashboardHeader(title = span(tagList(icon = icon("fab fa-twitter"),"Sentimiento del mercado usando Twitter")),titleWidth = 500
                                    ),
                    dashboardSidebar(br(),h5("La app realiza el análisis de sentimiento de mercado acerca de alguna de las acciones de las principales empresas del mundo en base a muestras recientes de Twitter."), 
 br(),               
                      sidebarMenu(
                        menuItem("Positividad", tabName = "dashboard", icon = icon("dashboard")),
                        menuItem("Distribución del sentimiento", tabName = "bar", icon = icon("fas fa-chart-bar")),
                        menuItem("Contenido de tweets", tabName = "tweets", icon = icon("fab fa-twitter-square"))
                      )
                    ),
                    dashboardBody(
                      tabItems(

 #Contenido de la primera pestaña
tabItem(tabName = "dashboard",
                                fluidRow(
                                  box(width=4, height=550,
                                    title = "Seleccione la acción",status = "danger",solidHeader = TRUE,
                                    fileInput("file", "Haga clic en el explorador para elegir el archivo CSV con el nombre de la acción",
                                              multiple = FALSE,buttonLabel = "Busque...",placeholder = "Ningún archivo",
                                              accept = ".csv"),
      # Línea Horizontal  ----
                                    tags$hr(),   
                                    # Línea Horizontal ----
                                    tags$hr()
                                  ),
                                  box(width=8,height =  550,
 #Nombre de la acción
                                    tags$b(align="left",h2(textOutput("accion", container = span))), solidHeader = TRUE,
                                    status = "info", 
 #Coloca el día y hora del análisis.
                                    tags$b(align="center",h3(textOutput("currentTime", container = span))),
                                    
 # Salida: Gráfico de medidor ----
                                    plotOutput("Sentimiento")           
                                  ))),     
                                
 #Contenido de la segunda pestaña__
                        tabItem(tabName = "bar",
                                wellPanel(
                                fluidRow(
                                  box(width=12,
                                  h2("Distribución del sentimiento del mercado"),
                                    br(),
                                    infoBoxOutput("progressBox"),
                                    br(),
                                    
   #Gráfico de barras
                                    tags$b(align="left"),
                                    plotOutput("barras")

                                  )))),
                        
 #Contenido de la tercera pestaña
                        tabItem(tabName = "tweets",
                                fluidRow(
                                  box(width = 4,
                                  
   #Entrada: Seleccione el número de filas a desplegar----
                                  radioButtons("disp", "Muestre",
                                               choices = c(Encabezado = "head",
                                                           Todo = "Todo"),
                                               selected = "head")
                                  ),
                                  
                                  box(width = 8,
                                    h2("Contenidos de los tweets"),

                                    
  #Nombre de la salida
                                    #tags$b(align="left",h2(textOutput("Contenido", container = span))),
                                    tableOutput("contenido")                    
                                  )))      
                      )
                    ),
                    tags$head(
                      tags$img(src='vision.svg',height='80',width='230'),
                      tags$style(HTML('
                                      .skin-blue .main-header .logo{
                                      background-color: #fff;
                                      color: #201545;
                                      }
                                      .skin-blue .main-header .navbar {
                                      background-color: #201545;
                                      }
                                      .skin-blue .main-sidebar{
                                      background-color: #201545;
                                      }
                                      .skin-blue .sidebar-menu>li.active>a{
                                      background: #201545;
                                      }
                                      '))
                      )
                      )

II. Contenido del Server

server <- function(input, output) {
  datos <- reactive({
    file1 <- input$file
    if(is.null(file1)){return()} 
    read.csv(as.character(file1$datapath),header = TRUE,
               sep=',',
               quote='"',
               skip = 1 ) 
  })  
  valores <- reactive({
    if(is.null(datos())){return ()}
  #Limpieza de tweets
    tweets.df2 <- gsub("http.*","",datos()$Tweet.Text)
    tweets.df2 <- gsub("https.*","",tweets.df2)
    tweets.df2 <- gsub("#.*","",tweets.df2)
      
    #Obtener puntuación de sentimiento para cada tweet
    word.df <- as.vector(tweets.df2)
    emotion.df <- get_nrc_sentiment(word.df) #Conteo de las palabras con emociones por cada tweet
    emotion.df2 <- cbind(tweets.df2, emotion.df) #Combinación de los tweets limpios con el conteo de las palabras que implican emociones 
    sent.value <- get_sentiment(word.df)
    
    #Alternativa para clasificar los tweets como Positivos, Negativos o Neutros
    category_senti <- ifelse(sent.value < 0, "Negativo", ifelse(sent.value > 0, "Positivo", "Neutral"))
    category_senti<-as.data.frame(category_senti)
    table(category_senti)  
  })
  output$accion <- renderText({
    br()
    paste0("Acción: ",file_path_sans_ext(input$file$name))
  })
  br()
  output$currentTime <- renderText({
    paste0("Positividad del sentimiento al ",format(today(),"%d/%m/%Y"))
  })
  output$Sentimiento <- renderPlot({
    req(input$file) 
    
  #Gráfico de velocidad en colores con ggplot2
    gg.gauge <- function(pos, breaks = c(0, 45, 55, 100), determinent) {
      require(ggplot2)
      get.poly <- function(a, b, r1 = 0.5, r2 = 1.0) {
        th.start <- pi * (1 - a / 100)
        th.end   <- pi * (1 - b / 100)
        th       <- seq(th.start, th.end, length = 1500)
        x        <- r1 * cos(th)
        xend     <- r2 * cos(th)
        y        <- r1 * sin(th)
        yend     <- r2 * sin(th)
        data.frame(x, y, xend, yend)
      }
      
      
      
      
      grob<-grobTree(textGrob(paste0(as.character(round(valores()[3]*100/(valores()[1]+valores()[3]),digits=0)),"%"),x=0.48,y=0.1,hjust=0,
                              gp=gpar(col="black" ,fontsize=16,fontface="bold")))
      ggplot() + 
        geom_segment(data = get.poly(breaks[1],breaks[4]), 
                     aes(x = x, y = y, xend = xend, yend = yend, color = xend),lwd=3) +
        scale_color_gradientn(colors = c("red", "gold", "green")) +
        geom_segment(data = get.poly(pos - 1, pos + 1, 0.2), aes(x = x, y  =y, xend = xend, yend = yend)) +
        geom_text(data=as.data.frame(breaks), size = 5, fontface = "bold", vjust = 0,
                  aes(x = 0.8 * cos(pi * (1 - breaks / 100)),  y = -0.1), label = c('Nada Positivo', '', '', "100% Positivo")) +
        #annotate("text", x 0, y=0, label=determinent,vjust=0,size=8,fontface="bold")+
        coord_fixed()+
        theme_bw()+
        theme(axis.text=element_blank(),
              axis.title=element_blank(),
              axis.ticks=element_blank(),
              panel.grid=element_blank(),
              panel.border=element_blank(),
              legend.position = "none")+
        annotation_custom(grob)
    }
    velocimetro<-try(gg.gauge(valores()[3]*100/(valores()[1]+valores()[3]),breaks=c(0,45,55,100)))
    if(class(velocimetro)[1]=="try-error"){
      df<-data.frame()
      ggplot(df)+geom_point()+xlim(0,10)+ylim(0,100)+theme_void()
    }else{velocimetro}    
  })
  
  # Genera un gráfico de barras
  br()
  output$progressBox <- renderInfoBox({
    jj<-try(infoBox("Total de Tweets",as.character(valores()[1]+valores()[2]+valores()[3]), icon = icon("list"),
         color = "purple", fill = TRUE))
    if(class(jj)[1]=="try-error"){
      infoBox("Total de Tweets", 0, icon = icon("list"),
              color = "purple", fill = TRUE)
    }else{jj}
})
    br()
  output$barras<-renderPlot({
    req(input$file)
    conteo<-try(ggplot(melt(valores()), aes(x=melt(valores())[,1], y=melt(valores())[,2],fill=melt(valores())[,1])) )
    if(class(conteo)[1]=="try-error"){
      df<-data.frame()
      ggplot(df)+geom_point()+xlim(0,10)+ylim(0,100)+theme_void()
    }else{
         conteo+ geom_bar(colour="black",stat="identity")+
        scale_fill_manual(values=c("red", "white", "green"))+
        guides(fill=FALSE)+
        xlab("Tipo de sentimiento") + ylab("Cantidad de Tweets") +
        ggtitle("Diagrama de barras para el sentimiento del mercado")+
        theme(axis.text = element_text(size = 12))+
        theme(axis.title = element_text(size = 16))+
        theme(plot.title = element_text(size = 20))
    }
  })
  br()
  
  # Muestra el contenido de los tutis de la muestra
  output$contenido <- renderTable({
    req(input$file) 
    df <- try(read.csv(as.character(input$file$datapath),
                       header = TRUE,
                       sep=',',
                       quote='"',
                       skip = 1))
    if(class(df)[1]=="try-error"){
      df<-data.frame()
    }else{df}
    if(input$disp == "head") {
      return(head(df$Tweet.Text))
    }
    else {
      return(df$Tweet.Text)
    }    
  })
}

III. Creación de la app de Shiny

shinyApp(ui, server)

Conclusión

La herramienta mostrada permite a profesionales del trading y a empresas de cualquier tamaño, conducir de manera independiente sus propias investigaciones de mercado, ajustándolas a su necesidades. Pueden emplearlas también para comparar con indicadores de sentimiento de otras fuentes y así estimar la confiabilidad de las mismas.

En todo caso es esencial que al hacer uso del análisis de sentimiento se tenga siempre presente que es un indicador retardado, y es solamente un complemento para otros análisis que necesariamente deben hacerse antes de tomar una decisión.

Copyright © 2014-2019 Synergy Vision. Los artículos del Corpus se comparten bajo los términos de la licencia Creative Commons con Reconocimiento, Propósito no comercial, Compartir contenido similar, 4.0 Internacional (CC BY-NC-SA 4.0).

Citar el artículo.