Muestra de filas aleatorias en el marco de datos

333

Estoy luchando por encontrar la función adecuada que devuelva un número específico de filas recogidas al azar sin reemplazo de un marco de datos en lenguaje R? ¿Puede alguien ayudarme?

nikhil
fuente

Respuestas:

445

Primero haga algunos datos:

> df = data.frame(matrix(rnorm(20), nrow=10))
> df
           X1         X2
1   0.7091409 -1.4061361
2  -1.1334614 -0.1973846
3   2.3343391 -0.4385071
4  -0.9040278 -0.6593677
5   0.4180331 -1.2592415
6   0.7572246 -0.5463655
7  -0.8996483  0.4231117
8  -1.0356774 -0.1640883
9  -0.3983045  0.7157506
10 -0.9060305  2.3234110

Luego seleccione algunas filas al azar:

> df[sample(nrow(df), 3), ]
           X1         X2
9  -0.3983045  0.7157506
2  -1.1334614 -0.1973846
10 -0.9060305  2.3234110
John Colby
fuente
44
@nikhil Vea aquí y aquí para empezar. También puede escribir ?sampleen la consola R para leer sobre esa función.
joran
10
¿Alguien puede explicar por qué la muestra (df, 3) no funciona? ¿Por qué necesita df [sample (nrow (df), 3),]?
stackoverflowuser2010
55
@ stackoverflowuser2010, puede escribir? sample y ver que el primer argumento en la función de muestra debe ser un vector o un entero positivo. No creo que un data.frame funcione como un vector en este caso.
David Braun
99
Recuerde configurar su semilla (por ejemplo set.seed(42)) cada vez que quiera reproducir esa muestra específica.
CousinCocaine
2
sample.intsería un poco más rápido, creo:library(microbenchmark);microbenchmark( sample( 10000, 100 ), sample.int( 10000, 100 ), times = 10000 )
Ari B. Friedman
199

La respuesta que da John Colby es la respuesta correcta. Sin embargo, si usted es un dplyrusuario, también existe la respuesta sample_n:

sample_n(df, 10)

Muestra aleatoriamente 10 filas del marco de datos. Llama sample.int, por lo que realmente es la misma respuesta con menos tipeo (y simplifica el uso en el contexto de magrittr ya que el marco de datos es el primer argumento).

kasterma
fuente
33

Escribe uno! Ajustar la respuesta de JC me da:

randomRows = function(df,n){
   return(df[sample(nrow(df),n),])
}

Ahora hazlo mejor comprobando primero si n <= nrow (df) y deteniéndote con un error.

Hombre espacial
fuente
33

El data.tablepaquete proporciona la función DT[sample(.N, M)], muestreando M filas al azar de la tabla de datos DT.

library(data.table)
set.seed(10)

mtcars <- data.table(mtcars)
mtcars[sample(.N, 6)]

    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1: 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
2: 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
3: 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
4: 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
5: 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
6: 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
Gented
fuente
10

Solo por completo:

dplyr también ofrece dibujar una proporción o fracción de la muestra por

df %>% sample_frac(0.33)

Esto es muy conveniente, por ejemplo, en el aprendizaje automático cuando tiene que hacer una cierta proporción dividida como 80%: 20%

Frijol ágil
fuente
9

EDITAR : Esta respuesta ahora está desactualizada, vea la versión actualizada .

En mi paquete R he mejorado samplepara que ahora se comporte como se esperaba también para los marcos de datos:

library(devtools); install_github('kimisc', 'krlmlr')

library(kimisc)
example(sample.data.frame)

smpl..> set.seed(42)

smpl..> sample(data.frame(a=c(1,2,3), b=c(4,5,6),
                           row.names=c('a', 'b', 'c')), 10, replace=TRUE)
    a b
c   3 6
c.1 3 6
a   1 4
c.2 3 6
b   2 5
b.1 2 5
c.3 3 6
a.1 1 4
b.2 2 5
c.4 3 6

Esto es logra haciendo sampleun método genérico S3 y proporcionando la funcionalidad necesaria (trivial) en una función. Una llamada para setMethodarreglar todo. Todavía se puede acceder a la implementación original a través de base::sample.

krlmlr
fuente
1
¿Qué tiene de inesperado su tratamiento de los marcos de datos?
un ben diferente
2
@adifferentben: cuando llamo sample.default(df, ...)a un marco de datos df, toma muestras de las columnas del marco de datos, ya que un marco de datos se implementa como una lista de vectores de la misma longitud.
krlmlr
¿Su paquete aún está disponible? Corrí install_github('kimisc', 'krlmlr')y conseguí Error: Does not appear to be an R package (no DESCRIPTION). ¿Alguna forma de evitar eso?
terdon
1
@JorisMeys: De acuerdo, excepto por la parte "como se esperaba". El hecho de que un marco de datos se implemente como una lista internamente, no significa que deba comportarse como uno solo. El [operador para marcos de datos es un contraejemplo. Además, por favor dígame: ¿Alguna vez, solo una vez, usó samplemuestras de columnas de un marco de datos?
krlmlr
1
@krlmlr El [operador no es un contraejemplo: iris[2]funciona como una lista, como lo hace iris[[2]]. O iris$Species, lapply(iris, mean)... Los marcos de datos son listas. Así que espero que se comporten como ellos. Y sí, en realidad he usado sample (myDataframe). En un conjunto de datos donde cada variable contiene datos de expresión de un solo gen. Su método específico ayuda a los usuarios novatos, pero también cambia efectivamente la forma en que se sample()comporta. Tenga en cuenta que uso "como se esperaba" desde la vista de un programador. Lo cual es diferente de la intuición general. Hay muchas cosas en R que no son compatibles con la intuición general ...;)
Joris Meys
8

Respuesta desactualizada. Por favor, use dplyr::sample_frac()o en su dplyr::sample_n()lugar.

En mi paquete R hay una función sample.rowssolo para este propósito:

install.packages('kimisc')

library(kimisc)
example(sample.rows)

smpl..> set.seed(42)

smpl..> sample.rows(data.frame(a=c(1,2,3), b=c(4,5,6),
                               row.names=c('a', 'b', 'c')), 10, replace=TRUE)
    a b
c   3 6
c.1 3 6
a   1 4
c.2 3 6
b   2 5
b.1 2 5
c.3 3 6
a.1 1 4
b.2 2 5
c.4 3 6

Mejorar sampleal convertirlo en una función genérica S3 fue una mala idea, según los comentarios de Joris Meys a una respuesta anterior .

krlmlr
fuente
5

Seleccione una muestra aleatoria de un tipo tibble en R:

library("tibble")    
a <- your_tibble[sample(1:nrow(your_tibble), 150),]

nrow toma un tibble y devuelve el número de filas. El primer parámetro pasado a samplees un rango de 1 al final de su tibble. El segundo parámetro pasado a la muestra, 150, es cuántos muestreos aleatorios desea. El corte de corchetes especifica las filas de los índices devueltos. La variable 'a' obtiene el valor del muestreo aleatorio.

Eric Leschinski
fuente
4

Podrías hacer esto:

library(dplyr)

cols <- paste0("a", 1:10)
tab <- matrix(1:1000, nrow = 100) %>% as.tibble() %>% set_names(cols)
tab
# A tibble: 100 x 10
      a1    a2    a3    a4    a5    a6    a7    a8    a9   a10
   <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
 1     1   101   201   301   401   501   601   701   801   901
 2     2   102   202   302   402   502   602   702   802   902
 3     3   103   203   303   403   503   603   703   803   903
 4     4   104   204   304   404   504   604   704   804   904
 5     5   105   205   305   405   505   605   705   805   905
 6     6   106   206   306   406   506   606   706   806   906
 7     7   107   207   307   407   507   607   707   807   907
 8     8   108   208   308   408   508   608   708   808   908
 9     9   109   209   309   409   509   609   709   809   909
10    10   110   210   310   410   510   610   710   810   910
# ... with 90 more rows

Arriba acabo de hacer un marco de datos con 10 columnas y 100 filas, ¿de acuerdo?

Ahora puede probarlo con sample_n:

sample_n(tab, size = 800, replace = T)
# A tibble: 800 x 10
      a1    a2    a3    a4    a5    a6    a7    a8    a9   a10
   <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
 1    53   153   253   353   453   553   653   753   853   953
 2    14   114   214   314   414   514   614   714   814   914
 3    10   110   210   310   410   510   610   710   810   910
 4    70   170   270   370   470   570   670   770   870   970
 5    36   136   236   336   436   536   636   736   836   936
 6    77   177   277   377   477   577   677   777   877   977
 7    13   113   213   313   413   513   613   713   813   913
 8    58   158   258   358   458   558   658   758   858   958
 9    29   129   229   329   429   529   629   729   829   929
10     3   103   203   303   403   503   603   703   803   903
# ... with 790 more rows
igorkf
fuente
1

Soy nuevo en R, pero estaba usando este método fácil que funciona para mí:

sample_of_diamonds <- diamonds[sample(nrow(diamonds),100),]

PD: Siéntete libre de notar si tiene algún inconveniente en el que no estoy pensando.

Leopoldo Sanczyk
fuente
0

Podrías hacer esto:

sample_data = data[sample(nrow(data), sample_size, replace = FALSE), ]
Mohammad
fuente