studio - operaciones con data frame en r
muestra filas de subgrupos de dataframe con dplyr (3)
¡Buena pregunta! No puedo ver ninguna manera fácil de hacerlo con la sintaxis documentada para dplyr
pero ¿qué tal esto para una solución?
sampleGroup<-function(df,x=1){
df[
unlist(lapply(attr((df),"indices"),function(r)sample(r,min(length(r),x))))
,]
}
sampleGroup(iris %.% group_by(Species),3)
#Source: local data frame [9 x 5]
#Groups: Species
#
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#39 4.4 3.0 1.3 0.2 setosa
#16 5.7 4.4 1.5 0.4 setosa
#25 4.8 3.4 1.9 0.2 setosa
#51 7.0 3.2 4.7 1.4 versicolor
#62 5.9 3.0 4.2 1.5 versicolor
#59 6.6 2.9 4.6 1.3 versicolor
#148 6.5 3.0 5.2 2.0 virginica
#103 7.1 3.0 5.9 2.1 virginica
#120 6.0 2.2 5.0 1.5 virginica
EDITAR - COMPARACIÓN DE RENDIMIENTO
Aquí hay una prueba para usar data.table (nativa y con una llamada de función según el ejemplo) para 1m de filas, 26 grupos.
Native data.table es aproximadamente 2x tan rápido como la solución dplyr y también llamada data.table con llamada. Así que probablemente dplyr / data.table tenga el mismo rendimiento.
¡Esperemos que los chicos de dplyr nos den una sintaxis nativa para el muestreo pronto! (o incluso mejor, tal vez ya esté allí)
sampleGroup.dt<-function(df,size) {
df[sample(nrow(df),size=size),]
}
testdata<-data.frame(group=sample(letters,10e5,T),runif(10e5))
dti<-data.table(testdata)
# using the dplyr workaround with external function call
system.time(sampleGroup(testdata %.% group_by(group),10))
#user system elapsed
#0.07 0.00 0.06
#using native data.table
system.time(dti[dti[,list(val=sample(.I,10)),by="group"]$val])
#user system elapsed
#0.04 0.00 0.03
#using data.table with external function call
system.time(dti[, sampleGroup.dt(dti, 10), by=group])
#user system elapsed
#0.06 0.02 0.08
Si quiero seleccionar aleatoriamente algunas muestras de diferentes grupos, uso el paquete plyr y el código a continuación
require(plyr)
sampleGroup<-function(df,size) {
df[sample(nrow(df),size=size),]
}
iris.sample<-ddply(iris,.(Species),function(df) sampleGroup(df,10))
Aquí se seleccionan 10 muestras de cada especie.
Algunos de mis marcos de datos son muy grandes y mi pregunta es ¿puedo usar la misma función sampleGroup con el paquete dplyr? ¿O hay otra manera de hacer lo mismo en dplyr?
EDITAR
La versión 0.2 del paquete dplyr introdujo dos nuevas funciones para seleccionar filas aleatorias de una tabla sample_n y sample_frac
Esto es fácil de hacer con data.table y es útil para una mesa grande.
NOTA: Como lo mencionó Troy, hay una manera más eficiente de hacerlo usando data.table, pero quería respetar la función y el formato de muestra OP en la respuesta.
require(data.table)
DT <- data.table(x = rnorm(10e6, 100, 50), y = letters)
sampleGroup<-function(df,size) {
df[sample(nrow(df),size=size),]
}
result <- DT[, sampleGroup(.SD, 10), by=y]
print(result)
# y x y
# 1: a 30.11659 m
# 2: a 57.99974 h
# 3: a 58.13634 o
# 4: a 87.28466 x
# 5: a 85.54986 j
# ---
# 256: z 149.85817 d
# 257: z 160.24293 e
# 258: z 26.63071 j
# 259: z 17.00083 t
# 260: z 130.27796 f
system.time(DT[, sampleGroup(.SD, 10), by=y])
# user system elapsed
# 0.66 0.02 0.69
Using the iris dataset:
iris <- data.table(iris)
iris[,sampleGroup(.SD, 10), by=Species]
Sí, puede utilizar dplyr con elegancia mediante la función do (). Aquí hay un ejemplo:
mtcars %>%
group_by(cyl) %>%
do(sample_n(.,2))
y los resultados son así
Source: local data frame [6 x 11]
Groups: cyl
mpg cyl disp hp drat wt qsec vs am gear carb
1 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
3 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
4 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
5 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
6 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
Actualizar:
La función do
ya no es necesaria para sample_n
en las versiones más nuevas de dplyr. Código actual para tomar una muestra aleatoria de dos filas por grupo:
mtcars %>%
group_by(cyl) %>%
sample_n(2)