2015-06-14

Una introducción a la minería de textos en R con El Quijote

Title Vamos a ver una introducción a la minería de textos en R utilizando el texto de El Quijote.

Importación y manipulación

  1. Necesitamos descargar el texto de Project Gutenberg. Contiene las dos partes.
  2. quijote_ruta <- "http://www.gutenberg.org/cache/epub/2000/pg2000.txt"
    download.file(quijote_path, "quijote.txt")
    # Especificamos el argumento encoding por los acentos y caracteres especiales como la ñ.
    lineas <- readLines("quijote.txt", encoding = "UTF-8")
    head(lineas, 3)
    tail(lineas, 3)
    
  3. Observamos que hay texto no perteneciente al libro tanto al comienzo como al final.
  4. head(lineas, 3)
    
    [1] "The Project Gutenberg EBook of Don Quijote, by Miguel de Cervantes Saavedra"
    [2] ""                                                                              
    [3] "This eBook is for the use of anyone anywhere at no cost and with" 
    
    tail(lineas, 3)
    
    [1] "including how to make donations to the Project Gutenberg Literary" 
    [2] "Archive Foundation, how to help produce our new eBooks, and how to"
    [3] "subscribe to our email newsletter to hear about new eBooks." 
    
    Lo eliminamos:

    lineas  <-  lineas[-(1:36)] # Comienzo
    lineas  <-  lineas[-(37454:length(lineas))] # Final
    
    head(lineas, 3)
    
    [1] "El ingenioso hidalgo don Quijote de la Mancha" ""                                             
    [3] ""
    
    tail(lineas, 3)
    
    [1] ""    ""    "Fin"
    
  5. Creamos el corpus. Utilizamos el paquete tm
  6. library(tm)
    doc.corpus <- Corpus(VectorSource(lineas))
    
    [1] "El ingenioso hidalgo don Quijote de la Mancha" ""                                             
    [3] ""
    
  7. Realizamos varias transformaciones al texto
  8.  # Muestra las transformaciones disponibles
    getTransformations()
    # Realizaremos las siguientes:
    doc.corpus <- tm_map(doc.corpus, content_transformer(tolower)) # Minúsculas
    doc.corpus <- tm_map(doc.corpus, removePunctuation) # Puntuación
    doc.corpus <- tm_map(doc.corpus, removeNumbers) # Números
    
  9. Construimos nuestro Term Document Matrix (TDM)
  10. TDM <- TermDocumentMatrix(doc.corpus)
    
    Con el argumento control controlamos la longitud de las palabras incluidas. Por defecto es c(3, Inf), es decir, palabras de más de 3 letras. Para incluir todas las palabras:

    TDM <- TermDocumentMatrix(doc.corpus, 
                              control = list(wordLengths = c(1, Inf))) 
    

Consultas a nuestro corpus

  1. Inspección del corpus
  2. inspect(TDM)
    
    TermDocumentMatrix (terms: 22858, documents: 37453)
    Non-/sparse entries: 253654/855847020
    Sparsity           : 100%
    Maximal term length: 21
    Weighting          : term frequency (tf)
    
  3. Número de términos
  4. dim(TDM)
    
    [1] 22858 37453
    
  5. Términos frecuentes
  6. Empleamos la función findFreqTerms(x, lowfreq = 0, highfreq = Inf). Por defecto el límite inferior es cero y el superior infinito.

    # Más de 1.500 veces
    palabras.frec <- findFreqTerms(TDM, 1500) 
    
    [1] "como"    "con"     "del"     "dijo"    "don"     "las"     "los"     "más"     "por"     "que"     "quijote" "sancho" 
    
    # Entre 100 y 1000
    palabras.frec <- findFreqTerms(TDM, 100, 1000) 
    head(palabras.frec)
    
    [1] "adelante" "agora"    "ahora"    "algo"     "algún"    "alguna" 
    
  7. Asociaciones de palabras
  8. Con la función findAssocs(x, terms, corlimit). Especificamos como corlimit cero, para que nos devuelva todas las palabras aunque la correlación sea mínima.

    asociaciones <- findAssocs(TDM, "rocinante", 0)
    head(asociaciones, 10)
    
               rocinante
    riendas         0.13
    espuelas        0.12
    picó            0.11
    rucio           0.11
    ayudándole      0.10
    ensilló         0.10
    huellas         0.10
    cabestro        0.09
    subió           0.09
    

Reducción del tamaño del corpus

EL tamaño de nuestra Term-Document Matrix (TDM) es a veces demasiado grande. Si deseamos reducirlo:

TDM.comun <- removeSparseTerms(TDM, 0.999) 
dim(TDM.comun)
Cuanto más pequeño el sparse factor, porcentaje aplicado —0.999 en nuestro ejemplo—, menor número de palabras (aquellas más frecuentes incluirá). En nuestro ejemplo como solamente tenemos un documento y nuestra sparsity es 100% (ver inspect(TDM)), para no eliminar todos los términos debemos especificar un porcentaje muy grande.

 [1]   922 37453
Una manera de reducir drásticamente el tamaño de nuestro futuro corpus, es la siguiente línea:

doc.corpus <- Corpus(VectorSource(paste(lineas, collapse = " ")))

N-grams

Un n-gram es una secuencia continua de n elementos de un texto o discurso dado.

library(tau)
# Bigramas: n = 2
bigramas <- textcnt(lineas, n = 2, method = "string")
bigramas <- bigramas[order(bigramas, decreasing = TRUE)]
bigramas[1]
don quijote 
       2166 
# n = 5
n5<- textcnt(lineas, n = 5, method = "string")
n5<- n5[order(n5, decreasing = TRUE)]
data.frame(n5 = n5[1:10])
                               n5
don quijote de la mancha      134
caballero de la triste figura  34
la señora dulcinea del toboso  24
el caballero de la triste      21
el cura y el barbero           21
en todos los días de           21
caballero don quijote de la    17
de don quijote de la           17
el duque y la duquesa          17
señor don quijote de la        16
# n = 10
n10 <- textcnt(lineas, n = 10, method = "string")
n10 <- n10[order(n10, decreasing = TRUE)]
data.frame(n10 = n10[1:10])
                                                                 n10
cruel vireno fugitivo eneas barrabás te acompañe allá te avengas   4
parte del ingenioso hidalgo don quijote de la mancha capítulo      4
eso haré yo de muy buena gana señor mío respondió                  3
parte de la historia de don quijote de la mancha                   3
que desnudo nací desnudo me hallo ni pierdo ni gano                3
vuestro hasta la muerte el caballero de la triste figura           3
a dios rogando y con el mazo dando y que                           2
a la sin par dulcinea del toboso única señora de                   2
a mi casa y a mi mujer y a mis                                     2
antes se ha de perder por carta de más que                         2

Exportación

Para exportar los resultados transformamos nuestro Term-Document Matrix (TDM) bien en una matriz o en un data frame.

m <- as.matrix(TDM) # Large matrix
  • Matriz
  • # Matriz
    m1 <- sort(rowSums(m), decreasing = TRUE)
    data.frame(frec = m1[1:10])# para mostrarlo en una columna
    
             frec
    que     20626
    los      4748
    con      4202
    por      3940
    las      3468
    don      2647
    del      2491
    como     2263
    quijote  2175
    sancho   2148
    
    # Exportamos la matriz
    write.csv2(x = m1, file = "quijote89.csv", row.names = TRUE)
    
  • Data frame
  • # Data frame
    df <- data.frame(ocurrencias = sort(rowSums(m), decreasing = TRUE))
    write.csv2(x = df, file = "quijote.csv", row.names = TRUE) 
    
    Para consultar la frecuencia de una palabra en nuestro data frame.

    v["toledo", ] 
    
    [1] 11
    

    Nube de palabras

    Creamos una nube de palabras a partir de la matriz creada.

    library(wordcloud)
    set.seed(4) # Para obtener el mismo resultado siempre
    wordcloud(rownames(m), rowSums(m), min.freq = 1000)
    

    Referencias

    No hay comentarios:

    Publicar un comentario

    Nube de datos