1 Introducción


1.1 Descripción de la PEC a realizar

La prueba está estructurada en 7 ejercicios teórico-prácticos que piden que se desarrolle la fase de preparación y estimación de un modelo utilizando un juego de datos.

Deben responderse al menos 6 de los 7 ejercicios para poder superar la PEC. Para optar a la máxima nota tienen que responderse los 7 ejercicios.

1.2 Criterios de evaluación

Ejercicios teóricos
Todos los ejercicios deben ser presentados de forma razonada y clara. No se aceptará ninguna respuesta que no esté claramente justificada.

Ejercicios prácticos
Para todas las PEC es necesario documentar en cada ejercicio práctico qué se ha hecho y cómo se ha hecho.

Pregunta Criterio de valoración Peso
1 Respuesta a la pregunta de forma correcta 10%
2 Primera visualización 5%
2 Segunda visualización 5%
3 Se realiza el gráfico solicitado 5%
3 Se contestan las cuestiones y se justifican 10%
4 Se describen los valores que se solicitan 10%
4 Se evalua la capacidad predictiva que se pide 5%
4 Se interpretan los resultados 5%
5 Se entrenan los modelos solicitados 10%
5 Se valoran los resultados obtenidos 10%
6 Se entrena el modelo solicitado 15%
6 Se contesta a la cuestión planteada 10%

1.3 Formato y fecha de entega

El formato de entrega es: studentname-PECn.html
Fecha de Entrega: 22/11/2020
Se debe entregar la PEC en el buzón de entregas del aula


2 Base teórica


Esta práctica se basa en una de las aplicaciones de la Minería de Textos, que consiste en clasificar documentos en función de su temática. Esto es lo que se conoce como Topic Model. Para realizar la clasificación utilizaremos el algoritmo de aprendizaje automático K-Nearest Neighbors (K-NN).

Por Topic Model entendemos procesos de aprendizaje automático que tienen por objetivo descubrir el tema subyacente en una colección de documentos. Generalizando un poco más, Topic Model busca patrones en el contenido de los documentos y lo hace en base a la frecuencia de aparición de palabras.

El análisis que realizamos se basa en el hecho de que en documentos pertenecientes a un mismo tema aparecerán palabras que se repetirán con mayor frecuencia. Por lo tanto, el análisis plantea la clasificación de documentos utilizando como criterio las palabras que son más frecuentes en cada temática. Estas frecuencias se almacenarán en una matriz de datos, donde las variables serán las palabras y los registros los documentos, que será la base para que puedan trabajar los algoritmos de aprendizaje automático, que en esta práctica se centran en el K-NN.

En este ámbito de conocimiento se basan los sistemas de clasificación documental, búsqueda de contenidos y sistemas de recomendación entre otros.

2.1 Competencias

Las competencias que se trabajan en esta práctica son:

  • Capacidad de analizar datos textuales en R.
  • Capacidad de implementar el algoritmo K-NN para la clasificación de textos según temática.

2.2 Objetivos

  • Asimilar correctamente los apartados 1.2.1, 1.2.2, 2.1, 3.2.1 y 3.2.2.

2.3 Recursos

Para realizar esta práctica recomendamos la lectura de lo siguiente:

2.4 Nota: Propiedad intelectual

A menudo es inevitable, al producir una obra multimedia, hacer uso de recursos creados por terceras personas. Es por lo tanto comprensible hacerlo en el marco de una práctica de los estudios de Informática, Multimedia y Telecomunicación de la UOC, siempre y cuando esto se documente claramente y no suponga plagio en la práctica.

Por lo tanto, al presentar una práctica que haga uso de recursos ajenos, se debe presentar junto con ella un documento en el que se detallan todos ellos, especificando el nombre de cada recurso, su autor, el lugar dónde se obtuvo y su estatus legal: si la obra está protegida por el copyright o se acoge a alguna otra licencia de uso (Creative Commons, licencia GNU, GPL …). El estudiante deberá asegurarse de que la licencia no impide específicamente su uso en el marco de la práctica. En caso de no encontrar la información correspondiente tendrá que asumir que la obra está protegida por copyright.

Deberéis, además, adjuntar los ficheros originales cuando las obras utilizadas sean digitales, y su código fuente si corresponde.


3 Enunciado


El objetivo es clasificar un conjunto de artículos de Reuters correspondientes a distintas temáticas: acquire, crude, earn, grain, interest, money-fx, ship y trade. Se trata de temáticas relacionadas con inversiones financieras y fondos de inversión.

Se utiliza un sistema de clasificación de documentos que se basa en el algoritmo de aprendizaje automático K-NN (K-Nearest Neighbors o K vecinos más próximos).

Los datos están en el fichero data_reuter.txt. Este fichero contiene dos campos, el primero se corresponde con el tipo de temática (en total hay 8) y el segundo campo contiene el artículo relacionado. Entre las 8 temáticas se seleccionan 2 para realizar el análisis.

Para mostrar el funcionamiento del algoritmo de clasificación se utiliza un 70% de los artículos para entrenar el modelo de aprendizaje. Dicho algoritmo se aplica sobre el 30% de artículos restantes con el objetivo de predecir su temática.


4 Apartados de la práctica


El código R que utilizaremos en la práctica se divide en apartados según las tareas que iremos realizando:


5 Inicialización de variables


Instalamos los packages de R que necesitaremos para realizar la práctica:

install.packages(“tm”) install.packages(“plyr”) install.packages(“class”) install.packages(“ggplot2”) install.packages(“SnowballC”) install.packages(“wordcloud”)

Definimos el directorio de trabajo donde tendremos guardado el fichero de datos.

setwd(“D:\uoc\Data Analytics Specialization\Fundamentos del data Science\Modulo1\PEC1”)

Para instalar los paquetes y definir el directorio de trabajo podéis eliminar los asteriscos delante de los install.packages() y setwd() seleccionarlos y ejecutarlos como comandos de R (Control+Intro).

## Cargamos los paquetes necesarios para ejecutar las funciones que se describen a continuación:
# Para la función Corpus()
library(tm)
# Para la función rbind.fill
library(plyr)
# Para la función knn()
library(class)

# En R una variable tipo factor es una variable categórica que puede contener tanto números como carácteres. Se trata de un tipo de variable muy útil para realizar tareas de modelización estadística.

# En R, por defecto, las columnas con carácteres no numéricos son tratadas como factores. Para evitarlo y garantizar que estas columnas sigan siendo consideradas carácteres, fijaremos el siguiente parámetro
options(stringsAsFactors = FALSE)

# Leemos los datos
data <- read.table('data_reuter.txt', header=FALSE, sep='\t')
# Describimos los datos
## Cuantos hay en total
nrow(data)
## [1] 5485
# Cuantos hay para cada tipo de temática
table(data$V1)
## 
##      acq    crude     earn    grain interest money-fx     ship    trade 
##     1596      253     2840       41      190      206      108      251
library(ggplot2)
qplot(data$V1,xlab="Tematica", main = "Frecuencias")+ coord_flip()

# Finalmente seleccionamos dos temáticas: acq y earn
data2<-data[which(data$V1 %in% c("acq","earn")),]
## Cuantos hay en total
nrow(data2)
## [1] 4436

6 Creación del corpus, limpieza y acondicionado del texto.


A continuación creamos un corpus para cada temática sobre los que se realizarán las siguietes tareas de acondicionado de texto:

  1. Eliminar signos de puntuación.
  2. Eliminar espacios en blanco innecesarios.
  3. Convertir todo el texto a minúsculas.
  4. Eliminar palabras sin significado propio.
  5. Eliminar números.
  6. Substituir las palabras derivadas por su palabra raíz.
# Creación del corpus de la temática acq
## Seleccionamos la temática
data_acq<-data2[(data2$V1=="acq"),]
## Construimos el corpus
source <- VectorSource(data_acq$V2)
corpus1 <- Corpus(source)
## Acondicionamos el corpus
### Convertir todo el texto a minúsculas
corpus1 <- tm_map(corpus1, content_transformer(tolower))
### Elimina números
corpus1 <- tm_map(corpus1, removeNumbers)
### Eliminar signos de puntuación
corpus1 <- tm_map(corpus1, removePunctuation)
###Eliminar espacios en blanco innecesarios
corpus1 <- tm_map(corpus1, stripWhitespace)
### Eliminar palabras sin significado propio
v_stopwords <- c(stopwords("english"),c("dont","didnt","arent","cant","one","also","said"))
corpus1 <- tm_map(corpus1, removeWords, v_stopwords)
### Eliminar signos de puntuación
corpus1 <- tm_map(corpus1, removePunctuation)
### Substituir las palabras derivadas por su palabra raíz
corpus1 <- tm_map(corpus1, stemDocument, language="english")

# Creación del corpus de la temática earn
## Seleccionamos la temática
data_earn<-data2[(data2$V1=="earn"),]
## Construimos el corpus
source <- VectorSource(data_earn$V2)
corpus2 <- Corpus(source)
## Acondicionamos el corpus
corpus2 <- tm_map(corpus2, content_transformer(tolower))
corpus2 <- tm_map(corpus2, removeNumbers)
corpus2 <- tm_map(corpus2, removePunctuation)
corpus2 <- tm_map(corpus2, stripWhitespace)
v_stopwords <- c(stopwords("english"),c("dont","didnt","arent","cant","one","also","said"))
corpus2 <- tm_map(corpus2, removeWords, v_stopwords)
corpus2 <- tm_map(corpus2, removePunctuation)
corpus2 <- tm_map(corpus2, stemDocument, language="english")

7 Generación de la Matriz de Términos (TDM-Terms Data Matrix)


A continuación construimos una matriz de términos para cada temática para posteriormete unirlas en una misma lista.

# Construimos la matrix de documentos de la temática acq
mat_acq <- TermDocumentMatrix(corpus1)
## Controlamos la dispersión (Sparsity): Número de celdas igual a cero respecto al total.
mat_acq<- removeSparseTerms(mat_acq,  0.85)
inspect(mat_acq)
## <<TermDocumentMatrix (terms: 42, documents: 1596)>>
## Non-/sparse entries: 17687/49345
## Sparsity           : 74%
## Maximal term length: 10
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     1060 1347 181 28 296 49 557 68 77 797
##   compani    7    9   1  7   5  6   5  7  5  12
##   corp       1    6   3  1   2  0   3  1  1   6
##   dlrs       9   10   4 11   7 17  19 15  4   4
##   inc        3    2   3  3   2  5   1  4  3   2
##   mln        4    6   1  5   7  7  19  4  0   5
##   offer      8    7  16  5   0 11   1  7 11   0
##   pct        2    1   5  2   2  2   2  6  3   3
##   reuter     1    1   1  1   1  1   2  1  2   2
##   share     14   12   6  6   7  7   5 11  4   1
##   will       1    4   1  9   1  0   2  0  2   3
mat_acq<-list(name="acq",mat=mat_acq)
mat_acq
## $name
## [1] "acq"
## 
## $mat
## <<TermDocumentMatrix (terms: 42, documents: 1596)>>
## Non-/sparse entries: 17687/49345
## Sparsity           : 74%
## Maximal term length: 10
## Weighting          : term frequency (tf)
str(mat_acq)
## List of 2
##  $ name: chr "acq"
##  $ mat :List of 6
##   ..$ i       : int [1:17687] 1 2 3 4 5 6 7 8 9 10 ...
##   ..$ j       : int [1:17687] 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ v       : num [1:17687] 1 1 3 4 2 4 1 2 1 2 ...
##   ..$ nrow    : int 42
##   ..$ ncol    : int 1596
##   ..$ dimnames:List of 2
##   .. ..$ Terms: chr [1:42] "acquir" "buy" "common" "compani" ...
##   .. ..$ Docs : chr [1:1596] "1" "2" "3" "4" ...
##   ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"
# Construimos la matrix de documentos de la temática earn
mat_earn <- TermDocumentMatrix(corpus2)
mat_earn<- removeSparseTerms(mat_earn,  0.85)
inspect(mat_earn)
## <<TermDocumentMatrix (terms: 29, documents: 2840)>>
## Non-/sparse entries: 27960/54400
## Sparsity           : 66%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##         Docs
## Terms    1076 1537 176 1987 209 316 459 465 523 703
##   cts       4    5   0    4  11   3   5  14   0  12
##   dlrs     17   19  11   13  12  19  17  32  47  12
##   loss      6    6   4    8   8   2   7   5   8   8
##   mln       9   20  24   16  10  18  13  11  45   4
##   net       9    3   7    6   5   2   5   9   2   3
##   profit    8    6   1    5   5   4   1   0   6   4
##   reuter    1    1   1    1   1   1   1   1   1   1
##   share     1    6   3    7   9   2   1   7   2  10
##   shr       2    2   0    2   2   0   0   3   0   2
##   year      2    6   7    6   3   4  10  10  13   4
mat_earn<-list(name="earn",mat=mat_earn)
mat_earn
## $name
## [1] "earn"
## 
## $mat
## <<TermDocumentMatrix (terms: 29, documents: 2840)>>
## Non-/sparse entries: 27960/54400
## Sparsity           : 66%
## Maximal term length: 8
## Weighting          : term frequency (tf)
str(mat_earn)
## List of 2
##  $ name: chr "earn"
##  $ mat :List of 6
##   ..$ i       : int [1:27960] 1 2 3 4 5 6 7 8 9 10 ...
##   ..$ j       : int [1:27960] 1 1 1 1 1 1 1 1 2 2 ...
##   ..$ v       : num [1:27960] 2 1 1 2 1 1 2 1 2 2 ...
##   ..$ nrow    : int 29
##   ..$ ncol    : int 2840
##   ..$ dimnames:List of 2
##   .. ..$ Terms: chr [1:29] "april" "compani" "inc" "mln" ...
##   .. ..$ Docs : chr [1:2840] "1" "2" "3" "4" ...
##   ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"
# Juntamos ambas matrices de términos en una misma lista
mat<-list(mat_acq, mat_earn)
str(mat)
## List of 2
##  $ :List of 2
##   ..$ name: chr "acq"
##   ..$ mat :List of 6
##   .. ..$ i       : int [1:17687] 1 2 3 4 5 6 7 8 9 10 ...
##   .. ..$ j       : int [1:17687] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ v       : num [1:17687] 1 1 3 4 2 4 1 2 1 2 ...
##   .. ..$ nrow    : int 42
##   .. ..$ ncol    : int 1596
##   .. ..$ dimnames:List of 2
##   .. .. ..$ Terms: chr [1:42] "acquir" "buy" "common" "compani" ...
##   .. .. ..$ Docs : chr [1:1596] "1" "2" "3" "4" ...
##   .. ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   .. ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"
##  $ :List of 2
##   ..$ name: chr "earn"
##   ..$ mat :List of 6
##   .. ..$ i       : int [1:27960] 1 2 3 4 5 6 7 8 9 10 ...
##   .. ..$ j       : int [1:27960] 1 1 1 1 1 1 1 1 2 2 ...
##   .. ..$ v       : num [1:27960] 2 1 1 2 1 1 2 1 2 2 ...
##   .. ..$ nrow    : int 29
##   .. ..$ ncol    : int 2840
##   .. ..$ dimnames:List of 2
##   .. .. ..$ Terms: chr [1:29] "april" "compani" "inc" "mln" ...
##   .. .. ..$ Docs : chr [1:2840] "1" "2" "3" "4" ...
##   .. ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   .. ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"

7.1 Visualizaciones sobre la matriz de palabras TDM


Con las dos matrices de frecuencias mat[[1]]$mat para acq y mat[[2]]$mat para earn, podemos realizar algunas visualizaciones básicas.

# Frecuencia de los 25 primeros términos en los 10 primeros documentos para ambos temas
inspect(mat[[1]]$mat[1:25,1:10])
## <<TermDocumentMatrix (terms: 25, documents: 10)>>
## Non-/sparse entries: 103/147
## Sparsity           : 59%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     1 10 2 3 4 5 6 7 8 9
##   common  3  0 0 0 2 0 2 0 0 1
##   compani 4  1 9 1 0 5 1 0 1 0
##   corp    0  0 1 0 2 0 1 2 0 2
##   dlrs    4  1 4 0 1 2 1 0 1 1
##   inc     2  2 3 3 0 1 0 0 1 0
##   mln     1  1 3 0 1 3 1 0 1 0
##   pct     2  1 0 0 2 2 3 0 0 2
##   reuter  1  1 1 1 1 1 1 1 1 1
##   share   5  1 6 0 4 0 3 2 0 3
##   stock   3  1 1 0 1 8 2 1 0 0
inspect(mat[[2]]$mat[1:25,1:10])
## <<TermDocumentMatrix (terms: 25, documents: 10)>>
## Non-/sparse entries: 120/130
## Sparsity           : 52%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##         Docs
## Terms    1 10 2 3 4 5 6 7 8 9
##   cts    0  6 2 7 1 4 3 6 3 2
##   dlrs   0  0 2 0 2 3 6 0 3 0
##   mln    2  4 6 8 7 0 4 1 4 0
##   net    0  2 2 1 3 0 0 2 3 0
##   profit 0  4 0 7 0 0 2 6 0 0
##   reuter 1  1 1 1 1 1 1 1 1 1
##   rev    0  2 0 2 2 0 0 2 2 0
##   share  2  0 0 0 0 4 6 0 0 0
##   shr    0  2 2 4 2 0 0 2 3 0
##   year   0  1 2 0 0 6 1 0 2 0
# Frecuencia de los 30 primeros términos en todos los documentos del tema acq
inspect(mat[[1]]$mat[1:30,])
## <<TermDocumentMatrix (terms: 30, documents: 1596)>>
## Non-/sparse entries: 14082/33798
## Sparsity           : 71%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     1060 1347 1477 181 28 296 49 557 68 77
##   compani    7    9    3   1  7   5  6   5  7  5
##   corp       1    6    2   3  1   2  0   3  1  1
##   dlrs       9   10    0   4 11   7 17  19 15  4
##   inc        3    2    0   3  3   2  5   1  4  3
##   mln        4    6   15   1  5   7  7  19  4  0
##   offer      8    7    2  16  5   0 11   1  7 11
##   pct        2    1    1   5  2   2  2   2  6  3
##   reuter     1    1    2   1  1   1  1   2  1  2
##   share     14   12   18   6  6   7  7   5 11  4
##   will       1    4    0   1  9   1  0   2  0  2
# Frecuencia de los términos en los documentos del tema earn
inspect(mat[[2]]$mat)
## <<TermDocumentMatrix (terms: 29, documents: 2840)>>
## Non-/sparse entries: 27960/54400
## Sparsity           : 66%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##         Docs
## Terms    1076 1537 176 1987 209 316 459 465 523 703
##   cts       4    5   0    4  11   3   5  14   0  12
##   dlrs     17   19  11   13  12  19  17  32  47  12
##   loss      6    6   4    8   8   2   7   5   8   8
##   mln       9   20  24   16  10  18  13  11  45   4
##   net       9    3   7    6   5   2   5   9   2   3
##   profit    8    6   1    5   5   4   1   0   6   4
##   reuter    1    1   1    1   1   1   1   1   1   1
##   share     1    6   3    7   9   2   1   7   2  10
##   shr       2    2   0    2   2   0   0   3   0   2
##   year      2    6   7    6   3   4  10  10  13   4
# Inventario de los primeros términos del del tema earn
head(mat[[2]]$mat$dimnames$Terms)
## [1] "april"   "compani" "inc"     "mln"     "record"  "reuter"
# Número de documentos del tema acq
nDocs(mat[[1]]$mat)
## [1] 1596
# Número de términos del tema acq
nTerms(mat[[1]]$mat)
## [1] 42
# Visualizamos los términos con más de 100 apariciones en documentos de temática acq
findFreqTerms(mat[[1]]$mat, lowfreq=100)
##  [1] "acquir"     "buy"        "common"     "compani"    "complet"   
##  [6] "dlrs"       "hold"       "inc"        "mln"        "pct"       
## [11] "plan"       "price"      "purchas"    "reuter"     "sale"      
## [16] "share"      "stock"      "year"       "board"      "cash"      
## [21] "corp"       "offer"      "will"       "group"      "industri"  
## [26] "exchang"    "invest"     "new"        "secur"      "stake"     
## [31] "acquisit"   "sell"       "term"       "ltd"        "own"       
## [36] "approv"     "merger"     "sharehold"  "subsidiari" "unit"      
## [41] "agreement"  "agre"

8 Descripción de la TDM.



8.1 Representación gráfica de las frecuencias


# Para acq
mmat_acq <- as.matrix(mat[[1]]$mat)
# Agregamos las frecuencias por términos y las ordenamos de mayor a menor  
v_acq <- sort(rowSums(mmat_acq), decreasing=TRUE)
# Creamos un data.frame con términos y frecuencias
d_acq <- data.frame(word=names(v_acq), freq=v_acq)
d_acq[,3]<-"acq"
# Hacemos lo mismo para earn
mmat_earn <- as.matrix(mat[[2]]$mat)
# Agregamos las frecuencias por términos y las ordenamos de mayor a menor  
v_earn <- sort(rowSums(mmat_earn), decreasing=TRUE)
# Creamos un data.frame con términos y frecuencias
d_earn <- data.frame(word=names(v_earn), freq=v_earn)
d_earn[,3]<-"earn"

# Concatenamos las dos matrices
fdata<-rbind(d_acq,d_earn)
colnames(fdata)
## [1] "word" "freq" "V3"
colnames(fdata)<-c("Palabra", "Frecuencia", "Tematica")

# Gráfico de barras con las palabras más frecuentes
library(ggplot2)

ggplot(subset(fdata, Frecuencia>500),aes(Palabra,Frecuencia,fill=Tematica))+geom_bar(stat="identity",position=position_dodge())+theme(axis.text.x=element_text(angle=45, hjust=1))


8.2 Construcción de una nube de palabras


Podemos construir una nube de palabras para la matriz de términos con ambas temáticas.

# Cargamos la librería wordcloud
require(wordcloud)
# Construimos la nube de palabras o términos, para ello primero seleccionamos los que tienen una frecuencia superior a 500
sfdata<-subset(fdata, Frecuencia>500)
wordcloud(sfdata$Palabra, fdata$Frecuencia,min.freq=500,random.color=FALSE, colors=rainbow(3))


9 Creación de un data.frame apto para K-NN


A continuación se construirá un data.frame en el que las columnas representan Términos, las filas Documentos y las celdas Frecuencias del término o palabra en cada documento.

# Creación de un data.frame apto para K-NN
# Para acq
s.mat_acq <- t(data.matrix(mat[[1]]$mat))
# La convertimos en data.frame que vendría a ser como un formato excel (filas, columnas y celdas con valores)  
# En este data.frame, tenemos que cada fila es un documento, cada columna una palabra y las celdas contienen la frecuencia en que cada palabra aparece en cada documento.
s.df_acq <- as.data.frame(s.mat_acq, stringsAsFactors = FALSE)
nrow(s.df_acq)
## [1] 1596
# En la última columna colocaremos el Tema de cada documento tdm[["name"]. Para ello usaremos dos funciones cbind() y rep()  

# Recordemos que en la lista TDM habíamos almacenado el tema en el valor "name"
# Mediante la función rep() repetiremos el tema del documento tantas veces como filas hay en el data.frame 
Tema <- rep(mat[[1]]$name, nrow(s.df_acq))
s.df_acq<-cbind(s.df_acq,Tema)

# Para earn
s.mat_earn <- t(data.matrix(mat[[2]]$mat))
# La convertimos en data.frame que vendría a ser como un formato excel (filas, columnas y celdas con valores)  
# En este data.frame , tenemos que cada fila es un documento, cada columna una palabra y las celdas contienen la frecuencia en que cada palabra aparece en cada documento.
s.df_earn <- as.data.frame(s.mat_earn, stringsAsFactors = FALSE)
# En la última columna colocaremos el Tema de cada documento tdm[["name"]. Para ello usaremos dos funciones cbind() y rep()  

# Recordemos que en la lista TDM habíamos almacenado el tema en el valor "name"
# Mediante la función rep() repetiremos el tema del documento tantas veces como filas hay en el data.frame 
Tema <- rep(mat[[2]]$name, nrow(s.df_earn))
s.df_earn<-cbind(s.df_earn,Tema)

# Utilizamos la función rbind.fill() para concatenar las filas de dos data frame con distinta dimensión y pone NA en las casillas donde no hay información.
pila <-rbind.fill(s.df_acq, s.df_earn)
pila[is.na(pila)] <- 0

# Cada fila representa un documento, cada columna una palabra y las celdas son la frecuencia de aparición de esa palabra en ese documento.
## Tenemos 4436 documentos 
nrow(pila)
## [1] 4436
## Tenemos 48 palabras
ncol(pila)
## [1] 63

9.1 Construcción del Modelo de clasificación


Construimos un juego de datos de entrenamiento con el 70% de los documentos, es decir, 3106 documentos.
Así mismo construiremos un juego de datos de pruebas con el 30% de documentos restante, es decir 1330 documentos.

# Fijamos una semilla para poder repetir la práctica obteniendo los mismos resultados. 
set.seed(111)

# 70% de los documentos para entrenamiento
entrena.idx <- sample(nrow(pila), ceiling(nrow(pila) * 0.7))
# El resto de documentos para pruebas
test.idx <- (1:nrow(pila))[-entrena.idx]

Para poder aplicar el algoritmo de aprendizaje por vecindad K-NN necesitamos realizar unas pequeñas adaptaciones.
Éstas consisten en separar por un lado los temas y por otro la matriz de frecuencias.

# guardamos por un lado los temas
tema <- pila[, "Tema"]
# y por otro lado el resto de palabras
pila.nl <- pila[, !colnames(pila) %in% "Tema"]

Aplicamos el modelo K-NN, pasándole como parámetros la matriz de frecuencias de los documentos de entrenamiento, la matriz de frecuencias de los documentos de pruebas y los temas de los documentos de entrenamiento.

Los temas de los documentos de prueba no se los pasamos, porque precisamente es lo que el algoritmo debe predecir.

Recordamos que el objetivo del modelo será el de predecir el tema de los documentos de pruebas.

# Modelo KNN
knn.pred <- knn(pila.nl[entrena.idx, ], pila.nl[test.idx, ], tema[entrena.idx])

10 Validación del Modelo de clasificación


Una vez aplicado el modelo K-NN sobre el juego de documentos de prueba, podemos utilizar una matriz de confusión para valorar el nivel de acierto del modelo.

# Modelo KNN
knn.pred <- knn(pila.nl[entrena.idx, ], pila.nl[test.idx, ], tema[entrena.idx])
# Matriz de confusión
# Las filas son predicciones y las columnas son observaciones reales
conf.mat <- table("Predicción" = knn.pred,"Real" = tema[test.idx])
conf.mat
##           Real
## Predicción acq earn
##       acq  460   10
##       earn  30  830

Observamos como K-NN, de los 1330 documentos, ha clasificado correctamente 1292:

y ha fallado en 40 documentos, puesto que los ha clasificado 10 como acq cuando en realidad eran earn y 30 como earn que en reladad eran acq.

Para evaluar la capacidad predictiva del algoritmo utilizamos dos medidas, que hemos denominado ratio1 y rati2.

ratio1 <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[1,2]))*100
ratio1
## [1] 97.87234
ratio2 <- (conf.mat[2,2]/(conf.mat[1,2]+conf.mat[2,2]))*100
ratio2
## [1] 98.80952

11 Ejercicios


11.1 Ejercicio 1:

En el apartado “Generación de la Matriz de Términos”, un valor a controlar es la “Sparsity” que se fija en 0.85. ¿Qué sucedería si se disminuye el valor de la “Sparsity”? y ¿si se incrementa dicho valor?.

11.2 Respuesta 1:

Si disminuimos el valor de sparsity estaremos siendo más restrictivos en nuestro análisis ya que aumentaremos la exigencia de aparición de los términos en los documentos, arriesgando a descartar información valiosa dentro de la matriz. Por otra parte, si lo aumentamos, aumentamos la dispersión, usando la práctica totalidad de la matriz de términos y sus apariciones en los documentos contenidos, también al aumentarlo aumentaremos el número de términos que no aparecen en documentos. Entiendo que la lógica aquí sería, dependiendo del tipo de análisis a realizar encontrar el equilibrio deseado.

11.3 Ejercicio 2:

En el apartado “Visualizaciones sobre la matriz de palabras TDM” se muestron algunos ejemplos de visualización de distintas secciones de la matriz de términos. Visualizad los 10 primeros términos y los 5 primeros documentos en la temática “earn”. Posteriormente visualizar aquellas palabras relacionadas con esta misma temática y con frecuencia menor a 2000 y mayor a 20.

11.4 Respuesta 2:

#Visualizad los 10 primeros términos y los 5 primeros documentos en la temática "earn"
inspect(mat[[2]]$mat[1:10,1:5])
## <<TermDocumentMatrix (terms: 10, documents: 5)>>
## Non-/sparse entries: 29/21
## Sparsity           : 42%
## Maximal term length: 7
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     1 2 3 4 5
##   april   2 0 0 0 0
##   compani 1 0 0 0 3
##   cts     0 2 7 1 4
##   dlrs    0 2 0 2 3
##   inc     1 1 1 1 1
##   mln     2 6 8 7 0
##   record  1 0 0 0 0
##   reuter  1 1 1 1 1
##   share   2 0 0 0 4
##   two     1 0 1 0 0
#Posteriormente visualizar aquellas palabras relacionadas con esta misma temática y con frecuencia menor a 2000 y mayor a 20
findFreqTerms(mat[[2]]$mat,lowfreq=20,highfreq=2000)
##  [1] "april"    "compani"  "inc"      "record"   "share"    "two"     
##  [7] "includ"   "note"     "qtr"      "dividend" "oper"     "prior"   
## [13] "rev"      "corp"     "end"      "quarter"  "sale"     "march"   
## [19] "div"      "pay"

11.5 Ejercicio 3:

En el apartado “Descripción de la TDM”" se construye un gráficos de barras con las palabras con una frecuencia mayor que 500 en ambas temáticas. Construya un gráfico de barras similar pero con las barras apiladas y en posición horizontal. ¿Cuantas barras salen bicolor?. ¿Qué implica la existencias de estas barras bicolor?.

11.6 Respuesta 3:

#Codigo usado para generar el nuevo gráfico de barras apiladas. Se modifica el output de la función geom_bar para mostrar los datos apilados y se añade coord_flip para mostrarlo de manera horizontal.
ggplot(subset(fdata, Frecuencia>500),aes(Palabra,Frecuencia,fill=Tematica))+geom_bar(stat="identity")+theme(axis.text.x=element_text(angle=45, hjust=1))+coord_flip()

# ¿Cuantas barras salen bicolor? Respuesta: 7
# ¿Qué implica la existencias de estas barras bicolor? Respuesta: Indica que el termino aparece en las dos temáticas analizadas, en este caso acq y earn.

11.7 Ejercicio 4:

En el apartado “Validación del Modelo de clasificación” se presenta la matriz de confusión del modelo generado. A partir de esta matriz se calculan dos ratios. Se supone que la categoría de referencia o “verdadera” es acq. Determinad que ratios (ratio1 y ratio2) hemos calculado y obtened el ratio de precisión. Interpretad los resultados.

11.8 Respuesta 4:

El ratio1 mide la sensibilidad del modelo calculando la tasa de verdaderos positivos (True Postitiva Rate), para ello se usa el valor de Verdaderos Positivos y se divide por la suma de los Verdaderos Positivos y los Falsos Negativos, dando como resultado un 97.87234% de Sensibilidad

ratio1 <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[1,2]))*100
ratio1
## [1] 97.87234

El ratio2 mide la Especifidad (Especificity, true negative Rate) del modelo para obtener el ratio de casos negativos que el algoritmo a clasificado correctamente, para ello se usa el valor de el total de Verdaderos Negativos y se divide por la suma de Verdaderos negativos y falsos positivos. Da como resultado un 98.80952%

ratio2 <- (conf.mat[2,2]/(conf.mat[1,2]+conf.mat[2,2]))*100
ratio2
## [1] 98.80952

para calcular el ratio de precisión tomamos el total de Valores Positivos y lo dividimos por la suma de Valores Positivos y Falsos Negativos. Da como resultado : 93.87755% la fórmula la podemos ver a continuación:

precision <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[2,1]))*100
precision
## [1] 93.87755

11.9 Ejercicio 5:

En el apartado “Validación del Modelo de clasificación” se utiliza la función “knn” para clasificar los documentos según temática. Esta función por defecto supone que el número de vecinos a evaluar es igual a 1. Valorad los resultados del algoritmo K-NN utilizando distinto número de vecinos, por ejemplo, 2, 3 y 5. Qué dificultad añadida podría tener seleccionar K=2.

11.10 Respuesta 5:

En primer lugar he modificado el modelo usando el valor K del enunciado, aplicado la matriz de confusión y para cada uno de ellos aplicando los ratios de sensibilidad, especificidad y precisión para cada uno de los valores.

#usando k=2
knn.pred <- knn(pila.nl[entrena.idx, ], pila.nl[test.idx, ], tema[entrena.idx],k=2)
conf.mat <- table("Predicción" = knn.pred,"Real" = tema[test.idx])
conf.mat
##           Real
## Predicción acq earn
##       acq  459   11
##       earn  31  829
Sensibilidad <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[1,2]))*100
Sensibilidad
## [1] 97.65957
Especificidad <- (conf.mat[2,2]/(conf.mat[1,2]+conf.mat[2,2]))*100
Especificidad
## [1] 98.69048
precision <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[2,1]))*100
precision
## [1] 93.67347
#usando k=3
knn.pred <- knn(pila.nl[entrena.idx, ], pila.nl[test.idx, ], tema[entrena.idx],k=3)
conf.mat <- table("Predicción" = knn.pred,"Real" = tema[test.idx])
conf.mat
##           Real
## Predicción acq earn
##       acq  463   13
##       earn  27  827
Sensibilidad <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[1,2]))*100
Sensibilidad
## [1] 97.26891
Especificidad <- (conf.mat[2,2]/(conf.mat[1,2]+conf.mat[2,2]))*100
Especificidad
## [1] 98.45238
precision <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[2,1]))*100
precision
## [1] 94.4898
#usando k=5
knn.pred <- knn(pila.nl[entrena.idx, ], pila.nl[test.idx, ], tema[entrena.idx],k=5)
conf.mat <- table("Predicción" = knn.pred,"Real" = tema[test.idx])
conf.mat
##           Real
## Predicción acq earn
##       acq  468   14
##       earn  22  826
Sensibilidad <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[1,2]))*100
Sensibilidad
## [1] 97.09544
Especificidad <- (conf.mat[2,2]/(conf.mat[1,2]+conf.mat[2,2]))*100
Especificidad
## [1] 98.33333
precision <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[2,1]))*100
precision
## [1] 95.5102

Podemos decir que el modelo usando K=5 presenta una mayor precisión, aunque podemos ver que los valores seleccionados no representan grandes variaciones entre ellos. En cualquier caso, para la elección del valor K, siempre tendremos que tener o encontrar un balance para evitar el overfitting o underfitting del modelo. A menor valor de K, más capacidad de encontrar patrones y detalles dentro del set de datos usado, pero no permitiría realizar una generalización de estos. Considero que en el proceso de modelización se debería realizar un análisis usando diferentes valores, ver el impacto en los ratios relevantes para el análisis que se quiere hacer y tomar una decisión consensuada sobre lo que aporta más valor.

El Valor K determina el numero de “vecinos” a usar en nuestro modelo KNN para la clasificación teniendo en cuenta la metrica de distancia utilizada. El modelo clasifica en base al resultado más frecuente dentro del rango determinado en el valor K. Si usamos K=2, estamos haciendo que el modelo pueda tener problemas con empates de valores analizados, lo que puede tener un impacto en la eficacia del algoritmo. Por este motivo es recomendable siempre usar valores impares o primos.

11.11 Ejercicio 6:

Del fichero inicial seleccionar dos temáticas distintas a las del enunciado y entrenar un k-NN que permita clasificar nuevos artículos en una de ambas temáticas. ¿Podría explicar de forma detallada como realiza la clasificación el algoritmo k-NN?

11.12 Respuesta 6:

Para realizar este ejercicio he seleccionado las temáticas “crude” y “trade”.

Previamente al uso del algoritmo de clasificación Knn, debemos realizar:

Instalación de paquetes, definición del directorio de trabajo usando la función setwd() y ejecutamos las librerías necesarias para utilizar la función Corpus(), library (tm), concatenar los valores, library (plyr) y la librería (class) para la ejecución del algoritmo knn. Para el ejercicio no lo realizaremos porque ya han sido instalados previamente.

Instalación de paquetes: install.packages(“tm”) install.packages(“plyr”) install.packages(“class”) install.packages(“ggplot2”) install.packages(“SnowballC”) install.packages(“wordcloud”)

Definición del directorio de trabajo*** setwd(“D:\uoc\Data Analytics Specialization\Fundamentos del data Science\Modulo1\PEC1”)

Librerías necesarias para poder crear el corpus, el concatenado de valores con rbind y class para poder usar el algoritmo Knn # Para la función Corpus() library(tm) # Para la función rbind.fill library(plyr) # Para la función knn() library(class)

Para asegurarnos que los caracteres no numéricos se consideren strings y no factores como por defecto hace R, usamos lo siguiente:

options(stringsAsFactors = FALSE)

Procedemos a la lectura de datos, visualizamos el total y las frecuencias por temática, aquí usamos también la función qplot() para realizar nuestra primera visualización gráfica.

Lectura de los datos*** data <- read.table(‘data_reuter.txt’, header=FALSE, sep=’)

Visualización de datos totales*** nrow(data)

visualizamos el Split de datos por temática y “pintamos” nuestra primera visualización***

table(data$V1)
## 
##      acq    crude     earn    grain interest money-fx     ship    trade 
##     1596      253     2840       41      190      206      108      251
library(ggplot2)
qplot(data$V1,xlab="Tematica", main = "Frecuencias")+ coord_flip()

> Procedemos a seleccionar dos temáticas (crude, trade) que queremos usar para el algoritmo knn(), lo guardamos en un nuevo factor data3 y visualizamos el número de datos que contienen las temáticas crude y trade

data3<-data[which(data$V1 %in% c("crude","trade")),]
nrow(data3)
## [1] 504

Creamos el corpus para el data cleaning y acondicionamiento del texto que vamos a usar

Creación del corpus para la temática crude elecionamos la temática generando otro factor data_crude

data_crude<-data3[(data3$V1=="crude"),]

construimos el corpus***

source2 <- VectorSource(data_crude$V2)
corpus3 <- Corpus(source2)

Realizamos las tareas de acondicionamiento** Convertir todo el texto a minúsculas

corpus3 <- tm_map(corpus3, content_transformer(tolower))

Elimina números*

corpus3 <- tm_map(corpus3, removeNumbers)

Eliminar signos de puntuación*

corpus3 <- tm_map(corpus3, removePunctuation)

Eliminar espacios en blanco innecesarios*

corpus3 <- tm_map(corpus3, stripWhitespace)

Eliminar palabras sin significado propio*

v_stopwords <- c(stopwords("english"),c("dont","didnt","arent","cant","one","also","said"))
corpus3 <- tm_map(corpus3, removeWords, v_stopwords)

Eliminar signos de puntuación*

corpus3 <- tm_map(corpus3, removePunctuation)

Substituir las palabras derivadas por su palabra raíz*

corpus3 <- tm_map(corpus3, stemDocument, language="english")

Realizamos todo el proceso de nuevo para la temática trade***

data_trade<-data3[(data3$V1=="trade"),]
source <- VectorSource(data_trade$V2)
corpus4 <- Corpus(source)
corpus4 <- tm_map(corpus4, content_transformer(tolower))
corpus4 <- tm_map(corpus4, removeNumbers)
corpus4 <- tm_map(corpus4, removePunctuation)
corpus4 <- tm_map(corpus4, stripWhitespace)
v_stopwords <- c(stopwords("english"),c("dont","didnt","arent","cant","one","also","said"))
corpus4 <- tm_map(corpus4, removeWords, v_stopwords)
corpus4 <- tm_map(corpus4, removePunctuation)
corpus4 <- tm_map(corpus4, stemDocument, language="english")

Construcción de matriz de términos por temática utilizando los factores corpus generados en el paso anterior, control de dispersión y unificación de las matrices en una única lista

temática crude. Asignando una dispersión del 0.85 usando la función removeSparseTerms***

mat_crude <- TermDocumentMatrix(corpus3)
mat_crude<- removeSparseTerms(mat_crude,  0.85)
inspect(mat_crude)
## <<TermDocumentMatrix (terms: 68, documents: 253)>>
## Non-/sparse entries: 4599/12605
## Sparsity           : 73%
## Maximal term length: 9
## Weighting          : term frequency (tf)
## Sample             :
##         Docs
## Terms    137 142 245 249 250 36 44 51 59 84
##   barrel   4   4   2   0   1  3  0  1  3  2
##   bpd      8   8   0  18  15  1 20 10  7  5
##   crude    1   1   2   5   3  6  2  3  7  4
##   dlrs     5   5   7   0   0  4  0  1  9  4
##   mln      8   8   0  28  11  5 13  8  7  2
##   oil     10  10  18  10   8 19  3  3 19  6
##   opec    24  23   1   5   4  0  6 19 10 19
##   price   10  10   8   2   2  7  3  8 17 14
##   reuter   3   2   1   1   1  1  4  4  4  1
##   will     4   4   7   2   2  2  0  1  8  1
mat_crude<-list(name="crude",mat=mat_crude)
mat_crude
## $name
## [1] "crude"
## 
## $mat
## <<TermDocumentMatrix (terms: 68, documents: 253)>>
## Non-/sparse entries: 4599/12605
## Sparsity           : 73%
## Maximal term length: 9
## Weighting          : term frequency (tf)
str(mat_crude)
## List of 2
##  $ name: chr "crude"
##  $ mat :List of 6
##   ..$ i       : int [1:4599] 1 2 3 4 5 6 7 8 9 10 ...
##   ..$ j       : int [1:4599] 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ v       : num [1:4599] 2 2 1 3 3 1 2 1 1 2 ...
##   ..$ nrow    : int 68
##   ..$ ncol    : int 253
##   ..$ dimnames:List of 2
##   .. ..$ Terms: chr [1:68] "barrel" "compani" "corp" "crude" ...
##   .. ..$ Docs : chr [1:253] "1" "2" "3" "4" ...
##   ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"

repetimos el proceso para la temática trade ***

mat_trade <- TermDocumentMatrix(corpus4)
mat_trade<- removeSparseTerms(mat_trade,  0.85)
inspect(mat_trade)
## <<TermDocumentMatrix (terms: 96, documents: 251)>>
## Non-/sparse entries: 6316/17780
## Sparsity           : 74%
## Maximal term length: 13
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     108 185 188 201 203 236 31 48 81 86
##   billion  11   3   0   1   1   2  6  1  1  1
##   countri   6   1   0   1   0  14  1  3  4  4
##   export   10   3   1   0   0   2  2  1  0  0
##   import    2   1   4   2  12   2  2  3  7  6
##   japan     5  13   9  14   8   4  1  1  1  1
##   japanes   0  13   8   6   4   0  0  0  0  0
##   reuter    1   2   1   3   1   1  1  1  1  1
##   trade    18  11   5  22   6   6  8 19 28 26
##   will      9   0   1   1  12   9  6  8  6  5
##   year      8   3   1   1   4   2  4  2  5  5
mat_trade<-list(name="trade",mat=mat_trade)
mat_trade
## $name
## [1] "trade"
## 
## $mat
## <<TermDocumentMatrix (terms: 96, documents: 251)>>
## Non-/sparse entries: 6316/17780
## Sparsity           : 74%
## Maximal term length: 13
## Weighting          : term frequency (tf)
str(mat_trade)
## List of 2
##  $ name: chr "trade"
##  $ mat :List of 6
##   ..$ i       : int [1:6316] 1 2 3 4 5 6 7 8 9 10 ...
##   ..$ j       : int [1:6316] 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ v       : num [1:6316] 3 1 1 3 1 1 1 2 3 1 ...
##   ..$ nrow    : int 96
##   ..$ ncol    : int 251
##   ..$ dimnames:List of 2
##   .. ..$ Terms: chr [1:96] "billion" "countri" "dlr" "dlrs" ...
##   .. ..$ Docs : chr [1:251] "1" "2" "3" "4" ...
##   ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"

procedemos a juntar ambas matrices en una lista***

matz<-list(mat_crude, mat_trade)
str(matz)
## List of 2
##  $ :List of 2
##   ..$ name: chr "crude"
##   ..$ mat :List of 6
##   .. ..$ i       : int [1:4599] 1 2 3 4 5 6 7 8 9 10 ...
##   .. ..$ j       : int [1:4599] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ v       : num [1:4599] 2 2 1 3 3 1 2 1 1 2 ...
##   .. ..$ nrow    : int 68
##   .. ..$ ncol    : int 253
##   .. ..$ dimnames:List of 2
##   .. .. ..$ Terms: chr [1:68] "barrel" "compani" "corp" "crude" ...
##   .. .. ..$ Docs : chr [1:253] "1" "2" "3" "4" ...
##   .. ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   .. ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"
##  $ :List of 2
##   ..$ name: chr "trade"
##   ..$ mat :List of 6
##   .. ..$ i       : int [1:6316] 1 2 3 4 5 6 7 8 9 10 ...
##   .. ..$ j       : int [1:6316] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ v       : num [1:6316] 3 1 1 3 1 1 1 2 3 1 ...
##   .. ..$ nrow    : int 96
##   .. ..$ ncol    : int 251
##   .. ..$ dimnames:List of 2
##   .. .. ..$ Terms: chr [1:96] "billion" "countri" "dlr" "dlrs" ...
##   .. .. ..$ Docs : chr [1:251] "1" "2" "3" "4" ...
##   .. ..- attr(*, "class")= chr [1:2] "TermDocumentMatrix" "simple_triplet_matrix"
##   .. ..- attr(*, "weighting")= chr [1:2] "term frequency" "tf"

Realizamos visualizaciones básicas sobre la variable mat, tales como, frecuencias de términos limitando el número de documentos, usamos la función head para visualizar los primeros términos por temática, el numero de términos y documentos por temática y usamos la función findFreqTerms para ver los términos que aparecen con más frecuencia que la especificada # Frecuencia de los 25 primeros términos en los 10 primeros documentos para ambos temas

inspect(matz[[1]]$mat[1:25,1:10])
## <<TermDocumentMatrix (terms: 25, documents: 10)>>
## Non-/sparse entries: 104/146
## Sparsity           : 58%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##         Docs
## Terms    1 10  2 3 4 5 6 7 8 9
##   bpd    0  0  4 0 0 0 0 7 0 0
##   crude  3  0  0 1 3 4 0 2 0 0
##   dlrs   2  0  0 1 1 2 2 2 1 0
##   last   1  2  1 0 1 1 0 4 3 0
##   market 2  0  5 0 0 0 0 3 0 2
##   meet   0  0  7 0 0 0 0 3 0 1
##   mln    0  0  4 0 0 0 2 4 1 0
##   oil    5  5 12 0 2 1 2 7 4 3
##   price  6  2  7 1 2 2 0 8 1 2
##   reuter 1  1  2 0 1 1 1 1 1 1
inspect(matz[[2]]$mat[1:25,1:10])
## <<TermDocumentMatrix (terms: 25, documents: 10)>>
## Non-/sparse entries: 121/129
## Sparsity           : 52%
## Maximal term length: 7
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     1 10 2 3  4 5 6 7 8  9
##   billion 3  0 4 0  1 2 1 0 7  2
##   countri 1  2 0 0  1 0 3 3 0  4
##   export  1  0 3 0  1 4 2 5 2 10
##   import  1  5 3 0  2 3 0 0 0  5
##   japan   0  5 2 0 10 0 0 3 0  0
##   last    1  0 0 0  2 3 1 0 0  4
##   reuter  1  1 1 1  1 2 1 1 1  1
##   surplus 3  0 4 0  1 4 0 0 0  0
##   trade   3  2 2 3 15 5 7 4 0 14
##   year    1  2 3 0  1 6 0 0 1  4

Frecuencia de los 30 primeros términos en todos los documentos del tema crude

inspect(matz[[1]]$mat[1:30,])
## <<TermDocumentMatrix (terms: 30, documents: 253)>>
## Non-/sparse entries: 2508/5082
## Sparsity           : 67%
## Maximal term length: 8
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     137 142  2 245 249 44 51 54 59 84
##   barrel    4   4  0   2   0  0  1  1  3  2
##   bpd       8   8  4   0  18 20 10 18  7  5
##   crude     1   1  0   2   5  2  3  8  7  4
##   dlrs      5   5  0   7   0  0  1  0  9  4
##   mln       8   8  4   0  28 13  8 22  7  2
##   oil      10  10 12  18  10  3  3  4 19  6
##   opec     24  23 16   1   5  6 19  7 10 19
##   price    10  10  7   8   2  3  8  2 17 14
##   product   7   7  6   1   4  2  2  5  2  3
##   reuter    3   2  2   1   1  4  4  1  4  1

Frecuencia de los términos en los documentos del tema trade

inspect(matz[[2]]$mat)
## <<TermDocumentMatrix (terms: 96, documents: 251)>>
## Non-/sparse entries: 6316/17780
## Sparsity           : 74%
## Maximal term length: 13
## Weighting          : term frequency (tf)
## Sample             :
##          Docs
## Terms     108 185 188 201 203 236 31 48 81 86
##   billion  11   3   0   1   1   2  6  1  1  1
##   countri   6   1   0   1   0  14  1  3  4  4
##   export   10   3   1   0   0   2  2  1  0  0
##   import    2   1   4   2  12   2  2  3  7  6
##   japan     5  13   9  14   8   4  1  1  1  1
##   japanes   0  13   8   6   4   0  0  0  0  0
##   reuter    1   2   1   3   1   1  1  1  1  1
##   trade    18  11   5  22   6   6  8 19 28 26
##   will      9   0   1   1  12   9  6  8  6  5
##   year      8   3   1   1   4   2  4  2  5  5

Inventario de los primeros términos del del tema trade

head(matz[[2]]$mat$dimnames$Terms)
## [1] "billion" "countri" "dlr"     "dlrs"    "domest"  "end"

Número de documentos del tema crude

nDocs(matz[[1]]$mat)
## [1] 253

Número de términos del tema crude

nTerms(matz[[1]]$mat)
## [1] 68

Visualizamos los términos con más de 100 apariciones en documentos de temática crude

findFreqTerms(matz[[1]]$mat, lowfreq=100)
##  [1] "barrel"    "compani"   "crude"     "day"       "dlrs"      "last"     
##  [7] "market"    "oil"       "price"     "product"   "reuter"    "bpd"      
## [13] "energi"    "industri"  "mln"       "opec"      "output"    "petroleum"
## [19] "report"    "will"      "pct"       "year"      "countri"   "minist"   
## [25] "offici"    "produc"    "export"    "govern"

Realizamos la representación la representación gráfica de las frecuencias, para ello tenemos que crear un dataframe de términos y frecuencias por temáticas, se concatenan usando la función rbind y se usa ggplot( ) para representar el grafico de barras, el cual he indicando que represente las palabras con una frecuencia mayor de 200

Para crude***

mmat_crude <- as.matrix(matz[[1]]$mat)

Agregamos las frecuencias por términos y las ordenamos de mayor a menor ***

v_crude <- sort(rowSums(mmat_crude), decreasing=TRUE)

Creamos un data.frame con términos y frecuencias***

d_crude <- data.frame(word=names(v_crude), freq=v_crude)
d_crude[,3]<-"crude"

Hacemos lo mismo para trade ##

mmat_trade <- as.matrix(matz[[2]]$mat)

Agregamos las frecuencias por términos y las ordenamos de mayor a menor ##

v_trade <- sort(rowSums(mmat_trade), decreasing=TRUE)

Creamos un data.frame con términos y frecuencias ##

d_trade <- data.frame(word=names(v_trade), freq=v_trade)
d_trade[,3]<-"trade"

Concatenamos las dos matrices usando la función rbind()

fdata2<-rbind(d_crude,d_trade)
colnames(fdata2)
## [1] "word" "freq" "V3"
colnames(fdata2)<-c("Palabra", "Frecuencia", "Tematica")

Gráfico de barras con las palabras más frecuentes ##

library(ggplot2)

ggplot(subset(fdata2, Frecuencia>200),aes(Palabra,Frecuencia,fill=Tematica))+geom_bar(stat="identity",position=position_dodge())+theme(axis.text.x=element_text(angle=45, hjust=1))

Construcción de una nube de palabras, para ello necesitamos cargar la librería wordcloud y pasamos como parámetro de la función que el mínimo de frecuencia de aparición sea 200##

require(wordcloud)
sfdata2<-subset(fdata2, Frecuencia>200)
wordcloud(sfdata2$Palabra, fdata2$Frecuencia,min.freq=200,random.color=FALSE, colors=rainbow(3))

Procedemos a crear un data frame apto para el modelo Knn, las columnas son los términos, las filas documentos y la intersección entre ellos la frecuencia de aparición del del término en cada documento

Para crude

s.mat_crude <- t(data.matrix(matz[[1]]$mat))
s.df_crude <- as.data.frame(s.mat_crude, stringsAsFactors = FALSE)
nrow(s.df_crude)
## [1] 253

vemos que el número de filas es de 253 para la temática crude##

Asignaremos (usando la función rep()) el tema del documento tantas veces como filas contenga el dataframe, para ello usaremos el valor de “name” que hemos definido previamente.

Tema2 <- rep(matz[[1]]$name, nrow(s.df_crude))
s.df_crude<-cbind(s.df_crude,Tema2)

Realizaremos el mismo proceso para la temática trade***

s.mat_trade <- t(data.matrix(matz[[2]]$mat))
s.df_trade <- as.data.frame(s.mat_trade, stringsAsFactors = FALSE)
Tema2 <- rep(matz[[2]]$name, nrow(s.df_trade))
s.df_trade<-cbind(s.df_trade,Tema2)

Concatenamos ambos dataframes y rellenamos con NA las combinaciones vacías##

pila2 <-rbind.fill(s.df_crude, s.df_trade)
pila2[is.na(pila2)] <- 0

Vemos el número de filas (documentos) y numero de columnas (palabras) que se han generado tras combinar los dataframes##

nrow(pila2)
## [1] 504

Tenemos 504 documentos

ncol(pila2)
## [1] 126

tenemos 126 palabras

Finalmente vamos a construir el modelo de clasificación que consta de dos partes: el 70% de los documentos formarán el juego de datos de entrenamiento el 30% de los documentos formarán el juego de datos de pruebas asginamos valor a la función set.seed() para asegurarnos de que el modelo sea replicable**

set.seed(111)

realizamos la división de documentos entre el juego de datos de entrenamiento y el de pruebas***

entrena2.idx <- sample(nrow(pila2), ceiling(nrow(pila2) * 0.7))
test2.idx <- (1:nrow(pila2))[-entrena2.idx]

se usa la función sample() para generar un set de datos aleatorio y usando la función ceiling dentro de la misma para asegurarnos el redondeo de la operación, con esto obtenemos el 70% de datos necesarios para el juego de entrenamiento. En el caso de del juego de datos de prueba, simplemente se obtiene restando los documentos que se han guardado en el juego de entrenamiento y creando una variable especifica #Separamos los temas y la matriz de frecuencias para adaptarlos y poder aplicarlos en el algoritmo knn #Guardamos los temas:***

tema <- pila2[, "Tema2"]

Guardamos las palabras***

pila3.nl <- pila2[, !colnames(pila2) %in% "Tema2"]

Aplicamos el modelo K-NN**, pasándole como parámetros la matriz de frecuencias de los documentos de entrenamiento, la matriz de frecuencias de los documentos de pruebas y los temas de los documentos de entrenamiento. Pasamos 1 como valor de K.

knn.pred2 <- knn(pila3.nl[entrena2.idx, ], pila3.nl[test2.idx, ], tema[entrena2.idx],k=1)

Generamos la matriz de confusión***

conf.mat <- table("Predicción" = knn.pred2,"Real" = tema[test2.idx])
conf.mat
##           Real
## Predicción crude trade
##      crude    83     1
##      trade     0    67

Observamos que: El modelo ha clasificado correctamente 83 verdaderos positivos, 67 verdaderos negativos y solo hemos obtenido 1 falso positivo Esta matriz nos permite calcular los ratos de sensibilidad, especificidad y precisión ratio de sensibilidad de un 98.80952%***

Sensibilidad <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[1,2]))*100
Sensibilidad
## [1] 98.80952

ratio de especificidad de 98.52941%***

Especificidad <- (conf.mat[2,2]/(conf.mat[1,2]+conf.mat[2,2]))*100
Especificidad
## [1] 98.52941

ratio de precisión del 100%***

precision2 <- (conf.mat[1,1]/(conf.mat[1,1]+conf.mat[2,1]))*100
precision2
## [1] 100

estos resultados nos dicen que el algoritmo es tremendamente efectivo en la clasificación de Positivos verdaderos (True Positive Rate), de igual manera también lo es para la clasificación de verdaderos negativos y obteniendo un 100% de precisión***

11.13 Ejercicio 7:

¿En qué distancia se basa el algoritmo K-NN que se define en la función knn() de R que se ha utilizado para entrenar el modelo?. Realizad una o más críticas a dicha distancia y describid cómo podría corregirse.

11.14 Respuesta 7:

El algoritmo knn se basa en la distancia euclidiana. Esta distancia se usa para medir la distancia en línea recta entre dos puntos y entre una de sus funcionalidades destaca la de determinar la similitud entre datos analizados, lo cual lo hace ser uno de los estándares para algoritmos de clasificación o de recomendación.