Muestrear aleatoriamente un data frame teniendo en cuenta los factores en R

Seleccionar un número de filas de un tabla es relativamente sencillo en R. Pero si queremos seleccionar aleatoriamente un número de elementos concreto teniendo en consideración los factores de una variable categórica, ya es otro cantar. Estas tablas en R se conocen como data frames. Como sé que esto es algo difícil de comprender con palabras, vamos a poner un ejemplo práctico con el que vais a aprender a muestrear aleatoriamente un data frame teniendo en cuenta los factores.

Aunque si lo que queréis es muestrear una buena cantidad de data frames localizados dentro de una lista, estáis en el sitio equivocado. En su lugar, hay que leerse con detenimiento este texto.

Volviendo a nuestro caso, vamos emplear los datos que se llaman mtcars, que se sitúan dentro del paquete datasets.

data(mtcars) # cargamos los datos

Y nos vamos a interesar especialmente por la columna cyl, que representa el número de cilindros del coche. Al cargar los datos, esta variable cyl no tiene categoría de factor, por lo que primero que hacemos en convertirla en una variable factorial. Si no controláis el tema de los factores en R, aquí tenéis un magnífico comienzo para comprenderlos.

mtcars$cyl <- factor(mtcars$cyl) # convertimos la variable cyl en factorial

Ya tenemos nuestro conjunto de datos preparado. Si vemos su estructura, observamos que presenta 32 observaciones (filas) y 11 variables (columnas).

str(mtcars)
'data.frame':    32 obs. of  11 variablestimares:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : Factor w/ 3 levels "4","6","8": 2 2 1 2 3 2 3 1 1 2 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

Si nos centramos más específicamente sobre la variable cyl, vemos que tiene 3 factores: 4, 6 y 8. Y cada factor tiene un número diferente de observaciones. Por ejemplo, en el conjunto de datos mtcars existen 11 coches con 4 cilindros, 7 coches con 6 cilindros, y 14 vehículos con 8 cilindros, tal y como se ve a continuación.

summary(mtcars$cyl)
 4  6  8 
11  7 14

Estamos interesados en coger una muestra de coches de este conjunto de datos. Si nos da igual cómo estén representados los coches por cilindro, y sólo queremos coger aleatoriamente un número determinado, podemos emplear la función sample() tal y como mostramos en detalle en esta fantástica entrada.

Pero si estuviéramos interesados en tener el mismo número de coches seleccionados aleatoriamente por tipo de cilindro, entonces la cosa cambia. Tenemos que editar más código para tener esa condición implementada.

Dos modos de Muestrear aleatoriamente un data frame teniendo en cuenta los factores

Afortunadamente, el paquete dplyr puede ayudarnos en esta tarea de un modo extraordinario. Vamos a ver dos modos de tomar una muestra en nuestro data frame teniendo en cuenta una variable categórica:

  • Seleccionar aleatoriamente el mismo número de coches por tipo de cilindro.
  • Seleccionar aleatoriamente un porcentaje de coches determinado por tipo de cilindro.

Si tuviésemos el mismo número de coches por tipo de cilindro (cosa que no sucede), nos daría igual emplear un modo u otro de seleccionar aleatoriamente los vehículos. Pero si este número es diferente (que así es como sucede), nos puede interesar que en la muestra final esté representado un porcentaje idéntico de coches según tipo de cilindro, adaptándose al número total de cada tipo de coche en el conjunto de datos inicial.

Vamos a cargar en R el paquete mencionado:

library(dplyr)

Seleccionar aleatoriamente un número determinado de filas por factor

Para seleccionar aleatoriamente un número determinado de coches por tipo de cilindro, empleamos la función sample_n(). Esta función está integrada en una cadena conectada con el operador pipe (%>%).

Pongamos que queremos seleccionar 4 coches aleatoriamente por tipo de cilindro. Para ello, ejecutamos el siguiente código:

mtcars %>%
  group_by(cyl) %>%
  sample_n(size = 4, replace = F)
# A tibble: 12 x 11
# Groups:   cyl [3]
     mpg cyl    disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  21.5 4     120.     97  3.7   2.46  20.0     1     0     3     1
 2  24.4 4     147.     62  3.69  3.19  20       1     0     4     2
 3  32.4 4      78.7    66  4.08  2.2   19.5     1     1     4     1
 4  22.8 4     141.     95  3.92  3.15  22.9     1     0     4     2
 5  17.8 6     168.    123  3.92  3.44  18.9     1     0     4     4
 6  19.7 6     145     175  3.62  2.77  15.5     0     1     5     6
 7  21   6     160     110  3.9   2.62  16.5     0     1     4     4
 8  21.4 6     258     110  3.08  3.22  19.4     1     0     3     1
 9  10.4 8     460     215  3     5.42  17.8     0     0     3     4
10  18.7 8     360     175  3.15  3.44  17.0     0     0     3     2
11  15.8 8     351     264  4.22  3.17  14.5     0     1     5     4
12  15   8     301     335  3.54  3.57  14.6     0     1     5     8

En el código anterior ejecutamos las líneas que nos permiten seleccionar aleatoriamente coches por tipo de cilindro. Primero aparece el nombre del conjunto de datos (mtcars), ha continuación se agrupa por la variable factorial en cuestión, que es cyl (group_by(cyl)). Finalmente se ejecuta la función sample_n(), que se aplica a cada grupo de cilindro de modo independiente.

Dentro de la función sample_n() hemos indicado que seleccione 4 coches (size = 4) y que no exista repetición de los valores seleccionados (replace = F).

Como hemos podido observar en el conjunto seleccionado, existen 4 coches con 4 cilindros, 4 coches con 6 cilindros, y 4 coches con 8 cilindros, todos ellos muestreados aleatoriamente y sin repetición.

Seleccionar aleatoriamente un porcentaje determinado de filas por factor

Si lo que queremos es seleccionar aleatoriamente el 60% de los coches por tipo de cilindro, tenemos que sustituir en el código anterior la función sample_n() por sample_frac(). En esta ocasión, en el argumento size indicamos el porcentaje, que en nuestro caso sería size = 0.6.

library(dplyr)
mtcars %>%
  group_by(cyl) %>%
  sample_frac(size = .6, replace = F)
# A tibble: 19 x 11
# Groups:   cyl [3]
     mpg cyl    disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  22.8 4     108      93  3.85  2.32  18.6     1     1     4     1
 2  30.4 4      75.7    52  4.93  1.62  18.5     1     1     4     2
 3  24.4 4     147.     62  3.69  3.19  20       1     0     4     2
 4  22.8 4     141.     95  3.92  3.15  22.9     1     0     4     2
 5  33.9 4      71.1    65  4.22  1.84  19.9     1     1     4     1
 6  21.5 4     120.     97  3.7   2.46  20.0     1     0     3     1
 7  21.4 4     121     109  4.11  2.78  18.6     1     1     4     2
 8  21   6     160     110  3.9   2.62  16.5     0     1     4     4
 9  19.7 6     145     175  3.62  2.77  15.5     0     1     5     6
10  17.8 6     168.    123  3.92  3.44  18.9     1     0     4     4
11  21.4 6     258     110  3.08  3.22  19.4     1     0     3     1
12  10.4 8     472     205  2.93  5.25  18.0     0     0     3     4
13  14.3 8     360     245  3.21  3.57  15.8     0     0     3     4
14  13.3 8     350     245  3.73  3.84  15.4     0     0     3     4
15  14.7 8     440     230  3.23  5.34  17.4     0     0     3     4
16  15.5 8     318     150  2.76  3.52  16.9     0     0     3     2
17  16.4 8     276.    180  3.07  4.07  17.4     0     0     3     3
18  17.3 8     276.    180  3.07  3.73  17.6     0     0     3     3
19  10.4 8     460     215  3     5.42  17.8     0     0     3     4

Como vemos, se han seleccionado 7 coches con 4 cilindros (el 60% de los que había inicialmente con 4 cilindros), 4 coches con 6 cilindros (el 60% de los que había inicialmente con 6 cilindros), y 8 coches con 8 cilindros (el 60% de los que había inicialmente con 8 cilindros).

1 comentario en “Muestrear aleatoriamente un data frame teniendo en cuenta los factores en R”

Deja un comentario