2009-11-23 2 views
8

J'utilise actuellement cast sur une table fondue pour calculer le total de chaque valeur à la combinaison des variables ID ID1 (noms de lignes) et ID2 (en-têtes de colonnes), ainsi que des totaux généraux pour chaque ligne en utilisant margins="grand_col".Calcul du pourcentage du total des lignes avec plyr

c <- cast(m, ID1 ~ ID2, sum, margins="grand_col")

ID1  ID2a ID2b  ID2c  ID2d ID2e (all) 
1 ID1a 6459695 885473 648019 453613 1777308 10224108 
2 ID1b 7263529 1411355 587785 612730 2458672 12334071 
3 ID1c 7740364 1253524 682977 886897 3559283 14123045 

Jusqu'à présent, si R-like.

Ensuite, je divise chaque cellule par son total de ligne pour obtenir un pourcentage du total.

c[,2:6]<-c[,2:6]/c[,7] 

Cela ressemble kludgy. Y at-il quelque chose que je devrais faire dans cast ou peut-être dans plyr pour gérer le pourcentage de calcul de marge dans la première commande?

Merci, Matt

+0

Je ne pas de grandes idées ici. J'espère que quelqu'un d'autre le fait! – hadley

Répondre

4

En supposant que votre table source ressemble à ceci:

dfm <- structure(list(ID1 = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 
2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), .Label = c("ID1a", "ID1b", "ID1c" 
), class = "factor"), ID2 = structure(c(1L, 1L, 1L, 2L, 
2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L), .Label = c("ID2a", 
"ID2b", "ID2c", "ID2d", "ID2e"), class = "factor"), value = c(6459695L, 
7263529L, 7740364L, 885473L, 1411355L, 1253524L, 648019L, 587785L, 
682977L, 453613L, 612730L, 886897L, 1777308L, 2458672L, 3559283L 
)), .Names = c("ID1", "ID2", "value"), row.names = c(NA, 
-15L), class = "data.frame") 

> head(dfm) 
    ID1 ID2 value 
1 ID1a ID2a 6459695 
2 ID1b ID2a 7263529 
3 ID1c ID2a 7740364 
4 ID1a ID2b 885473 
5 ID1b ID2b 1411355 
6 ID1c ID2b 1253524 

En utilisant ddply d'abord pour calculer les pourcentages et cast pour présenter les données dans le format requis

library(reshape) 
library(plyr) 

df1 <- ddply(dfm, .(ID1), summarise, ID2 = ID2, pct = value/sum(value)) 
dfc <- cast(df1, ID1 ~ ID2) 

dfc 
    ID1  ID2a  ID2b  ID2c  ID2d  ID2e 
1 ID1a 0.6318101 0.08660638 0.06338147 0.04436700 0.1738350 
2 ID1b 0.5888996 0.11442735 0.04765539 0.04967784 0.1993399 
3 ID1c 0.5480662 0.08875735 0.04835905 0.06279786 0.2520195 

Par rapport à votre exemple, il manque les totaux des lignes, ceux-ci doivent être ajoutés arately.

Vous ne savez pas si cette solution est plus élégante que celle que vous avez actuellement.

+0

C'est une meilleure solution si seulement parce que les index de colonne n'ont pas besoin d'être codés en dur, et je peux vivre sans les totaux des colonnes. Vérifié comme la réponse. En attendant, que se passe-t-il dans l'argument ID2 = ID2 dans votre commande ddply? –

+0

L'argument summary de ddply crée une nouvelle trame de données et si ID2 n'a pas été spécifié, la nouvelle trame de données ne comportera que deux colonnes: ID1 et pct. – learnr

4

Voici un monodisque utilisant tapply et prop.table. Il ne faut pas compter sur tous les paquets auxilliaires:

prop.table(tapply(dfm$value, dfm[1:2], sum), 1) 

donnant:

 ID2 
ID1   ID2a  ID2b  ID2c  ID2d  ID2e 
    ID1a 0.6318101 0.08660638 0.06338147 0.04436700 0.1738350 
    ID1b 0.5888996 0.11442735 0.04765539 0.04967784 0.1993399 
    ID1c 0.5480662 0.08875735 0.04835905 0.06279786 0.2520195 

ou ce qui est encore plus courte:

prop.table(xtabs(value ~., dfm), 1)