2015-06-29

Eliminar duplicados de un data frame en R

Title

Problema

Deseamos eliminar los duplicados de un data frame en R.

Solución

Disponemos de múltiples opciones. Emplearemos como ejemplo el conjunto de datos iris que contiene dos filas duplicadas: la 102 y la 143

  • Paquete base
  • Detectamos los duplicados.

    # De arriba a abajo
    anyDuplicated(iris) # Número de fila
    iris[duplicated(iris), ]  # Fila
    
        Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    143          5.8         2.7          5.1         1.9 virginica
    
    # De abajo a arriba
    anyDuplicated(iris, fromLast = TRUE)
    iris[duplicated(iris, fromLast = TRUE), ]
    
        Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    102          5.8         2.7          5.1         1.9 virginica
    
    Eliminamos los duplicados.

    unique(iris)
    iris[!duplicated(iris), ]
    # En orden inverso
    unique(iris, fromLast = TRUE)
    iris[!duplicated(iris, fromLast = TRUE), ]
    
  • Paquete dplyr
  • library(dplyr)
    iris %>% distinct
    
  • Paquete sqldf
  • library(sqldf)
    sqldf('SELECT DISTINCT * FROM iris')
    

    Notas

    Usando el paquete base veremos que conserva el número de filas —150— aunque observaremos, dependiendo del orden que hayamos escogido, que la fila 102 o 143 habrá desaparecido. En cambio con dplyr y sqldf, el resultado numera de nuevo las filas, mostrando la última con el número 149.

    Entradas relacionadas

    2015-06-26

    Borrar a la vez todas las notas de una presentación en PowerPoint

    Title

    Problema

    Deseamos borrar a la vez todas las notas de nuestra presentación en PowerPoint.

    Solución

    Para evitar borrar manualmente cada una de las notas seguimos los siguientes pasos:

    1. Archivo -> Información -> Preparar para compartir -> Comprobar si hay problemas -> Inspector de documento
    2. Desactivamos todas las casillas de verificación salvo la de Notas de presentación y clic en Inspeccionar.
    3. A la derecha de Notas de presentación, clic en Quitar todo y luego en Cerrar.

    Al volver a la presentación, comprobaremos que todas las notas han sido borradas. Si deseamos recobrarlas, hacemos clic en deshacer o Ctrl+Z.

    Entradas relacionadas

    2015-06-24

    Estadísticas descriptivas en R

    Title

    Problema

    Deseamos calcular estadísticas descriptivas a nuestros datos.

    Solución

    Vamos a ver algunas de las fórmulas que hemos visto de manera dispersa en otras entradas.

  • Función summary
  • # Para una sola variable
    summary(iris$Sepal.Length)
    
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      4.300   5.100   5.800   5.843   6.400   7.900 
    
    # Para una tabla (data frame)
    summary(iris)
    
      Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
     Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100   setosa    :50  
     1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300   versicolor:50  
     Median :5.800   Median :3.000   Median :4.350   Median :1.300   virginica :50  
     Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199                  
     3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800                  
     Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
    
  • Función fivenum
  • Resumen con los 5 números de Tukey empleados en los diagramas de caja: mínimo, bigote inferior, mediana, bigote superior, máximo

    # Para una variable solamente
    fivenum(iris$Sepal.Width)
    
    [1] 2.0 2.8 3.0 3.3 4.4
    
  • Función boxplot.stats
  • boxplot.stats(iris$Sepal.Width)
    
    $stats
    [1] 2.2 2.8 3.0 3.3 4.0
    
    $n
    [1] 150
    
    $conf
    [1] 2.935497 3.064503
    
    $out
    [1] 4.4 4.1 4.2 2.0
    
    Podemos acceder a los elementos de la lista anterior, con el símbolo $ seguido del elemento de la lista:

    $stats - vector con los 5 números de Tukey.
    $n - número de observaciones.
    $conf - intervalo de confianza para la media.
    $out- los valores de los valores atípicos (outliers).

    Con el paquete psych

  • Para una tabla
  • install.packages("psych")
    require("psych")
    describe(iris)
    
                 vars   n mean   sd median trimmed  mad
    Sepal.Length    1 150 5.84 0.83   5.80    5.81 1.04
    Sepal.Width     2 150 3.06 0.44   3.00    3.04 0.44
    Petal.Length    3 150 3.76 1.77   4.35    3.76 1.85
    Petal.Width     4 150 1.20 0.76   1.30    1.18 1.04
    Species*        5 150  NaN   NA     NA     NaN   NA
                 min  max range  skew kurtosis   se
    Sepal.Length 4.3  7.9   3.6  0.31    -0.61 0.07
    Sepal.Width  2.0  4.4   2.4  0.31     0.14 0.04
    Petal.Length 1.0  6.9   5.9 -0.27    -1.42 0.14
    Petal.Width  0.1  2.5   2.4 -0.10    -1.36 0.06
    Species*     Inf -Inf  -Inf    NA       NA   NA
    
  • Estadísticas por grupo
  • describeBy(iris, group = iris$Species)
    
    group: setosa
                 vars  n mean   sd median trimmed  mad
    Sepal.Length    1 50 5.01 0.35    5.0    5.00 0.30
    Sepal.Width     2 50 3.43 0.38    3.4    3.42 0.37
    Petal.Length    3 50 1.46 0.17    1.5    1.46 0.15
    Petal.Width     4 50 0.25 0.11    0.2    0.24 0.00
    Species*        5 50  NaN   NA     NA     NaN   NA
                 min  max range skew kurtosis   se
    Sepal.Length 4.3  5.8   1.5 0.11    -0.45 0.05
    Sepal.Width  2.3  4.4   2.1 0.04     0.60 0.05
    Petal.Length 1.0  1.9   0.9 0.10     0.65 0.02
    Petal.Width  0.1  0.6   0.5 1.18     1.26 0.01
    Species*     Inf -Inf  -Inf   NA       NA   NA
    --------------------------------------- 
    group: versicolor
                 vars  n mean   sd median trimmed  mad
    Sepal.Length    1 50 5.94 0.52   5.90    5.94 0.52
    Sepal.Width     2 50 2.77 0.31   2.80    2.78 0.30
    Petal.Length    3 50 4.26 0.47   4.35    4.29 0.52
    Petal.Width     4 50 1.33 0.20   1.30    1.32 0.22
    Species*        5 50  NaN   NA     NA     NaN   NA
                 min  max range  skew kurtosis   se
    Sepal.Length 4.9  7.0   2.1  0.10    -0.69 0.07
    Sepal.Width  2.0  3.4   1.4 -0.34    -0.55 0.04
    Petal.Length 3.0  5.1   2.1 -0.57    -0.19 0.07
    Petal.Width  1.0  1.8   0.8 -0.03    -0.59 0.03
    Species*     Inf -Inf  -Inf    NA       NA   NA
    --------------------------------------- 
    group: virginica
                 vars  n mean   sd median trimmed  mad
    Sepal.Length    1 50 6.59 0.64   6.50    6.57 0.59
    Sepal.Width     2 50 2.97 0.32   3.00    2.96 0.30
    Petal.Length    3 50 5.55 0.55   5.55    5.51 0.67
    Petal.Width     4 50 2.03 0.27   2.00    2.03 0.30
    Species*        5 50  NaN   NA     NA     NaN   NA
                 min  max range  skew kurtosis   se
    Sepal.Length 4.9  7.9   3.0  0.11    -0.20 0.09
    Sepal.Width  2.2  3.8   1.6  0.34     0.38 0.05
    Petal.Length 4.5  6.9   2.4  0.52    -0.37 0.08
    Petal.Width  1.4  2.5   1.1 -0.12    -0.75 0.04
    Species*     Inf -Inf  -Inf    NA       NA   NA
    

    Referencias

    2015-06-22

    Project Euler - Problema 6 en R

    Title Continuamos con los problemas planteados en Project Euler.

    Problema - Sum square difference

    The sum of the squares of the first ten natural numbers is, 1^2 + 2^2 + ... + 10^2 = 385

    The square of the sum of the first ten natural numbers is, (1 + 2 + ... + 10)^2 = 55^2 = 3025

    Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is3025 − 385 = 2640.

    Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

    La suma de los cuadrados de los diez primeros números naturales es, 1^2 + 2^2 + ... + 10^2 = 385

    El cuadrado de la suma de los diez primeros números naturales es, (1 + 2 + ... + 10)^2 = 55^2 = 3.025

    La diferencia entre la suma de los cuadrados de los diez primeros números naturales y el cuadrado de la suma es 3.025 - 385 = 2.640 .

    Encuentra la diferencia entre la suma de los cuadrados de los primeros cien números naturales y el cuadrado de la suma .

    Solución

    sum(1:100)^2-sum((1:100)^2)
    
    [1] 25164150
    

    Referencias

    2015-06-20

    Generar números aleatorios en tipos de datos Autonumeración en Ms Access

    Title

    Problema

    Queremos crear una clave principal que utilice números aleatorios en lugar de valores numéricos incrementales.

    Solución

    1. Creamos una nueva tabla o abrimos una ya existente en Vista Diseño.
    2. En tipo de datos seleccionamos Autonumeración. En las Propiedades del campo, en Nuevos Valores seleccionamos Aleatoriamente.
    3. Por cada un nuevo registro a nuestra tabla, se generará un número aleatorio en el campo recién creado.

    Notas

    El objetivo del tipo de datos Autonumeración es generar un valor número único que Access insertará automáticamente cuando se agrega un registro. Se suelen usar como clave principal, aunque podemos crearlos y no utilizarlos como clave principal o quitarla posteriormente.

    Referencias

    2015-06-18

    Calcular el total acumulado en una columna o fila de Excel

    Title

    Problema

    Deseamos crear una columna o fila auxiliar mostrando el total acumulado de un rango.

    Solución

    Seguimos los siguientes pasos:

    1. Empleamos la función SUMA y creamos una referencia absoluta en la primera celda del rango.
    2. Situamos el cursor a la izquierda de los dos puntos y presionamos F4 una vez. Aparecerá el símbolo dólar a ambos lados de la letra. O bien los tecleamos manualmente.

    3. Arrastramos el controlador de relleno en la dirección de nuestro rango.
    4. Hacia abajo en nuestro ejemplo. Se observará como la última celda contiene la celda con la referencia absoluta —anclada— $B$2, y la última celda hasta que arrastramos el controlador, B13.

    Notas

    Se puede emplear este procedimiento para calcular el total acumulado en cualquier dirección deseada, por filas o columnas, y de izquierda a derecha o viceversa.

    Referencias

    2015-06-16

    Resolver ecuaciones de segundo grado en R

    Title

    Problema

    Queremos resolver una ecuación de segundo grado en R: ax2 + bx + c = 0.

    Solución

    1. Dos soluciones reales
    2. Números positivos dentro de la raíz cuadrada.

      2x2 + 20x + 3 = 0

      x <- 2
      y <- 20
      z <- 3
      
      x1 <- (-y + sqrt((y^2) - (4 * x * z)))/(2 * x)
      x2 <- (-y - sqrt((y^2) - (4 * x * z)))/(2 * x)
      print(c(x1, x2))
      
      No empleamos las letras a, b y c, pues c es una palabra reservada en R.

      [1] -0.1523201 -9.8476799
      
    3. Una solución real repetida
    4. Un cero y un número positivo dentro de la raíz cuadrada.

      x2 - 6x + 9 = 0

      x <- 1
      y <- -6
      z <- 9
      
      x1 <- (-y + sqrt((y^2) - (4 * x * z)))/(2 * x)
      x2 <- (-y - sqrt((y^2) - (4 * x * z)))/(2 * x)
      print(c(x1, x2))
      
      [1] 3 3
      
    5. Dos soluciones complejas
    6. Números negativos dentro de la raíz cuadrada.

      2x2 + 7x + 11 = 0

      x <- 2
      y <- 7
      z <- 11
      
      polyroot(c(z, y, x))
      
      [1] -1.75+1.561249i -1.75-1.561249i
      
      El código empleado en las dos opciones anteriores generaría un error. La función polyroot devolverá dos números complejos como la suma de un número real y uno número imaginario. También podemos emplear dicha fórmula en los casos anteriores. En dichos casos el número imaginario será 0i = 0.

      2x2 + 20x + 3 = 0

      x <- 2
      y <- 20
      z <- 3
      
      polyroot(c(z, y, x))
      
      [1] -0.1523201-0i -9.8476799+0i
      

    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

    Nube de datos