Juan David Velásquez Henao
jdvelasq@unal.edu.co
Universidad Nacional de Colombia, Sede Medellín
Facultad de Minas
Medellín, Colombia
[Licencia]
[Readme]
Software utilizado.
Este es un documento interactivo escrito como un notebook de Jupyter, en el cual se presenta un tutorial sobre regresión logistica usando R en el contexto de aprendizaje de maquinas. Los notebooks de Jupyter permiten incoporar simultáneamente código, texto, gráficos y ecuaciones. El código presentado en este notebook puede ejecutarse en los sistemas operativos Linux y OS X.
Haga click aquí para obtener instrucciones detalladas sobre como instalar Jupyter en Windows y Mac OS X.
Haga clic [aquí] para ver la última versión de este documento en nbviewer.
Descargue la última versión de este documento a su disco duro; luego, carguelo y ejecutelo en línea en Try Jupyter!
Haga clic aquí para ver el tutorial de visualización y gráficas.
Los modelos gráficos probabilisticos son representaciones en forma de grafo que describen la relación de independencia condicional entre un conjunto de variables aleatorias. Estos modelos proporcionan un marco poderoso para modelar las interacciones complejas entre varias variables aleatorias Y han sido existosamente aplicados a diagnostico médico así como a segmentación de imágenes.
Estos modelos manejan dos conceptos principales de dos ramas de la matemática, :
Esta sub-rama de la matemática estudia los objetos conocidos como grafos, los cuales consisten de dos conjuntos: vértices (o nodos) enumerados y las conexiones entre los vértices (o bordes). Por lo tanto, un grafo no es nada más que una descripción de puntos y conexiones entre ellos. Cada uno de estas conexiones pueden tener direcciones (flechas) que van desde el nodo fuente o cola hasta el vértice objetivo o cabeza. Cuando el grafo presenta direcciones se le denomina un grafo dirigido, de lo contrario se denomina un grafo no dirigido donde las conexiones se representan con lineas y no flechas.
Una forma común de describir un grafo como el anterior es a través de una matriz de adyacencia. Si tenemos $ V $ vértices en el grafo, una matriz de adyacencia es de dimensión $ V \times V $ cuyas entradas son cero si el vertice del número de la fila no está conectado con el vértice del número de la columna. Si existe una conexión, el valor es 1. Cuando se trata de grafos no dirigidos, la matriz siempre es simetrica.
Un vértice se denomina $ v_{i} $ mientras que un borde o conexión se denomina $ (v_{i},v_{j}) $ donde el vértice $ i $ es la fuente y el vértice $ j $ es el destino. Por lo tanto se dice que dos vertices están conectados si tienen un camino representado por una o varias conexiones entre los nodos que permitan llegar de $ i $ hasta $ j $. Por ejemplo, los nodos 2 y 6 están conectados ya que pasando a través del nodo 1 se pueden llegar. No obstante, note que del 6 al 2 no existe camino.
Cabe aclarar que no importa la posición de los puntos o conexiones, solo es relevante que las conexiones entre los nodos se encuentren correctas. Es por esto que para los dos grafos mostrados se pueden representar con la misma matriz de adyacencia.
Dado que para dos vertices cualesquiera pueden existir varios caminos, definimos la distancia entre dos nodos como el camino más corto entre ellos, esto es la longitud medida en nodos de dicho camino. Por lo tanto, la distancia entre el nodo 2 y 6, es igual a 1.
Adicionalmente un camino que empieza y termina en el mismo vértice se le conoce como un ciclo. Cuando un grafo no tiene un ciclo se le conoce como un grafo aciclico. Adicional, cuando tiene direcciones se le conoce como un grafo acíclico dirigido (DAG por sus siglas en inglés).
Muchos fenómenos reales pueden ser representandos como un grafo, ya sea las conexiones de amigos en facebook, o las redes de internet, de telecomunicaciones, de transporte, de electriciadad, etc.
Dentro de la aplicación de aprendizaje de maquinas, asumimos que los nodos son variables aleatorias y las conexiones son las dependencias entre ellas.
Para explorar más las variables aleatorias, se hace una corta introdución al teorema de Bayes. Para esto suponga que hay dos eventos $ A $ y $ B $. Por ejemplo el evento $ A $ puede ser que un paciente tenga apendicitis y el evento $ B $ que dicho paciente tenga alto nivel de globulos blancos. Por lo tanto, se define la probabilidad condicional de $ A $ dado $ B $ como lq proabilidad de que el evento $ A $ d suceda dado que el evento $ B $ ha sucedido anteriormente.
Matemáticamente, se define la proabilidad condicional como la división entre la probabilidad de que los dos eventos ocurran divido por la probabilidad de que el evento B ocurra:
$$ P(A|B)= \frac{P(A \cap B)}{P(B)} $$Note que si los eventos son independientes entre sí la ecuación es simplemente la probabilidad de $ A $, lo cual es consistente ya que la ocurrencia de $ B $ no influye en la probabilidad de $ B $.
$$ P(A|B)= \frac{P(A)·P(B)}{P(B)} = P(A) $$Por lo tanto se puede reexpresar la probabilidad conjunta como:
$$ P(A \cap B) = P(A|B) · P(B) = P(B|A)·P(A) $$Luego, se define el teorema de Bayes como:
$$ P(A|B)= \frac{P(B|A)·P(A)}{P(B)} = \frac{P(B|A)}{P(B)}·P(A)$$La anterior ecuación representa la probabilidad posterior de $ A $ dado que ha ocurrido $ B $, donde $ P(A) $ es la probabilidad a priori de la ocurrencia de $ B $ y el coeficiente $ \frac{P(B|A)}{P(B)} $ es el ajuste de la nueva información del evento $ B $ una vez ha ocurrido.
Existen ocasiones cuando dos variables $A, B$ puede que no sean estadísticamente independientes en el principio, pero observando una tercera variable $C$, puede resultar en que se vuelvan independientes. Formalmente, se define como:
$$ P(A \cap B | C)=P(A|C) · P(B|C) $$Por ejemplo, si $J$ representa la probabilidad de que se le ofrezca una oferta de trabajo en una compañía y $G$ la probabilidad de ser aceptado en un estudio de posgrado en cierta universidad, puede ser que estos dos eventos son independientes dado que existen varios factores que influyen en estos eventos (entrevistas, candidatos, etc). No obstante, ambos pueden depender en la variable $U$ representando el desempeño de la persona en sus estudios universitarios.
Por lo tanto, si se desconoce $U$ pero se sabe que la persona fue aceptada en el estudio de posgrado puede incrementar la creencia en la probabilidad de conseguir un trabajo, ya que que en cierto modo tuvo un buen desempeño en sus estudios de la universidad. Luego, los eventos $J$ y $G$ no son tan independientes del todo.
Las redes bayesianas son un tipo de grafos dirigidos acíclicos donde usualmente se les denomina a los nodos fuente y destino como nodos padres e hijos (o descendientes), respectivamente. En caso que exista un camino entre $A$ y $B$, se dice que $B$ es descendiente directo de $A$ y, dado que el grafo no tiene ciclos, la relación es mutualmente exclusiva.
Por lo tanto, las redes bayesianas tienen una propiedad donde dado los nodos padres, cada nodo en la red es condicionalmente independiente de todos los otros nodos que no sean descendientes. A lo anterior, se le denomina la propiedad de Markov local, lo cual permite factorizar la probabilidad conjunta de todas las variables aleatorias tomando en cuenta todos los nodos del grafo.
Ilustrando, para las tres variables $G, J, U$ se puede expresar:
$$ P(G,J,U)=P(G|J,U)·P(J,U)=P(G|J,U)·P(J|U)·P(U) $$Esta regla es general y se puede aplicar a más variables sin perdida de generalidad, lo que permite simplificar cálculos ya que no se considera todas las combinaciones posibles, sino unicamente las que especifica la fórmula.
El primer modelo gráfico probabilistico es el Clasificador Bayesiando Ingenuo, el cual es un modelo DAG que contiene un nodo padre y una serie de nodos hijos representando variables aleatorias que son dependientes solo del nodo padre sin depedencia entre ellas.
Usualmente el nodo padre se le conoce como el nodo causal donde, por ejemplo, el nodo "Sentimiento" influye en el nodo "triste", "divertido", etc. Por lo tanto, para realizar estimaciones en el nodo padre a partir de observaciones de los nodos hijos (es decir, los nodos hijos son las variables predictoras y el nodo padre la variable respuesta) se puede reexpresar la probabilidad conjunta como:
$$ P(C|F_{1},...,F_{n}) = \frac{P(C)·P(F_{1},...,F_{n}|C)}{P(F_{1},...,F_{n})} $$Por lo tanto,se asume independencia de la red:
$$ P(C|F_{1},...,F_{n}) = \frac{P(C)· P(F_{1}|C)·...·P(F_{n}|C)}{P(F_{1},...,F_{n})} $$Luego, para realizar un clasificador usando esta fórmula, el objetivo es escoger la clase $C_{i}$ que maximice la probabilidad posterior de una clase dadas unas características $P(C_{i}|F_{1},...,F_{n})$. Dado que el denominador no es influenciado por la clase $C_{i}$, el problema se convierte en maximizar el numerador:
$$ Clasificar \hspace{0.25cm} C_{i}: \underset{c}{\arg\max} P(C) · \prod_{i=1}^{n}P(F_{i}|C) $$A partir de los datos se puede estimar las probabilidades $ P(F_{i}|C_{j}) $ como las proporciones relativas de las observaciones de la clase $C_{j}$ que tienen diferente valor de la variable $F_{i}$. También se puede estimar $P(C_{j}$ como la proporcion relativa de las observaciones que están asiganas a la clase $C_{j}$. Estos son los estimadores de máxima verosimilitud.
El análisis de sentimientos, la tarea es analizar un determinado fragmento de texto para determinar el sentimiento que está siendo expresado por el autor, ya sea en blogs, twitters, noticias, etc. determinando si la reaccion es positiva, neutral o negativa.
Abarcar este problema se puede realizar a través de los modelos gráficos probabilisticos, donde el sentimiento (positivo o negativo) es el nodo padre y los nodos hijos son las palabras particulares que se encuentren en el texto. Un supuesto importante en Naive Bayes es que la presencia de cada palabra importante es independiente de las otras, lo cual es algo irrealista. No obstante, el modelo se desempeña formidable.
Para ello se utiliza el dataset de crítica de películas con 25.000 datos de entrenamiento y otros 25.000 de validación. Se usará la librería tm de R para operaciones de minería de texto.
In [2]:
## Instale y cargue las siguientes librerias
library(tm)
library(caret)
library("e1071")
In [5]:
## Lectura de datos
url<-"http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz" # Link al data set
download.file(url, # URL del dataset
destfile="tmp.tar.gz") # Archivo de destino
In [6]:
## Los datos descargados quedan en directorio y se descomprimen
untar("tmp.tar.gz") # Descompresión del archivo TAR
La carpeta que se descomprimió aclImdb tiene unas subcarpetas llamadas train y test cada una con los archivos .txt que contiene cada review de cada pelicula separados por negativos y positivos.
In [8]:
## Asignación de variables
path_to_neg_folder <- paste0(getwd(), # Pegar directorio local
"/aclImdb/train/neg") # Direccion a los negativos
path_to_pos_folder <- paste0(getwd(),
"/aclImdb/train/pos") # Direccion a los positivos
nb_pos <- Corpus( # Devuelve la colección de documentos
DirSource(path_to_pos_folder), # Direccion de los documentos
readerControl = list(language = "en")) # Lenguaje de los docuemtos
nb_neg <- Corpus(
DirSource(path_to_neg_folder),
readerControl = list(language = "en"))
nb_all <- c(nb_pos, nb_neg, recursive = T) # Concatenar colecciones
meta(nb_all[[1]]) # Datos del primer archivo
Observe que los archivos se encuentra de la forma _#pelicula_calificacion_ donde la calificación es una escala de 0 a 10, siendo 10 la mejor calificación. Ahora se crea un vector con los nombres de los archivos.
In [ ]:
## Crear vector de nombres
ids <- sapply( 1 : length(nb_all), # Vector de 1 hasta el numero de peliculas
function(x) meta(nb_all[[x]], "id")) # Extaer el ID
head(ids) # Primeros seis datos
Posteriormente se extrae la calificación de cada película con la función sub
In [ ]:
## Obtener las calificaciones de cada pelicula
scores <- as.numeric(sapply(ids, # Nombre de los archivos
function(x) sub("[0-9]+_([0-9]+)\\.txt", "\\1", x))) # Expresión regular para encontrar la calificación
scores <- factor(ifelse(scores >= 5, "positive", "negative")) # Forzar clase de positivo-negativo con limite de calificacion 5
summary(scores) # Resumen de las calificacion
Cuando se trabaja con minería de texto, usualemente uno asocia palabras a los sentimientos ya que si una critica presenta adjetivos como aburrido, cliché, horrible tiende asociarse con una mala crítica, mientras que palabras como Excelente, genial, divertida son tendientes a una buena crítica.
Por lo tanto, antes de empezar se realizan pasos de pre-procesamiento como convertir las palabras a minúsculas, remover puntuaciones, numeros o palabras muertas (the, of, on, over, etc.)
In [ ]:
## Pre-procesamiento de datos
nb_all <- tm_map(nb_all,
content_transformer(removeNumbers)) # Remover los números
nb_all <- tm_map(nb_all,
content_transformer(removePunctuation)) # Remover caracteres de puntuación
nb_all <- tm_map(nb_all,
content_transformer(tolower)) # Forzar a minúscula
nb_all <- tm_map(nb_all,
content_transformer(removeWords), # Remover palabras
stopwords("english")) # Palabras muertas
nb_all <- tm_map(nb_all,
content_transformer(stripWhitespace)) # Quitar espacios en blanco
Ahora se procede a estimar las características a través de una matriz de terminos documentales donde cada fila corresponde a un documento y las columnas son las palabras de dicho documento. Cada entrada es un 0 o 1 donde indica la falta o la presencia de dicha palabra en el documento, respectivamente.
In [ ]:
## Creación de matriz
nb_dtm <- DocumentTermMatrix(nb_all)
dim(nb_dtm) # Dimensiones de la matriz
nb_dtm
La matriz tiene 118.235 columnas lo que indica que esas son las palabras distintas en todos los documentos. Adicional se observa que la matriz es sparse, un tipo especial de matriz que contiene una gran cantidad de 0. En este caso existen 2.493.738 de valores distintos de cero y 2.953.381.262 de campos iguales a 0. Una forma de reducir la dimensionalidad de esta matriz es quitar las columnas que tenegan mayor número de ceros, donde se establece un porcentaje de aceptación que en este caso será del 99%.
In [ ]:
## Reducción matriz
nb_dtm <- removeSparseTerms(x = nb_dtm,
sparse = 0.99) # Porcentaje de aceptación
dim(nb_dtm)
Observe que se redujo a 1603 columnas. Luego, se fuerza la matriz a ser binaria.
In [ ]:
## Forzar a matriz de 0 y 1
nb_dtm <- weightBin(nb_dtm)
inspect(nb_dtm[10:16, 1:6])
Una vez la matriz como se necesita, se procede a realizar el modelo Naive Bayes, donde primero se crea los datos de entranmiento y validación.
In [ ]:
## Particionamos sets training y testing
set.seed(443452342) # Semilla aleatoria
nb_df <- as.data.frame(as.matrix(nb_dtm)) # Convertir a data.frame
nb_sampling_vector <- createDataPartition(scores, # Crear vector de muestreo
p = 0.80, # Porcentaje de muestreo
list = FALSE) # Devolver lista es falso
nb_df_train <- nb_df[nb_sampling_vector,] # Variables predictoras de entrenamiento
nb_df_test <- nb_df[-nb_sampling_vector,] # Variables predictoras de validación
scores_train <- scores[nb_sampling_vector] # Variable respuesta de entrenamiento
scores_test <- scores[-nb_sampling_vector] # Variable respuesta de validación
Creación del modelo
In [ ]:
## Generar el clasificador Naive Bayes
nb_model <- naiveBayes(nb_df_train, # Variables predictoras de entrenamiento
scores_train) # Variable respuesta de entrenamiento
Predicción y porcentaje de ajuste
In [ ]:
## Predicciones y ajuste
nb_train_predictions <- predict(nb_model, # Modelo de Naive Bayes
nb_df_train) # Variables predictoras de entrenamiento
mean(nb_train_predictions == scores_train) # Porcenjate de acierto
table(actual = scores_train, # Valores reales
predictions = nb_train_predictions) # Valores predecidos
Evaluación del modelo con los datos de validación
In [ ]:
## Predicciones y evaluación de precisión
nb_test_predictions <- predict(nb_model, # Modelo de Naive Bayes
nb_df_test) # Variables predictoras de validación
mean(nb_test_predictions == scores_test) # Porcentaje de acierto
table(actual = scores_test, # Valores reales
predictions = nb_test_predictions) # Valores predecidos
Ejercicio.-- Utilice la base de datos de imagenes con letras escritas proporcionada por Kaggle para predecir que tipo de letra es utilizando modelo básico de Naive Bayes.
In [ ]:
Los modelos de Markov ocultos (HMM) son redes bayesianas con una estructura repetitiva entre ciertos estados que se puede utilizar para predecir secuencias. El diagrama básico de cómo se ve un HMM es:
Al observar la secuencia avanza de izquierda a derecha donde cada nodo del camino contiene un par de nodos conectados. Los nodos $C_{i}$ son conocidos como estados latentes, escondidos o solo estados dificiles de observar, donde los nodos $O_{i}$ son los estados observados. Como las redes bayesianas, las observaciones son independientes entre ellas dado su estado correspondiente. En los nodos escondidos, se produce una observación o un símbolo que hacen parte de la sequencia.
Estos modelos son ampliamente usados en el procesamiento natural de lenguaje (NLP) en la tarea de obtener una parte del habla y sacar la sequencia de las "etiquetas" (Sustantivo, adjetivo, adverbio, etc). También se utilizan en reconocimiento de imagenes, de intrusos en una red, entre otros.
Usualmente, se tiene una coleccion de sequencias etiquetadas con su respectivo estado donde, análogamente al clasificador ingenuo Bayesiano, se usa los conteos de frecuencia relativos para estimar la probabilidad inicial del algortimo. Cuando no se tienen clasificados los datos, la tarea es más dificil ya que pueden ser varios estados y se tienen que probar las combinaciones posibles. Un posible método es através del algoritmo Baum-Welch.
Una vez se estiman los parámetros del modelo, la cuestión es cómo predecir la sequencia más probable de estados detrás de una secuencia de observaciones. A continuación, se hace una inroducción de este tipo de algoritmos.
Dentro del campo de la biología los modelos HMM son ampliamente usados para la prediccion de secuencias genéticas. El DNA se compone de cuatro moleculas fundamentales: Timinia, Citosina, Adenina y Guanina, donde el orden en que estas aparecen en la secuencia codifica la información genética que contiene el ADN.
Un problema interesante es encontrar una secuencia promotora que juegan un papel importante en regular la transcripción de genes. Para esta tarea, se utiliza el HMM que discrimine qué secuencias son promotoras y que otras no.
In [ ]:
## Descargue e instale las siguientes librerias
library("HMM")
In [ ]:
## Lectura de datos
link <- paste0("https://archive.ics.uci.edu/ml/machine-learning-databases/", # Link de los datos
"molecular-biology/promoter-gene-sequences/promoters.data")
promoters <- read.csv(link, # Datos
header = F, # Sin encabezado
dec = ",", # Indicador decimal
strip.white = TRUE, # Elimina espacios en blanco al principio
stringsAsFactors = FALSE) # Cadenas de texto no se forzan a ser factores
promoters[1,] # Primer registro de la secuencia
Note que la primera columna denota las cadenas promotoras o no (+ o -), por lo tanto se divide el conjunto de datos.
In [ ]:
## Separar cadenas promotoras
positive_observations <- subset(promoters, # Data
V1 == '+', # Cadenas promotoras (+)
3) # Seleccionamos la columna 3
negative_observations <- subset(promoters, # Data
V1 == '-', # Cadenas promotoras (+)
3) # Seleccionamos la columna 3
Para el modelo HMM, es necesario concatenar todas las cadenas de la misma clase, pero sin perder el inicio y el fin de cada uno. Para ello se coloca una S al principio de cada cadena y una X al final.
In [ ]:
## Identificar el inicio y final de cada cadena
positive_observations <- sapply(positive_observations, # Cadenas
function(x) paste("S", x, "X", sep="")) # Pegar S al principio y X al final
negative_observations <- sapply(negative_observations, # Cadenas
function(x) paste("S", x, "X", sep="")) # Pegar S al principio y X al final
positive_observations[1] # Primer dato
Ahora se divide la secuencia en cada una de sus moleculas con la función strsplit()
In [ ]:
## Separar las cadenas
positive_observations <- strsplit(positive_observations, "") # Separar la cadena en cada molecula (letra)
negative_observations <- strsplit(negative_observations, "")
head(positive_observations[[1]], n = 15) # Mostrar 15 primeros datos
Ahora que los datos están organizados, hay definir las matrices de probabilidad con los 6 estados que se presentan (4 moleculas más X y S).
In [ ]:
## Estimación de las matrices de probabilidad
states <- c("S", "X", "a", "c", "g", "t") # Estados de la posición de la cadena
symbols <- c("S", "X", "a", "c", "g", "t") # Simbolos de cada estado
startingProbabilities <- c(1,0,0,0,0,0) # Probabilidades iniciales
emissionProbabilities <- diag(6) # Matriz 6x6 con 1's en su diagonal
colnames(emissionProbabilities) <- states # Asignamos nombre a las columnas
rownames(emissionProbabilities) <- symbols # Asignamos nombre a las filas
emissionProbabilities # Mostrar la matriz
Definir la función calculateTransitionProbabilities
que calcula la probabilidad de transición de un estado a otro.
In [ ]:
## Funcion para calcular probabilidades de transición
calculateTransitionProbabilities <- function(data, states) {
# Crear matriz
transitionProbabilities <- matrix(0, # Cero en las entradas
length(states), # numero de Filas
length(states)) # Numero de columnas
# Nombre de la filas y columnas
colnames(transitionProbabilities) <- states
rownames(transitionProbabilities) <- states
for (index in 1:(length(data) - 1)) {
current_state <- data[index] # Estado actual
next_state <- data[index + 1] # Proximo estado
transitionProbabilities[current_state, next_state] <-transitionProbabilities[current_state, next_state] + 1 # Se hace el conteo de los passos de estado
}
# Extraer frencuencias relativas
transitionProbabilities <- sweep(transitionProbabilities, # Barrer por la matriz de ocurrencias
1, # Recorrer por filas
rowSums(transitionProbabilities), # Estadística de suma de las filas
FUN = "/") # Dividir entre las filas
return(transitionProbabilities) # Devolver matriz
}
Dado que hay tan pocas observaciones, es recomendable usar validación cruzada dejando uno afuera para mejorar la estimación del modelo.
In [ ]:
## Validación cruzada dejando uno afuera y matrices
negative_observation <-Reduce(function(x, y) c(x, y), # Reducir la matriz
negative_observations, # Datos de entrenamiento
c())
(transitionProbabilitiesNeg <- calculateTransitionProbabilities(negative_observation, # Valores ajustados
states)) # Valores de los estados
Inciamos el HMM con la función initHMM de la librería HMM.
In [ ]:
## Inicializar modelos HMM
negative_hmm <- initHMM(states, # Estados
symbols, # Símbolos
startProbs = startingProbabilities, # Probabilidades iniciales
transProbs = transitionProbabilitiesNeg, # Probabilidades de transición
emissionProbs = emissionProbabilities) # Probabilidades de emision
Evaluación de las predicciones correctas.
In [ ]:
## Validación del ajuste
incorrect <- 0 # Inicializar vector incorrect
# Hacer un loop para contar los incorrectos
for (obs in 1 : length(positive_observations)) {
positive_observation <- Reduce(function(x, y) c(x, y), positive_observations[-obs], c()) # Quitar una observación
transitionProbabilitiesPos <- calculateTransitionProbabilities(positive_observation, states) # Calcular las matrices de transición
positive_hmm <- initHMM(states, symbols,startProbs = startingProbabilities, # Iniciar el modelo HMM
transProbs = transitionProbabilitiesPos,emissionProbs = emissionProbabilities)
test_observation <- positive_observations[[obs]] # Observaciones de test
final_index <- length(test_observation) # Longitud de cuántas observaciones
pos_probs <- exp(forward(positive_hmm, test_observation)) # Matriz con el logaritmo de la probabilidad.
neg_probs <- exp(forward(negative_hmm, test_observation)) # en cada paso
pos_seq_prob <- sum(pos_probs[, final_index]) # Sumar las cadenas positivas y negativas
neg_seq_prob <- sum(neg_probs[, final_index])
if (pos_seq_prob < neg_seq_prob) {incorrect <- incorrect + 1} # Contar el incorrecto
}
incorrect # Mostrar el número de incorrectos
In [ ]:
## Iniciar el modelo HMM para promotores negativos
positive_observation <- Reduce(function(x, y) c(x, y), positive_observations, c())
transitionProbabilitiesPos <- calculateTransitionProbabilities(positive_observation, states)
positive_hmm <- initHMM(states,
symbols,
startProbs = startingProbabilities,
transProbs = transitionProbabilitiesPos,
emissionProbs = emissionProbabilities)
In [ ]:
for (obs in 1:length(negative_observations)) {
negative_observation<-Reduce(function(x, y) c(x, y), negative_observations[-obs], c())
transitionProbabilitiesNeg <-calculateTransitionProbabilities(negative_observation, states)
negative_hmm <- initHMM(states,
symbols,
startProbs = startingProbabilities,
transProbs = transitionProbabilitiesNeg,
emissionProbs = emissionProbabilities)
test_observation <- negative_observations[[obs]]
final_index <- length(test_observation)
pos_probs <- exp(forward(positive_hmm,test_observation))
neg_probs <- exp(forward(negative_hmm,test_observation))
pos_seq_prob <- sum(pos_probs[, final_index])
neg_seq_prob <- sum(neg_probs[, final_index])
if (pos_seq_prob > neg_seq_prob) incorrect <- incorrect+1
}
incorrect
(cross_validation_accuracy <- 1 - (incorrect/nrow(promoters)))
Ejercicio.-- Una firma inversora en bolsa necesita saber para un grupo de acciones en las cuales tiene invertida una gran cantidad de capital cuales son los momentos al alza (bull) o a la baja (bear) con el fin de planear sus estrategías de compra-venta así como identificar oportunidades de invertir.
Se debe realizar un modelo donde a partir de la entrada de una serie de tiempo financiera prediga si la acción va a subir o bajar en una determinada ventana de tiempo. Luego de un análisis de la literatura, encuentra que los modelos de HMM pueden predecir si una serie de tiempo subirá o caerá en un régimen de tiempo.
Para descargar las series de tiempo, utilice la librería Quandl. Adicionalmente, realice todos los supuestos que requiera, así como ventana de tiempo de la inversión o la acción con la cual va a trabajar.
In [ ]: