para cada grupo, resuma las medias para todas las variables en el marco de datos (ddply? split?)
Pregunta
Hace una semana habría hecho esto manualmente: subordinar el marco de datos por grupo a los nuevos marcos de datos. Para cada medio de cálculo de la estructura de datos para cada variable, entonces rbind. muy torpe ...
Ahora he aprendido sobre split
y plyr
, y creo que debe haber una forma más fácil de usar estas herramientas. Por favor, no me demuestres que estoy equivocado.
test_data <- data.frame(cbind(
var0 = rnorm(100),
var1 = rnorm(100,1),
var2 = rnorm(100,2),
var3 = rnorm(100,3),
var4 = rnorm(100,4),
group = sample(letters[1:10],100,replace=T),
year = sample(c(2007,2009),100, replace=T)))
test_data$var1 <- as.numeric(as.character(test_data$var1))
test_data$var2 <- as.numeric(as.character(test_data$var2))
test_data$var3 <- as.numeric(as.character(test_data$var3))
test_data$var4 <- as.numeric(as.character(test_data$var4))
Estoy jugando con ddply
pero no puedo producir lo que deseo, es decir, una tabla como esta, para cada grupo
group a |2007|2009|
________|____|____|
var1 | xx | xx |
var2 | xx | xx |
etc. | etc| ect|
quizás d_ply
y alguna salida de odfweave
funcionaría para. Los aportes son muy apreciados.
p.s. Me doy cuenta de que data.frame convierte el rnorm a factores en mi data.frame? ¿Cómo puedo evitar esto? Yo (rnorm (100) no funciona, así que tengo que convertir a valores numéricos como se hizo anteriormente
Solución
Dado el formato que desea para el resultado, el paquete de remodelación será más eficiente que plyr.
test_data <- data.frame(
var0 = rnorm(100),
var1 = rnorm(100,1),
var2 = rnorm(100,2),
var3 = rnorm(100,3),
var4 = rnorm(100,4),
group = sample(letters[1:10],100,replace=T),
year = sample(c(2007,2009),100, replace=T))
library(reshape)
Molten <- melt(test_data, id.vars = c("group", "year"))
cast(group + variable ~ year, data = Molten, fun = mean)
El resultado se ve así
group variable 2007 2009
1 a var0 0.003767891 0.340989068
2 a var1 2.009026385 1.162786943
3 a var2 1.861061882 2.676524736
4 a var3 2.998011426 3.311250399
5 a var4 3.979255971 4.165715967
6 b var0 -0.112883844 -0.179762343
7 b var1 1.342447279 1.199554144
8 b var2 2.486088196 1.767431740
9 b var3 3.261451449 2.934903824
10 b var4 3.489147597 3.076779626
11 c var0 0.493591055 -0.113469315
12 c var1 0.157424796 -0.186590644
13 c var2 2.366594176 2.458204041
14 c var3 3.485808031 2.817153628
15 c var4 3.681576886 3.057915666
16 d var0 0.360188789 1.205875725
17 d var1 1.271541181 0.898973536
18 d var2 1.824468264 1.944708165
19 d var3 2.323315162 3.550719308
20 d var4 3.852223640 4.647498956
21 e var0 -0.556751465 0.273865769
22 e var1 1.173899189 0.719520372
23 e var2 1.935402724 2.046313047
24 e var3 3.318669590 2.871462470
25 e var4 4.374478734 4.522511874
26 f var0 -0.258956555 -0.007729091
27 f var1 1.424479454 1.175242755
28 f var2 1.797948551 2.411030282
29 f var3 3.083169793 3.324584667
30 f var4 4.160641429 3.546527820
31 g var0 0.189038036 -0.683028110
32 g var1 0.429915866 0.827761101
33 g var2 1.839982321 1.513104866
34 g var3 3.106414330 2.755975622
35 g var4 4.599340239 3.691478466
36 h var0 0.015557352 -0.707257185
37 h var1 0.933199148 1.037655156
38 h var2 1.927442457 2.521369108
39 h var3 3.246734239 3.703213646
40 h var4 4.242387776 4.407960355
41 i var0 0.885226638 -0.288221276
42 i var1 1.216012653 1.502514588
43 i var2 2.302815441 1.905731471
44 i var3 2.026631277 2.836508446
45 i var4 4.800676814 4.772964668
46 j var0 -0.435661855 0.192703997
47 j var1 0.836814185 0.394505861
48 j var2 1.663523873 2.377640369
49 j var3 3.489536343 3.457597835
50 j var4 4.146020948 4.281599816
Otros consejos
Puedes hacer esto con por ()
. Primero configura algunos datos:
R> set.seed(42)
R> testdf <- data.frame(var1=rnorm(100), var2=rnorm(100,2), var3=rnorm(100,3),
group=as.factor(sample(letters[1:10],100,replace=T)),
year=as.factor(sample(c(2007,2009),100,replace=T)))
R> summary(testdf)
var1 var2 var3 group year
Min. :-2.9931 Min. :-0.0247 Min. :0.30 e :15 2007:50
1st Qu.:-0.6167 1st Qu.: 1.4085 1st Qu.:2.29 c :14 2009:50
Median : 0.0898 Median : 1.9307 Median :2.98 f :12
Mean : 0.0325 Mean : 1.9125 Mean :2.99 h :12
3rd Qu.: 0.6616 3rd Qu.: 2.4618 3rd Qu.:3.65 d :11
Max. : 2.2866 Max. : 4.7019 Max. :5.46 b :10
(Other):26
Utilice por ()
:
R> by(testdf[,1:3], testdf$year, mean)
testdf$year: 2007
var1 var2 var3
0.04681 1.77638 3.00122
---------------------------------------------------------------------
testdf$year: 2009
var1 var2 var3
0.01822 2.04865 2.97805
R> by(testdf[,1:3], list(testdf$group, testdf$year), mean)
## longer answer by group and year suppressed
Aún necesita reformatear esto para su tabla, pero le da la esencia de su respuesta en una línea.
Editar: Se puede obtener un procesamiento adicional a través de
R> foo <- by(testdf[,1:3], list(testdf$group, testdf$year), mean)
R> do.call(rbind, foo)
var1 var2 var3
[1,] 0.62352 0.2549 3.157
[2,] 0.08867 1.8313 3.607
[3,] -0.69093 2.5431 3.094
[4,] 0.02792 2.8068 3.181
[5,] -0.26423 1.3269 2.781
[6,] 0.07119 1.9453 3.284
[7,] -0.10438 2.1181 3.783
[8,] 0.21147 1.6345 2.470
[9,] 1.17986 1.6518 2.362
[10,] -0.42708 1.5683 3.144
[11,] -0.82681 1.9528 2.740
[12,] -0.27191 1.8333 3.090
[13,] 0.15854 2.2830 2.949
[14,] 0.16438 2.2455 3.100
[15,] 0.07489 2.1798 2.451
[16,] -0.03479 1.6800 3.099
[17,] 0.48082 1.8883 2.569
[18,] 0.32381 2.4015 3.332
[19,] -0.47319 1.5016 2.903
[20,] 0.11743 2.2645 3.452
R> do.call(rbind, dimnames(foo))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
[2,] "2007" "2009" "2007" "2009" "2007" "2009" "2007" "2009" "2007" "2009"
Puedes jugar con los dimnames
un poco más:
R> expand.grid(dimnames(foo))
Var1 Var2
1 a 2007
2 b 2007
3 c 2007
4 d 2007
5 e 2007
6 f 2007
7 g 2007
8 h 2007
9 i 2007
10 j 2007
11 a 2009
12 b 2009
13 c 2009
14 d 2009
15 e 2009
16 f 2009
17 g 2009
18 h 2009
19 i 2009
20 j 2009
R>
Editar: Y con eso, podemos crear un data.frame
para el resultado sin tener que recurrir a paquetes externos utilizando solo la base R:
R> data.frame(cbind(expand.grid(dimnames(foo)), do.call(rbind, foo)))
Var1 Var2 var1 var2 var3
1 a 2007 0.62352 0.2549 3.157
2 b 2007 0.08867 1.8313 3.607
3 c 2007 -0.69093 2.5431 3.094
4 d 2007 0.02792 2.8068 3.181
5 e 2007 -0.26423 1.3269 2.781
6 f 2007 0.07119 1.9453 3.284
7 g 2007 -0.10438 2.1181 3.783
8 h 2007 0.21147 1.6345 2.470
9 i 2007 1.17986 1.6518 2.362
10 j 2007 -0.42708 1.5683 3.144
11 a 2009 -0.82681 1.9528 2.740
12 b 2009 -0.27191 1.8333 3.090
13 c 2009 0.15854 2.2830 2.949
14 d 2009 0.16438 2.2455 3.100
15 e 2009 0.07489 2.1798 2.451
16 f 2009 -0.03479 1.6800 3.099
17 g 2009 0.48082 1.8883 2.569
18 h 2009 0.32381 2.4015 3.332
19 i 2009 -0.47319 1.5016 2.903
20 j 2009 0.11743 2.2645 3.452
R>
EDITAR: escribí lo siguiente y luego me di cuenta de que Thierry ya había escrito casi EXACTAMENTE la misma respuesta. De alguna manera pasé por alto su respuesta. Así que si te gusta esta respuesta, vota en su lugar. Voy a seguir adelante y publicando desde que pasé el tiempo escribiéndolo.
¡Este tipo de cosas consume mucho más tiempo de lo que me gustaría! Aquí hay una solución que utiliza el paquete de reformar de Hadley Wickham. Este ejemplo no hace exactamente lo que pidió porque los resultados están todos en una tabla grande, no en una tabla para cada grupo.
El problema que estaba teniendo con los valores numéricos que aparecen como factores se debía a que estaba usando cbind y todo se estaba convirtiendo en una matriz de caracteres de tipo. Lo bueno es que no necesitas cbind con data.frame.
test_data <- data.frame(
var0 = rnorm(100),
var1 = rnorm(100,1),
var2 = rnorm(100,2),
var3 = rnorm(100,3),
var4 = rnorm(100,4),
group = sample(letters[1:10],100,replace=T),
year = sample(c(2007,2009),100, replace=T))
library(reshape)
molten_data <- melt(test_data, id=c("group", "year")))
cast(molten_data, group + variable ~ year, mean)
y esto da como resultado lo siguiente:
group variable 2007 2009
1 a var0 -0.92040686 -0.154746420
2 a var1 1.06603832 0.559765035
3 a var2 2.34476321 2.206521587
4 a var3 3.01652065 3.256580166
5 a var4 3.75256699 3.907777127
6 b var0 -0.53207427 -0.149144766
7 b var1 0.75677714 0.879387608
8 b var2 2.41739521 1.224854891
9 b var3 2.63877431 2.436837719
10 b var4 3.69640598 4.439047363
...
Escribí una publicación de blog recientemente sobre hacer algo similar con plyr . Debería hacer una parte 2 sobre cómo hacer lo mismo con el paquete remodelar. Hadley Wickham ha escrito tanto plyr como remhape y son herramientas útiles de locura.
Se podría hacer con la función básica de R:
n <- 100
test_data <- data.frame(
var0 = rnorm(n),
var1 = rnorm(n,1),
var2 = rnorm(n,2),
var3 = rnorm(n,3),
var4 = rnorm(n,4),
group = sample(letters[1:10],n,replace=TRUE),
year = sample(c(2007,2009),n, replace=TRUE)
)
tapply(
seq_len(nrow(test_data)),
test_data$group,
function(ind) sapply(
c("var0","var1","var2","var3","var4"),
function(x_name) tapply(
test_data[[x_name]][ind],
test_data$year[ind],
mean
)
)
)
Explicaciones:
- consejo: cuando generar datos aleatorios es útil para definir el número de observaciones. Cambiar el tamaño de la muestra es más fácil de esa manera,
- primer índice de fila dividida de tapply 1: nrow (test_data) por grupos,
- luego para cada grupo aplicar sobre las variables
- para el grupo fijo y la variable, haga una media de retorno de tapply simple de la variable por año.
En R 2.9.2 el resultado es:
$a
var0.2007 var1.2007 var2.2007 var3.2007 var4.2007
-0.3123034 0.8759787 1.9832617 2.7063034 4.1322758
$b
var0 var1 var2 var3 var4
2007 0.81366885 0.4189896 2.331256 3.073276 4.164639
2009 -0.08916257 1.5442126 3.008014 3.215019 4.398279
$c
var0 var1 var2 var3 var4
2007 0.4232098 1.3657369 1.386627 2.808511 3.878809
2009 0.3245751 0.6672073 1.797886 1.752568 3.632318
$d
var0 var1 var2 var3 var4
2007 -0.1335138 0.5925237 2.303543 3.293281 3.234386
2009 0.9547751 2.2111581 2.678878 2.845234 3.300512
$e
var0 var1 var2 var3 var4
2007 -0.5958653 1.3535658 1.886918 3.036121 4.120889
2009 0.1372080 0.7215648 2.298064 3.186617 3.551147
$f
var0 var1 var2 var3 var4
2007 -0.3401813 0.7883120 1.949329 2.811438 4.194481
2009 0.3012627 0.2702647 3.332480 3.480494 2.963951
$g
var0 var1 var2 var3 var4
2007 1.225245 -0.3289711 0.7599302 2.903581 4.200023
2009 0.273858 0.2445733 1.7690299 2.620026 4.182050
$h
var0 var1 var2 var3 var4
2007 -1.0126650 1.554403 2.220979 3.713874 3.924151
2009 -0.6187407 1.504297 1.321930 2.796882 4.179695
$i
var0 var1 var2 var3 var4
2007 0.01697314 1.318965 1.794635 2.709925 2.899440
2009 -0.75790995 1.033483 2.363052 2.422679 3.863526
$j
var0 var1 var2 var3 var4
2007 -0.7440600 1.6466291 2.020379 3.242770 3.727347
2009 -0.2842126 0.5450029 1.669964 2.747455 4.179531
Con mis datos aleatorios hay un problema con " a " grupo - solo 2007 casos estuvieron presentes. Si el año será un factor (con los niveles 2007 y 2009), los resultados pueden verse mejor (tendrá dos filas por cada año, pero es probable que haya NA).
El resultado es la lista, por lo que puede usar lapply para, por ejemplo, convertir a tabla de látex, tabla html, imprimir en transposición de pantalla, etc.
En primer lugar, no necesitas usar cbind, y es por eso que todo es un factor. Esto funciona:
test_data <- data.frame(
var0 = rnorm(100),
var1 = rnorm(100,1),
var2 = rnorm(100,2),
var3 = rnorm(100,3),
var4 = rnorm(100,4),
group = sample(letters[1:10],100,replace=T),
year = sample(c(2007,2009),100, replace=T))
En segundo lugar, la mejor práctica es utilizar ". " en lugar de " _ " en nombres de variables. Consulte la guía de estilo de Google (por ejemplo).
Finalmente, puedes usar el paquete Rigroup; Es muy rápido. Combine la función igroupMeans () con apply y configure el índice i = as.factor (paste (test_data $ group, test_data $ year, sep = " "))
. Intentaré incluir un ejemplo de esto más adelante.
EDITAR 9/6/2017
El paquete de Rigroup fue eliminado de CRAN. Consulte esto
Primero haga un agregado simple para resumirlo.
df <- aggregate(cbind(var0, var1, var2, var3, var4) ~ year + group, test_data, mean)
Eso hace que un data.frame como este ...
year group var0 var1 var2 var3 var4
1 2007 a 42.25000 0.2031277 2.145394 2.801812 3.571999
2 2009 a 30.50000 1.2033653 1.475158 3.618023 4.127601
3 2007 b 52.60000 1.4564604 2.224850 3.053322 4.339109
...
Eso, por sí mismo, es bastante cercano a lo que querías. Podrías dividirlo ahora por grupo.
l <- split(df, df$group)
Está bien, eso no es todo, pero podemos refinar la salida si realmente lo desea.
lapply(l, function(x) {d <- t(x[,3:7]); colnames(d) <- x[,2]; d})
$a
2007 2009
var0 42.2500000 30.500000
var1 0.2031277 1.203365
var2 2.1453939 1.475158
...
Eso no tiene todo el formato de su tabla, pero está organizado exactamente como lo describe y está muy cerca. En este último paso, podrías mejorar cómo te gusta.
Esta es la única respuesta aquí que coincide con la organización solicitada, y es la forma más rápida de hacerlo en R. Por cierto, no me molestaría en dar ese último paso y me quedaría con la primera salida del agregado. O tal vez la división.