Capítulo 3 R para Explorar
“Aquí tengo todos los datos que demuestran incuestionablemente que los datos no demuestran NADA….”
— Miguel Brieva
La exploración de datos implica normalmente poder leer datos de fuentes y formatos diversos y acomodarlos según nos convenga. Estas tareas son, de hecho, las que suelen tomar más tiempo, de todo el proceso de análisis y asimilación de la información.
3.1 Leer datos
Nos puede interesar leer y analizar datos de varios lados: de un archivo, una página web, una base de datos, etc.
3.1.1 Leer datos de un archivo
Si queremos leer los datos de una tabla, por ejemplo, un archivo en formato .csv
(valores delimitados por comas) que tenemos en nuestra carpeta o directorio, lo podemos hacer mediante el paquete readr (Wickham 2017a).
## # A tibble: 13 x 10
## Nombre Cromos Edad Deporte Poblacion Pais numerodehermanos
## <chr> <int> <int> <chr> <chr> <chr> <int>
## 1 Pepito 35 12 Waterpolo Barcelona España 1
## 2 Juanito 15 13 Futbol Madrid España 3
## 3 Carlitos 3 9 Waterpolo Ceuta España 2
## 4 Pedrito 21 10 Petanca Mallorca España 2
## 5 Mariela 40 12 Futbol Barcelona España 4
## 6 Vicent 21 10 Futbol Valencia España 2
## 7 Pablo 0 13 Basquet Madrid España 1
## 8 Tanita 33 8 Waterpolo Murcia España 0
## 9 Antonio 26 9 Futbol Porto Portugal 2
## 10 Marc 31 10 Basquet Andorra Andorra 2
## 11 Marie 11 12 Ballet Rennes Francia 3
## 12 Anas 14 10 Futbol Rabat Marruecos 1
## 13 Alfredo 9 10 Futbol Quito Ecuador 4
## # ... with 3 more variables: Juegopreferido <chr>,
## # Fechadenacimiento <chr>, Sexo <chr>
Nota: ojo al detalle del formato usado para indicar la ubicación del archivo: las barras son del tipo /
(si usamos \
no nos funcionará).
De modo similar, leería los datos de un archivo .txt
(datos no tabulares) usando la variante de la función de lectura read_file
en mi expresión: misdatos <- read_file("path/miarchivo.txt")
.
Habrá que fijarse bien y cuando sea necesario usar las distintas variantes de la función de lectura de readr según cómo estén delimitados los datos en el archivo que queremos leer: sea por comas, por punto y coma, por separador (tab) o por cualquier otro delimitador.
Mírate esta chuleta de Rstudio para entender todas las opciones de importación de datos: https://github.com/rstudio/cheatsheets/raw/master/data-import.pdf.
En caso de que no estén por defecto en la función de lectura que usamos estas opciones las deberemos especificar nosotros en los argumentos de la función; así como si tienen título o no, si queremos considerar los datos faltantes o no, etc. Siempre nos aseguraremos de que los datos se nos importan en el formato correcto.
3.1.2 Leer datos contenidos en un excel
Si me interesan algunos datos que tengo en un excel; los puedo seleccionar, copiar (en el portapapeles) y luego voy a R y escribo: misdatos <- read.delim ("clipboard")
.
Ahora cuando lo que quiero es leer archivos enteros de excel desde R, usaré -de modo similar a cómo hemos visto para leer archivos csv- paquetes como xlsx (Dragulescu 2014) o readxl (Wickham and Bryan 2017) (paquete que es parte del conjunto integrado de paquetes Tidyverse) y sus respectivas funciones para leer los datos de las tablas de un excel: read.xlsx ()
y read_excel()
.
3.1.3 Leer datos de una página web
Pongamos que me interesa una tabla en csv disponible en una página web. La puedo importar también con misdatos <- read.csv("http://www..../archivo.csv")
.
Otro caso seria recuperar una parte de contenido que se encuentra en formato HTML en una página web a un formato estructurado que podamos analizar. La técnica asociada a ese fin se conoce como webscrapping
. En R hay un paquete específico para hacer webscraping llamado rvest (Wickham 2016).
Por ejemplo, imaginemos que soy un fan del waterpolo y quiero recuperar los resultados de la competición de la categoría de másteres que se encuentran en la página de la federación catalana de natación:
#cargo el paquete rvest
library(rvest)
#asigno un nombre a la URL de la página que me interesa
clasificacion_waterpolo <-
read_html("https://www.aquatics.cat/competicio/informacioCompeticio/2017/228/97/0")
#recupero la segunda tabla que aparece en esta página indicando ".[[2]]" en la expresión:
clasificacion_waterpolo %>%
html_nodes("table") %>%
.[[2]] %>%
html_table()
## CLASSIFICACIÓ CLASSIFICACIÓ CLASSIFICACIÓ CLASSIFICACIÓ
## 1 NA Equip P PJ
## 2 1 CN Mataró 37 13
## 3 2 CN Terrassa 34 13
## 4 3 CN Molins de Rei 33 13
## 5 4 CLUB ESPORTIU MEDITERRANI 33 13
## 6 5 CN Sant Andreu 33 13
## 7 6 CN Catalunya 31 13
## 8 7 UE Horta 31 13
## 9 8 CN Martorell 26 13
## 10 9 CW SANT ADRIA B 25 13
## 11 10 CN Badia 25 14
## 12 11 Club Natació L'Hospitalet 23 14
## 13 12 CN Sabadell 22 13
## 14 13 Club Natació Poble Nou 22 13
## 15 14 CN Premià 21 14
## 16 15 CW SANT ADRIA A 21 13
## 17 16 CW Can Dragó 16 13
## 18 17 CN Atlètic-Barceloneta 15 13
## CLASSIFICACIÓ CLASSIFICACIÓ CLASSIFICACIÓ CLASSIFICACIÓ CLASSIFICACIÓ
## 1 PG PE PP GF GC
## 2 12 0 1 173 64
## 3 10 1 2 126 67
## 4 10 0 3 155 86
## 5 10 0 3 124 93
## 6 10 0 3 134 80
## 7 9 0 4 126 91
## 8 9 0 4 125 97
## 9 6 1 6 105 115
## 10 6 0 7 105 112
## 11 5 1 8 115 121
## 12 4 1 9 97 129
## 13 3 4 6 79 97
## 14 4 1 8 108 136
## 15 3 1 10 79 123
## 16 4 0 9 62 131
## 17 1 1 11 54 152
## 18 1 0 12 70 143
Ya tengo los resultados.
3.2 Acomodar datos
Muy a menudo, sin embargo, los datos se nos presentan de forma bruta o imperfecta (formatos raros, valores que faltan, duplicidades, etc) o simplemente no están de la forma que queremos. Por ello es importante acomodarlos de un modo que sea adecuado o conveniente para su análisis.
3.2.1 Funciones base en R
En R es posible usar funciones como apply, lapply, sapply, tapply, etc.
para realizar operaciones comunes en el trabajo con matrices y tablas.
- apply, permite aplicar funciones a filas o columnas de una matriz.
Por ejemplo, aplicaríamos la funcion suma a las columnas de la matriz df
con la expresión:
apply (df, 2, sum)
(aquí 1
se usa para indicar fila y 2
para indicar columna)
- lapply, extrae una parte de una matriz o tabla como una lista.
Por ejemplo, para extraer la primera fila de la tabla df
usariamos:
lapply (df, "[", 1, )
y para extraer la segunda columna de la tabla df
:
lapply (df, "[", , 2)
- tapply, permite aplicar funciones a una variable, desglosada en base a otra.
Por ejemplo, en el caso de nuestros datos, para calcular la mediana del número de cromos por sexo:
## f m
## 28.0 17.5
Las chicas tienen de media más cromos que los chicos.
Otras funciones disponibles en R base (sin necesidad de cargar paquetes adicionales) útiles para ordenar, filtrar o hacer transformaciones a nuestros datos son sort()
, subset()
o transform()
.
Prueba a buscar ayuda sobre estas funciones (por ejemplo escribiendo ?sort
).
3.2.2 Paquete dplyr
Más recientemente, en el marco de herramientas integradas que facilitan acomodar datos (tidyverse), podemos usar varias funciones incluidas en el paquete dplyr (Wickham et al. 2017). Las más importantes son:
filter() que permite filtrar observaciones por sus valores.
arrange() para reordenar filas por variables.
select() para tomar variables por sus nombres.
mutate() para canviar variables o crear nuevas variables con funciones de variables existentes.
summarise() para sumarizar muchos valores en uno solo.
Por ejemplo, para eliminar una columna de una tabla puedo usar select()
y el operador negativo -
:
df %>% select(-variable_inutil)
(siendo variable_inutil
el nombre de la columna de df
que no quiero).
Para eliminar filas duplicadas puedo usar la función distinct()
:
df_limpia <- df %>% distinct()
elimina filas duplicadas de df
y asigna una nueva tabla (df_limpia
) sin ellas (distinct
és útil por tanto para hacer recuentos de variables descartando las que aparecen más de una vez).
Con filter()
(función similar a subset
en R base) puedo por ejemplo retener determinadas observaciones de una columna (p.ej. un determinado rango de la variable Edad
):
df %>% filter(Edad > 18)
Con arrange()
(similar a sort
en R base) ordenar datos en orden ascendente: arrange(Edad)
o descendente : arrange(desc(Edad))
.
Con mutate()
(similar a transform
en R base) puedo, por ejemplo, crear una nueva variable en base a otras:
mutate(nueva_columna = col1 + col2)
Nota: vemos que una forma de expresar varias funciones a la vez de un modo eficiente y entendedor es usando el operador %>%
(conocido como pipe
y disponible con los paquetes magritte y tidyverse). Consiste básicamente en que, en vez de expresar una función que opere sobre unos datos como f(datos)
, lo puedo hacer como datos %>% f
y ello me permite ir concatenando varias funciones que quiera aplicar sobre esos mismos datos y que sea fácil de entender.
Veámoslo en un ejemplo:
library(dplyr)
misdatos %>%
#hago filtro de los que no son hijos únicos
filter(numerodehermanos > 1) %>%
#creo nueva variable resultante de dividir Cromos por Edad
mutate(RatioCromosEdad = Cromos/Edad) %>%
#creo nueva variable (Edaden5) sumándole 5 años a la variable Edad
transform(Edaden5 = Edad + 5) %>%
#ordeno por numero de cromos en orden descendente
arrange(desc(Cromos)) %>%
#mostrar las primeras 5 filas de la tabla resultante
head(5)
## Nombre Cromos Edad Deporte Poblacion Pais numerodehermanos
## 1 Mariela 40 12 Futbol Barcelona España 4
## 2 Marc 31 10 Basquet Andorra Andorra 2
## 3 Antonio 26 9 Futbol Porto Portugal 2
## 4 Pedrito 21 10 Petanca Mallorca España 2
## 5 Vicent 21 10 Futbol Valencia España 2
## Juegopreferido Fechadenacimiento Sexo RatioCromosEdad Edaden5
## 1 Farcry 12-4-2004 f 3.333333 17
## 2 GuitarHero 28-9-2005 m 3.100000 15
## 3 Minecraft 12-7-2007 m 2.888889 14
## 4 ClashRoyale 30-5-2006 m 2.100000 15
## 5 Minecraft 1-9-2005 m 2.100000 15
3.2.3 Limpiar textos
Para limpiar textos a menudo nos interesa reemplazar carácteres de nuestros datos brutos por otros más sencillos. Para ello suelen ser muy útiles funciones como gsub. La expresamos como:
gsub(pattern, replacement, x, ignore.case = TRUE)
Dónde:
pattern
: carácteres a cambiar.replacement
: carácteres para remplazar.x
: nuestros datos.ignore.case
: ponemos TRUE cuando queremos ignorar si el patrón es mayúsculas o minúsculas.
Por ejemplo:
## [1] "anger"
La función substr la podemos usar, por ejemplo, para eliminar n carácteres de un elemento. Si sólo queremos los carácteres del primero al onceavo:
## [1] "loquequiero"
Esta misma expresión la podemos opcionalmente formar junto con nchar
para indicar el número de carácteres que no queremos (empezando en este caso por atrás):
## [1] "loquequiero"
Otro paquete stringr (Wickham 2017b) es también útil para manipular textos; de modo similar me permite tomar sólo los últimos carácteres de algo:
## [1] "art"
O extrer las palabras unidas por guiones bajos en una frase:
## [[1]]
## [1] "el" "último" "de" "la" "fila"
O considerar los NA que aparecen a menudo en una tabla o un vector de textos como datos faltantes y reemplazarlos por carácteres (entrecomillados) sin eliminarlos:
## [1] "una_cosa" "NA" "otra_cosa"
Nota: Quizás lo estés pensando; pues sí, en R una misma cosa puede hacerse de muchos modos distintos y usando paquetes distintos. Hay algunas funciones comunes y paquetes muy usados -las que estamos tratando de mostrar aquí- pero existen innumerables funciones para resolver problemas similares y uno siempre encontrará un paquete que haga la misma cosa pero de otro modo.
Referencias
Wickham, Hadley. 2017a. Readr: Read Rectangular Text Data. https://CRAN.R-project.org/package=readr.
Dragulescu, Adrian A. 2014. Xlsx: Read, Write, Format Excel 2007 and Excel 97/2000/Xp/2003 Files. https://CRAN.R-project.org/package=xlsx.
Wickham, Hadley, and Jennifer Bryan. 2017. Readxl: Read Excel Files. https://CRAN.R-project.org/package=readxl.
Wickham, Hadley. 2016. Rvest: Easily Harvest (Scrape) Web Pages. https://CRAN.R-project.org/package=rvest.
Wickham, Hadley, Romain Francois, Lionel Henry, and Kirill Müller. 2017. Dplyr: A Grammar of Data Manipulation. https://CRAN.R-project.org/package=dplyr.
Wickham, Hadley. 2017b. Stringr: Simple, Consistent Wrappers for Common String Operations. https://CRAN.R-project.org/package=stringr.