Chapter 8 Introducción a los datos

8.1 El lenguaje de los datos

Cargamos los datos de ejemplo

library(openintro)
## Please visit openintro.org for free statistics materials
## 
## Attaching package: 'openintro'
## The following objects are masked _by_ '.GlobalEnv':
## 
##     cars, iris
## The following object is masked from 'package:ggplot2':
## 
##     diamonds
## The following objects are masked from 'package:datasets':
## 
##     cars, trees
data(email50)

library(dplyr)
glimpse(email50)
## Observations: 50
## Variables: 21
## $ spam         <dbl> 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, …
## $ to_multiple  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, …
## $ from         <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ cc           <int> 0, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ sent_email   <dbl> 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, …
## $ time         <dttm> 2012-01-04 14:19:16, 2012-02-16 21:10:06, 2012-01-…
## $ image        <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ attach       <dbl> 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, …
## $ dollar       <dbl> 0, 0, 0, 0, 9, 0, 0, 0, 0, 23, 4, 0, 3, 2, 0, 0, 0,…
## $ winner       <fct> no, no, no, no, no, no, no, no, no, no, no, no, yes…
## $ inherit      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ viagra       <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ password     <dbl> 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, …
## $ num_char     <dbl> 21.705, 7.011, 0.631, 2.454, 41.623, 0.057, 0.809, …
## $ line_breaks  <int> 551, 183, 28, 61, 1088, 5, 17, 88, 242, 578, 1167, …
## $ format       <dbl> 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, …
## $ re_subj      <dbl> 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, …
## $ exclaim_subj <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ urgent_subj  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ exclaim_mess <dbl> 8, 1, 2, 1, 43, 0, 0, 2, 22, 3, 13, 1, 2, 2, 21, 10…
## $ number       <fct> small, big, none, small, small, small, small, small…

Identificamos los tipos de variables con str() o glimpse() del paquete dplyr.

Tipo de variables: Numéricas (o cuantiativas) y categóricas (o cualitativas). Las numéricas se pueden dividir en continuas (pueden tener decimales) o discretas (como contajes). Las categóricas pueden ser ordinales con un orden.

8.1.1 Datos categóricos: factores

Los datos categóricos en R suelen estar guardadaos y almacenados como factores. Vamos a emplear el conjunto de datos email50 del paquete openintro.

library(openintro)
data(email50)
str(email50)
## 'data.frame':    50 obs. of  21 variables:
##  $ spam        : num  0 0 1 0 0 0 0 0 0 0 ...
##  $ to_multiple : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ from        : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ cc          : int  0 0 4 0 0 0 0 0 1 0 ...
##  $ sent_email  : num  1 0 0 0 0 0 0 1 1 0 ...
##  $ time        : POSIXct, format: "2012-01-04 14:19:16" "2012-02-16 21:10:06" ...
##  $ image       : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ attach      : num  0 0 2 0 0 0 0 0 0 0 ...
##  $ dollar      : num  0 0 0 0 9 0 0 0 0 23 ...
##  $ winner      : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
##  $ inherit     : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ viagra      : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ password    : num  0 0 0 0 1 0 0 0 0 0 ...
##  $ num_char    : num  21.705 7.011 0.631 2.454 41.623 ...
##  $ line_breaks : int  551 183 28 61 1088 5 17 88 242 578 ...
##  $ format      : num  1 1 0 0 1 0 0 1 1 1 ...
##  $ re_subj     : num  1 0 0 0 0 0 0 1 1 0 ...
##  $ exclaim_subj: num  0 0 0 0 0 0 0 0 1 0 ...
##  $ urgent_subj : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ exclaim_mess: num  8 1 2 1 43 0 0 2 22 3 ...
##  $ number      : Factor w/ 3 levels "none","small",..: 2 3 1 2 2 2 2 2 2 2 ...

Vemos que la última variable de email50, llamada number, es factorial con tres niveles: none, small y big. Hacemos un filtro seleccionando únicamente el factor big mediante el empleo del operador pipe del paquete dplyr y su función filter().

library(dplyr)
email50_big <- email50 %>%
  filter(number == "big")

glimpse(email50_big)
## Observations: 7
## Variables: 21
## $ spam         <dbl> 0, 0, 1, 0, 0, 0, 0
## $ to_multiple  <dbl> 0, 0, 0, 0, 0, 0, 0
## $ from         <dbl> 1, 1, 1, 1, 1, 1, 1
## $ cc           <int> 0, 0, 0, 0, 0, 0, 0
## $ sent_email   <dbl> 0, 0, 0, 0, 0, 1, 0
## $ time         <dttm> 2012-02-16 21:10:06, 2012-02-05 00:26:09, 2012-01-…
## $ image        <dbl> 0, 0, 0, 0, 0, 0, 0
## $ attach       <dbl> 0, 0, 0, 0, 0, 0, 0
## $ dollar       <dbl> 0, 0, 3, 2, 0, 0, 0
## $ winner       <fct> no, no, yes, no, no, no, no
## $ inherit      <dbl> 0, 0, 0, 0, 0, 0, 0
## $ viagra       <dbl> 0, 0, 0, 0, 0, 0, 0
## $ password     <dbl> 0, 2, 0, 0, 0, 0, 8
## $ num_char     <dbl> 7.011, 10.368, 42.793, 26.520, 6.563, 11.223, 10.613
## $ line_breaks  <int> 183, 198, 712, 692, 140, 512, 225
## $ format       <dbl> 1, 1, 1, 1, 1, 1, 1
## $ re_subj      <dbl> 0, 0, 0, 0, 0, 0, 0
## $ exclaim_subj <dbl> 0, 0, 0, 1, 0, 0, 0
## $ urgent_subj  <dbl> 0, 0, 0, 0, 0, 0, 0
## $ exclaim_mess <dbl> 1, 1, 2, 7, 2, 9, 9
## $ number       <fct> big, big, big, big, big, big, big

Si hacemos una tabla de frecuencias con table() referida a la variable number del conjunto de datos recien creado email50_big nos indica que de los factores none y small no tienen ningún dato. Esto es obvio porque los habíamos filtrado previamente con filter(). Ahora lo que queremos es que nos eliminen los factores cuya frecuencia sea cero. Y para ello usamos la función droplevels().

# Frecuencias de cada factor
table(email50_big$number)
## 
##  none small   big 
##     0     0     7
# Eliminamos los factores con frecuencia cero
email50_big$number <- droplevels(email50_big$number)

# Frecuencia del factor con datos únicamente
table(email50_big$number)
## 
## big 
##   7

Ahora vamos a dividir una variable numérica en dos, num_char, que representa el número de caracteres en cada email (x1000), en dos. Vamos a emplear como punto de corte la mediana de todos sus valores. Valores situados por debajo los vamos a llamar debajo de la mediana y al resto igual o por encima de la mediana. En esta ocasión, vamos a emplear la función ifelse() creando una variable nueva llamada num_char_cat dentro de la función mutate().

# Calculamos la mediana
med_num_char <- median(email50$num_char)

# Creamos la variable num_char_cat
email50_fortified <- email50 %>%
  mutate(num_char_cat = ifelse(num_char < med_num_char, "debajo de la mediana", "igual o por encima de la mediana"))
  
# Contamos cuántos emails están por encima o debajo
email50_fortified %>%
  count(num_char_cat)
## # A tibble: 2 x 2
##   num_char_cat                         n
##   <chr>                            <int>
## 1 debajo de la mediana                25
## 2 igual o por encima de la mediana    25

También podemos combinar factores si es necesario. Por ejemplo, unir de la variable number los factores small y big, manteniendo el factor none. Para ello, creamos una nueva variable, number_yn donde small y big se unan dando la categoría , y el factor none se convierta en no. Con este fin, empleamos la función mutate() y case_when().

# Create number_yn column in email50
email50_fortified <- email50 %>%
  mutate(
    number_yn = case_when(
      # si number es "none", se convierte number_yn en "no"
      number == "none" ~ "no", 
      # si number no es "none", se convierte number_yn en "sí"
      number != "none" ~ "sí"  
    )
  )
  
# Lo vemos usando ggplot2
library(ggplot2)
ggplot(email50_fortified, aes(x = number_yn)) +
  geom_bar()

8.2 Tipos de estudios estadísticos

Tipos de estudios estadísticos:

  • Estudios observacionales: la recogida de datos se hace de un modo que no interfiere directamente con cómo los datos se han reunido. Solo se pueden inferir correlaciones.
  • Estudios experimentales: Se asignan varios tratamiento aleatoriamente a varios sujetos. Se puede inferir la causación.

¡¡¡¡AMPLIAR ESTO CON MÁS INFORMACIÓN!!!!

Un muestreo aleatorio y una asignación aleatoria no son lo mismo. El muestreo aleatorio sucede cuando los sujetos han sido seleccionados para un estudio de un modo aleatorio dentro de la población, pudiendo generalizar los resultados a toda la población. La asignación aleatoria ocurre solo en la configuración de un estudio experimental, donde los sujetos han sido asignados a varios tratamientos, permitiendo inferir conclusiones causales.

Asignación aleatoria No asignación aleatoria
Muestreo aleatorio Causal y generalizable No causal, pero generalizable Generalizable
No muestreo aleatorio Causal, pero no generalizable Ni causal ni generalizable No generalizable
Causal No causal

La paradoja de Simpson sucede cuando omitimos en una relación entre la variable respuesta y la explicativa, alguna variable explicativa importante que podría cambiar el modo de relación observada entre la variable explicativa empleada. Vamos a verlo con un ejemplo de estudiantes admitidos en la Universidad de California Berkeley por sexo.

data("UCBAdmissions") # del paquete datasets
ucb_admits_df <- as.data.frame(UCBAdmissions)
ucb_admits <- ucb_admits_df[rep(row.names(ucb_admits_df), ucb_admits_df$Freq), 1:3]

library(dplyr)

ucb_admission_counts <- ucb_admits %>%
  count(Gender, Admit)
print(ucb_admission_counts)
## # A tibble: 4 x 3
##   Gender Admit        n
##   <fct>  <fct>    <int>
## 1 Male   Admitted  1198
## 2 Male   Rejected  1493
## 3 Female Admitted   557
## 4 Female Rejected  1278
# Calculamos la proporción de admitidos entre hombres y mujeres
ucb_admission_counts %>%
  # Group by gender
  group_by(Gender) %>%
  # Create new variable
  mutate(prop = n / sum(n)) %>%
  # Filter for admitted
  filter(Admit == "Admitted")
## # A tibble: 2 x 4
## # Groups:   Gender [2]
##   Gender Admit        n  prop
##   <fct>  <fct>    <int> <dbl>
## 1 Male   Admitted  1198 0.445
## 2 Female Admitted   557 0.304

Vemos que alrededor del 44% de los hombres han sido admitidos mientras que solo el 30% de las mujeres lo fueron.

Finally we’ll make a table similar to the one we constructed earlier, except we’ll first group the data by department. The goal is to compare the proportions of male admitted students across departments.

ucb_admission_counts <- ucb_admits %>%
  count(Dept, Gender, Admit)

print(ucb_admission_counts)
## # A tibble: 24 x 4
##    Dept  Gender Admit        n
##    <fct> <fct>  <fct>    <int>
##  1 A     Male   Admitted   512
##  2 A     Male   Rejected   313
##  3 A     Female Admitted    89
##  4 A     Female Rejected    19
##  5 B     Male   Admitted   353
##  6 B     Male   Rejected   207
##  7 B     Female Admitted    17
##  8 B     Female Rejected     8
##  9 C     Male   Admitted   120
## 10 C     Male   Rejected   205
## # … with 14 more rows
ucb_admission_counts  %>%
  # Group by department, then gender
  group_by(Dept, Gender) %>%
  # Create new variable
  mutate(prop = n/sum(n)) %>%
  # Filter for male and admitted
  filter(Gender == "Male", Admit == "Admitted")
## # A tibble: 6 x 5
## # Groups:   Dept, Gender [6]
##   Dept  Gender Admit        n   prop
##   <fct> <fct>  <fct>    <int>  <dbl>
## 1 A     Male   Admitted   512 0.621 
## 2 B     Male   Admitted   353 0.630 
## 3 C     Male   Admitted   120 0.369 
## 4 D     Male   Admitted   138 0.331 
## 5 E     Male   Admitted    53 0.277 
## 6 F     Male   Admitted    22 0.0590
print(ucb_admission_counts)
## # A tibble: 24 x 4
##    Dept  Gender Admit        n
##    <fct> <fct>  <fct>    <int>
##  1 A     Male   Admitted   512
##  2 A     Male   Rejected   313
##  3 A     Female Admitted    89
##  4 A     Female Rejected    19
##  5 B     Male   Admitted   353
##  6 B     Male   Rejected   207
##  7 B     Female Admitted    17
##  8 B     Female Rejected     8
##  9 C     Male   Admitted   120
## 10 C     Male   Rejected   205
## # … with 14 more rows

Visto desde un principio, sin controlar por el departamento, veíamos que los hombres eran mayoritariamente admitidos. Sin embargo, al incluir los datos de los departamentos, vemos que es mayoritaria la aceptación de mujeres. Esto sería una paradoja de Simpson.

8.3 Estrategias de muestreo y de diseño experimental

Teóricamente podríamos evaluar la totalidad de la población de estudio, en vez de seleccionar unos pocos indiviuos, lo que se conoce como muestra. Pero evaluar toda la población requiere una inversión de recursos, tiempo y dinero normalmente muy elevado. Es por eso que se seleccionan unos pocos individuos del conjunto sobre los que se miden los parámetros de nuestro estudio, y posteriormente podamos hacer inferencias sobre la población. Además, algunos individuos de nuestra población podrían ser muy difíciles de localizar, lo que hace necesario hacer un muestreo. Incluso, si tomáramos los datos de todos los individuos, en un futuro próximo podría cambiar y toda la inversión generada no servir.

Por ejemplo, cuando estamos cocinando un potaje, en vez de tomárnoslo entero para ver cómo sabe, cogemos una cuchara y probamos un poco. De este modo estamos obteniendo una muestra, y en base a esa muestra hacemos una inferencia sobre cómo está la totalidad del potaje. Pero podríamos tener un problema, y es que si hemos echado la sal y no hemos removido, la cuchara coge normalmente la parte superficial y en este caso tendríamos una cucharada muy salada que no sería la representación de la totalidad de la cazuela. Por eso es necesario que la cucharada (muestra) sea representativa de toda la cazuela. Es por eso que las técnicas de muestreo son esenciales, y tenemos 4 posibles estrategias de muestreo:

  • Muestreo aleatorio simple (simple ramdon sample). Se seleccionan varios elementos de la población de un modo aleatorio, de tal modo que cada elemento tiene las mismas probabilidades de ser escogido.
  • Muestreo estratificado (stratified sample). Primero dividimos la población en grupos homogéneos conocidos como estratos, y sobre cada grupo seleccionamos aleatoriamente sus elementos. Por ejemplo una población humana la dividimos en grupos en base a estados socioeconómicos.
  • Muestreo por agrupamiento (cluster sample). Se selecionan aleatoriamente los clusters o grupos y después se muestrea sobre ellos aleatoriamente. Los grupos son, por tanto, heterogéneos y similares entre sí, sienda esta la principal diferencia con el muestreo estratificado.
  • Muestreo multietapa (multistage sample). Añade un paso extra al muestreo por agrupamiento.

8.3.1 Muestreo aleatorio simple

Cargamos el conjunto de datos county del paquete openintro. Estos datos nos dan la información sobre los diferentes condados (counties) de Estados Unidos. Cada uno de los estados está dividido en condados, menos el Distrito Columbia.

library(openintro)
data(county)

# Eliminamos el Distrito Columbia
county_noDC <- county %>%
  filter(state != "District of Columbia") %>%
  droplevels()

Como tenemos recursos limitados, tenemos que seleccionar aleatoriamente 150 condados de los más de 3000 que existen en Estados Unidos. Para ello podemos seleccionar un muestreo aleatorio simple. Y para ello empleamos la función sample_n() del paquete dplyr.

county_srs <- county_noDC %>%
  sample_n(size = 150)

8.3.2 Muestreo estratificado

Si en el ejemplo anterior quisiéramos escoger aleatoriamente 3 condados de cada estado americano, el muestreo aleatorio simple no nos lo garantiza. Por lo tanto, tenemos que recurrir al muestreo estratificado empleando la función group_by() de dplyr.

county_srs <- county_noDC %>%
  group_by(state) %>%
  sample_n(size = 3)

8.3.3 Principios del diseño experimental

Los principios del diseño experimental pueden resumirse en cuatro puntos:

  • Control. Se establece un grupo control para comparar con el del tratamiento.
  • Aleatorizar. Asignar aleatoriamente sujetos a los tratamientos.
  • Replicación. Obtener un número suficientemente alto de la muestra del estudio, o replicar el estudio completo.
  • Block. Percatarse del efecto potencial de variables que pueden confundir. En un estudio sobre si los estudiantes aprender mejor programación en R con cursos online o con clases presenciales, se divide un grupo aleatoriamente en dos. Pero puede estar influenciado por su conocimiento previo de la programación, por lo que el bloque es su habilidad anterior de programación. En base a esta variable se seleccionan aleatoriamente individuos para impartir clases online y presenciales donde estén igualmente representados estudiantes con conocimientos previos y sin conocimientos previos en programación.