Objetivo


El objetivo de este markdown es plasmar las pautas principales para tener nuestros datos correctamente planteados y organizados.


Introduccion


library(tidyverse)

Tidy Data


Todos los datos con los que vayamos a trabajar siempre se van a poder representar de multiples formas. Este ejemplo muestra la misma informacion organizada de diferentes maneras.

table1
## # A tibble: 6 x 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583
table2
## # A tibble: 12 x 4
##    country      year type            count
##    <chr>       <int> <chr>           <int>
##  1 Afghanistan  1999 cases             745
##  2 Afghanistan  1999 population   19987071
##  3 Afghanistan  2000 cases            2666
##  4 Afghanistan  2000 population   20595360
##  5 Brazil       1999 cases           37737
##  6 Brazil       1999 population  172006362
##  7 Brazil       2000 cases           80488
##  8 Brazil       2000 population  174504898
##  9 China        1999 cases          212258
## 10 China        1999 population 1272915272
## 11 China        2000 cases          213766
## 12 China        2000 population 1280428583
table3
## # A tibble: 6 x 3
##   country      year rate             
## * <chr>       <int> <chr>            
## 1 Afghanistan  1999 745/19987071     
## 2 Afghanistan  2000 2666/20595360    
## 3 Brazil       1999 37737/172006362  
## 4 Brazil       2000 80488/174504898  
## 5 China        1999 212258/1272915272
## 6 China        2000 213766/1280428583
table4a
## # A tibble: 3 x 3
##   country     `1999` `2000`
## * <chr>        <int>  <int>
## 1 Afghanistan    745   2666
## 2 Brazil       37737  80488
## 3 China       212258 213766
table4b
## # A tibble: 3 x 3
##   country         `1999`     `2000`
## * <chr>            <int>      <int>
## 1 Afghanistan   19987071   20595360
## 2 Brazil       172006362  174504898
## 3 China       1272915272 1280428583

Todos son representaciones de los mismos datos pero no pueden ser usados de la misma manera.

Hay tres reglas principales que definen nuestro dataset como organizado o “tidy”.

  1. Cada variable tiene que tener su propia columna
  2. Cada observacion tiene que tener su propia fila
  3. Cada valor tiene que tener su propia celda
knitr::include_graphics("Tidy data.png")
A caption

A caption


Ampliacion y union (Spreading and Gathering)


Aunque creamos que no, la mayoria de la informacion que nos encontremos estara desorganizada y no adaptada a los estandares que hemos comentado anteriormente.

Por ello, el primer paso es siempre descubrir cuales son las variables y observaciones

El segundo paso, es resolver uno de estos dos problemas que son bastante comunes. Una variable que aparezca entre multiples columnas o una observacion que se disperse a través de multiples filas.

Para solucionar todos estos aspectos utilizaremos las funciones de gather() y spread().

Gathering

Un problema comun de los dataset es cuando algunos de los nombres de las columnas no son nombres de variables, si no valores de las variables.

table4a
## # A tibble: 3 x 3
##   country     `1999` `2000`
## * <chr>        <int>  <int>
## 1 Afghanistan    745   2666
## 2 Brazil       37737  80488
## 3 China       212258 213766

Necesitamos que esas columnas se junten en un nuevo par de variables. Para ello, definiremos 3 parametros.

table4a %>% 
  gather("1999","2000", key = "year", value = "cases")
## # A tibble: 6 x 3
##   country     year   cases
##   <chr>       <chr>  <int>
## 1 Afghanistan 1999     745
## 2 Brazil      1999   37737
## 3 China       1999  212258
## 4 Afghanistan 2000    2666
## 5 Brazil      2000   80488
## 6 China       2000  213766
knitr::include_graphics("Gathering table.png")
A caption

A caption

Para combinar diferentes tablas podemos utilizar la funcion de dplyr left_join().

Spreading

Spreading es lo contrario a gathering. Cuando una observacion se encuentra dispersa entre multiples filas.

En este caso solo necesitamos definir dos parametros:

spread(table2, key = type, value = count)
## # A tibble: 6 x 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583
knitr::include_graphics("Spreading table.png")
A caption

A caption


Separar y tirar (Separating and Pull)


Separating

Separate() separa una columna en multiples repartiendolas donde aparezca un separador de caracter.

table3
## # A tibble: 6 x 3
##   country      year rate             
## * <chr>       <int> <chr>            
## 1 Afghanistan  1999 745/19987071     
## 2 Afghanistan  2000 2666/20595360    
## 3 Brazil       1999 37737/172006362  
## 4 Brazil       2000 80488/174504898  
## 5 China        1999 212258/1272915272
## 6 China        2000 213766/1280428583
table3 %>%
  separate(rate, into = c("cases", "population"), sep = "/", convert = TRUE)
## # A tibble: 6 x 4
##   country      year  cases population
## * <chr>       <int>  <int>      <int>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Por defecto separate() dividira los valores donde vea un caracter no alfanumerico, pero podemos marcar la separacion que quereamos con sep=.

Por otro lado, los tipos de columnas de case y population son caracteres porque la transformacion se realiza asi por defecto. Pero no es util ya que son numeros, con la funcion convert solucionamos ese problema.

knitr::include_graphics("Separating table.png")
A caption

A caption

Unite

Unite() es lo contrario a separate. Combinas multiples columnas en una unica columna.

table5
## # A tibble: 6 x 4
##   country     century year  rate             
## * <chr>       <chr>   <chr> <chr>            
## 1 Afghanistan 19      99    745/19987071     
## 2 Afghanistan 20      00    2666/20595360    
## 3 Brazil      19      99    37737/172006362  
## 4 Brazil      20      00    80488/174504898  
## 5 China       19      99    212258/1272915272
## 6 China       20      00    213766/1280428583
table5 %>% 
  unite(new, century, year, sep = "")
## # A tibble: 6 x 3
##   country     new   rate             
##   <chr>       <chr> <chr>            
## 1 Afghanistan 1999  745/19987071     
## 2 Afghanistan 2000  2666/20595360    
## 3 Brazil      1999  37737/172006362  
## 4 Brazil      2000  80488/174504898  
## 5 China       1999  212258/1272915272
## 6 China       2000  213766/1280428583

Missing Values


A la hora de trabajar con diferentes dataset siempre apareceran problemas o diferentes formar de trabajar con los missing values.

Un Missing value nos puede aparecer de dos diferentes manera:

  1. Explicita: Marcado con un NA
  2. Implicita: Simplemente que no aparezca en nuestro dataset

Por ejemplo,

stocks <- tibble(
  year = c(2015, 2015, 2015, 2015, 2016, 2016, 2016),
  qtr = c( 1, 2, 3, 4, 2, 3, 4), 
  return = c(1.88, 0.59, 0.35, NA, 0.92, 0.17, 2.66)
)

En este caso, tenemos como missing values, un valor faltante en el Q4 de 2015 y en el Q1 de 2016 ni si quiera tenemos los datos.

Lo podriamos ver de esta manera:

Un valor faltante explícito es la presencia de una ausencia; Un valor implícito que falta es la ausencia de una presencia

Por ejemplo, podemos hacer que los missing values implicitos sean explicitos poniendo los años en las columnas.

stocks %>% 
  spread(year, return)
## # A tibble: 4 x 3
##     qtr `2015` `2016`
##   <dbl>  <dbl>  <dbl>
## 1     1   1.88  NA   
## 2     2   0.59   0.92
## 3     3   0.35   0.17
## 4     4  NA      2.66

Por otro lado, utilizando na.rm = TRUE podemos transformar los missing values explicitos en implicitos.

stocks %>% 
  spread(year, return) %>% 
  gather(year, return, "2015", "2016", na.rm = TRUE)
## # A tibble: 6 x 3
##     qtr year  return
## * <dbl> <chr>  <dbl>
## 1     1 2015    1.88
## 2     2 2015    0.59
## 3     3 2015    0.35
## 4     2 2016    0.92
## 5     3 2016    0.17
## 6     4 2016    2.66

Otra herramienta es la funcion complete() para hacer los missing values explicitos.

En este caso, complete toma un conjunto de columnas y encuentra todas las combinaciones únicas. Luego se asegura de que el conjunto de datos original contenga todos esos valores, completando las NA explícitas cuando sea necesario.

stocks %>%
  complete(year, qtr)
## # A tibble: 8 x 3
##    year   qtr return
##   <dbl> <dbl>  <dbl>
## 1  2015     1   1.88
## 2  2015     2   0.59
## 3  2015     3   0.35
## 4  2015     4  NA   
## 5  2016     1  NA   
## 6  2016     2   0.92
## 7  2016     3   0.17
## 8  2016     4   2.66

Por ultimo, otra herramienta es la funcion fill().

Cuando una fuente de datos se ha utilizado principalmente para la entrada de datos, los valores faltantes indican que el valor anterior debe mantenerse

treatment <- tribble(
  ~person, ~treatment, ~responde,
  "Derrick Whitmore", 1, 7,
  NA, 2, 10,
  NA, 3, 9,
  "Katherine Burke", 1, 4)

treatment %>%
  fill(person)
## # A tibble: 4 x 3
##   person           treatment responde
##   <chr>                <dbl>    <dbl>
## 1 Derrick Whitmore         1        7
## 2 Derrick Whitmore         2       10
## 3 Derrick Whitmore         3        9
## 4 Katherine Burke          1        4

Caso de estudio


Aplicaremos todo lo que hemos tratado anteriormente en este dataset que recoge los casos de tuberculosis anuales por año, pais, edad, genero y metodo de diagnostico.

Asi se nos muestra la tabla inicial:

who
## # A tibble: 7,240 x 60
##    country iso2  iso3   year new_sp_m014 new_sp_m1524 new_sp_m2534
##    <chr>   <chr> <chr> <int>       <int>        <int>        <int>
##  1 Afghan~ AF    AFG    1980          NA           NA           NA
##  2 Afghan~ AF    AFG    1981          NA           NA           NA
##  3 Afghan~ AF    AFG    1982          NA           NA           NA
##  4 Afghan~ AF    AFG    1983          NA           NA           NA
##  5 Afghan~ AF    AFG    1984          NA           NA           NA
##  6 Afghan~ AF    AFG    1985          NA           NA           NA
##  7 Afghan~ AF    AFG    1986          NA           NA           NA
##  8 Afghan~ AF    AFG    1987          NA           NA           NA
##  9 Afghan~ AF    AFG    1988          NA           NA           NA
## 10 Afghan~ AF    AFG    1989          NA           NA           NA
## # ... with 7,230 more rows, and 53 more variables: new_sp_m3544 <int>,
## #   new_sp_m4554 <int>, new_sp_m5564 <int>, new_sp_m65 <int>,
## #   new_sp_f014 <int>, new_sp_f1524 <int>, new_sp_f2534 <int>,
## #   new_sp_f3544 <int>, new_sp_f4554 <int>, new_sp_f5564 <int>,
## #   new_sp_f65 <int>, new_sn_m014 <int>, new_sn_m1524 <int>,
## #   new_sn_m2534 <int>, new_sn_m3544 <int>, new_sn_m4554 <int>,
## #   new_sn_m5564 <int>, new_sn_m65 <int>, new_sn_f014 <int>,
## #   new_sn_f1524 <int>, new_sn_f2534 <int>, new_sn_f3544 <int>,
## #   new_sn_f4554 <int>, new_sn_f5564 <int>, new_sn_f65 <int>,
## #   new_ep_m014 <int>, new_ep_m1524 <int>, new_ep_m2534 <int>,
## #   new_ep_m3544 <int>, new_ep_m4554 <int>, new_ep_m5564 <int>,
## #   new_ep_m65 <int>, new_ep_f014 <int>, new_ep_f1524 <int>,
## #   new_ep_f2534 <int>, new_ep_f3544 <int>, new_ep_f4554 <int>,
## #   new_ep_f5564 <int>, new_ep_f65 <int>, newrel_m014 <int>,
## #   newrel_m1524 <int>, newrel_m2534 <int>, newrel_m3544 <int>,
## #   newrel_m4554 <int>, newrel_m5564 <int>, newrel_m65 <int>,
## #   newrel_f014 <int>, newrel_f1524 <int>, newrel_f2534 <int>,
## #   newrel_f3544 <int>, newrel_f4554 <int>, newrel_f5564 <int>,
## #   newrel_f65 <int>

Y esta es la tabla final con todo lo aplicado.

who %>%
  gather(code, value, new_sp_m014:newrel_f65, na.rm = TRUE) %>% 
  mutate(code = stringr::str_replace(code,"newrel","new_rel")) %>%
  separate(code, c("new", "var", "sexage")) %>%
  select(-new, -iso2, -iso3) %>%
  separate(sexage, c("sex", "age", sep = 1))
## # A tibble: 76,046 x 7
##    country      year var   sex   age   `1`   value
##    <chr>       <int> <chr> <chr> <chr> <chr> <int>
##  1 Afghanistan  1997 sp    m014  <NA>  <NA>      0
##  2 Afghanistan  1998 sp    m014  <NA>  <NA>     30
##  3 Afghanistan  1999 sp    m014  <NA>  <NA>      8
##  4 Afghanistan  2000 sp    m014  <NA>  <NA>     52
##  5 Afghanistan  2001 sp    m014  <NA>  <NA>    129
##  6 Afghanistan  2002 sp    m014  <NA>  <NA>     90
##  7 Afghanistan  2003 sp    m014  <NA>  <NA>    127
##  8 Afghanistan  2004 sp    m014  <NA>  <NA>    139
##  9 Afghanistan  2005 sp    m014  <NA>  <NA>    151
## 10 Afghanistan  2006 sp    m014  <NA>  <NA>    193
## # ... with 76,036 more rows