pour chaque groupe, récapitulez les moyennes de toutes les variables du cadre de données (ddply? split?)

StackOverflow https://stackoverflow.com/questions/1407449

  •  05-07-2019
  •  | 
  •  

Question

Il y a une semaine, j'aurais fait cela manuellement: sous-définir le cadre de données par groupe dans de nouveaux cadres de données. Pour chaque donnée, calculer signifie pour chaque variable, puis rbind. très maladroit ...

Maintenant, j'ai appris sur split et plyr , et j'imagine qu'il doit exister un moyen plus simple d'utiliser ces outils. S'il vous plaît, ne me prouvez pas le contraire.

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))

Je joue avec les deux ddply mais je ne peux pas produire ce que je désire - c’est-à-dire un tableau comme celui-ci, pour chaque groupe

group a |2007|2009|
________|____|____|
var1    | xx | xx |
var2    | xx | xx |
etc.    | etc| ect|

peut-être d_ply et une sortie de odfweave fonctionneraient. Les entrées sont très appréciées.

p.s. Je remarque que data.frame convertit le rnorm en facteurs dans mon data.frame? comment puis-je éviter cela - I (rnorm (100) ne fonctionne pas, je dois donc convertir en numérique comme indiqué ci-dessus

Était-ce utile?

La solution

Étant donné le format souhaité pour le résultat, le package de remodelage sera plus efficace 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)

Le résultat ressemble à ceci

   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

Autres conseils

Vous pouvez le faire avec par () . Commencez par configurer certaines données:

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  

Utilisez par () :

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

Vous devez toujours reformater ceci pour votre table, mais cela vous donne l'essentiel de votre réponse en une seule ligne.

Éditer: Vous pouvez poursuivre le traitement via

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"

Vous pouvez jouer avec les dimnames encore:

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> 

Éditer: Et avec cela, nous pouvons créer un data.frame pour le résultat sans recourir à des packages externes en utilisant uniquement 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> 

MODIFIER: , j’écris ce qui suit et constate que Thierry a déjà écrit EXACTEMENT la même réponse. J'ai en quelque sorte oublié sa réponse. Donc, si vous aimez cette réponse, votez à la place. J'avance et je poste depuis que j'ai passé le temps à le taper.

Ce genre de travail me prend beaucoup plus de temps que je le souhaiterais! Voici une solution utilisant le paquet de refaçonnage de Hadley Wickham. Cet exemple ne fait pas exactement ce que vous avez demandé, car les résultats sont tous dans une grande table, pas une table pour chaque groupe.

Le problème que vous aviez avec les valeurs numériques apparaissant en tant que facteurs était dû au fait que vous utilisiez cbind et que tout devenait claqué dans une matrice de caractères. La chose intéressante est que vous n'avez pas besoin de cbind avec 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)

et cela se traduit par:

    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
...

J'ai écrit un publication d'un blog pour faire quelque chose de similaire avec plyr . Je devrais faire une deuxième partie sur la façon de faire la même chose en utilisant le paquetage reshape. Les deux plyr et reshape ont été écrits par Hadley Wickham et sont des outils fous utiles.

Cela pourrait être fait avec la fonction de base 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
        )
    )
)

Explications:

  • Conseil: lors de la génération de données aléatoires, il est utile de définir le nombre d'observations. Changer la taille de l'échantillon est plus facile,
  • premier index de ligne fractionné tapply 1: nrow (test_data) par groupes,
  • puis pour chaque groupe sur les variables
  • pour groupe fixe et variable, tapply returnig moyenne de variable par année.

Dans R 2.9.2, le résultat est:

$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

Avec mes données aléatoires, il y a un problème avec " un " groupe - seuls 2007 cas étaient présents. Si l'année est un facteur (avec les niveaux 2007 et 2009), alors les résultats peuvent sembler meilleurs (vous aurez deux lignes pour chaque année, mais il y aura probablement NA).

Le résultat est une liste, vous pouvez donc utiliser lapply pour, par exemple. convertir en table latex, table html, imprimer sur une transposition d'écran, etc.

Tout d’abord, vous n’avez pas besoin d’utiliser cbind, c’est pourquoi tout est déterminant. Cela fonctionne:

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))

Deuxièmement, la meilleure pratique consiste à utiliser ". " au lieu de " _ " dans les noms de variables. Voir le guide de style de Google (par exemple).

Enfin, vous pouvez utiliser le package Rigroup. c'est très rapide. Combinez la fonction igroupMeans () avec apply et définissez l'index i = as.factor (paste (groupe_test_données, groupe_données_test $, année =, ")) . J'essaierai d'inclure un exemple plus tard.

EDIT 6/9/2017

Le package Rigroup a été supprimé de CRAN. Voir ceci

Commencez par faire un agrégat simple pour le résumer.

df <- aggregate(cbind(var0, var1, var2, var3, var4) ~ year + group, test_data, mean)

Cela donne un data.frame comme ça ...

   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
...

Cela, en soi, est assez proche de ce que vous vouliez. Vous pouvez simplement le séparer par groupe maintenant.

l <- split(df, df$group)

OK, donc ce n’est pas tout à fait cela, mais nous pouvons affiner le résultat si vous le souhaitez vraiment.

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
...

Cela n’a pas l’ensemble de la mise en forme de votre tableau, mais il est organisé exactement comme vous le décrivez et est très proche. Cette dernière étape, vous pourriez très bien comment vous aimez.

C’est la seule réponse ici qui corresponde à l’organisation demandée, et c’est le moyen le plus rapide de le faire dans R. BTW, je ne me ferais pas la peine de faire cette dernière étape et d’en rester à la première sortie de l’agrégat. . ou peut-être la scission.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top