2012-06-19 4 views
2

Je suis tout à fait nouveau à R et ont une question sur les bouclesdouble boucle en R

Dans mon vrai jeu de données il y a 7000 observations dans 80 pays avec 15 secteurs et 6 types d'organisations, mais voici un exemple simplifié.

country <- c("a","a","a","a","a","a","b","b","b","b","b","b", 
      "c","c","c","c","c","c","d","d","d","d","d","d") 
sector <- c("a","a","a","b","c","c","a","b","b","b","c","c", 
      "b","b","b","b","c","c","a","a","b","b","c","c") 
organization <-c("a","b","c","c","b","a","a","b","b","c","b","b", 
       "c","a","a","b","b","c","c","b","a","a","b","c") 
budget <-c(2,4,3,5,9,7,5,4,3,6,1,2,4,5,6,1,5,3,4,2,3,5,4,6) 
table <- data.frame(country, sector, organization, budget) 

Ce que je veux:

  1. Montant des différents types d'organisations dans un secteur spécifique dans un pays spécifique.
  2. Pourcentage du budget total dans un secteur donné aux différents types d'organisations.

Je dois d'abord faire un sous-ensemble pour sélectionner les informations seulement de pays « un » secteur « a »

smalltable <-subset(table, (country == "a") & (sector == "a")) 

puis répondre à ma première question, combien de chaque type d'organisation sont en un secteur dans un pays

smalltable$count <- table(smalltable$organization) 

alors je dois trouver le pourcentage de financement

smalltable$percentage <- smalltable$budget/sum(smalltable$budget) 

alors j'utilisé tapply

N <- tapply(smalltable$count, smalltable$organization, FUN=sum) 
financialshare <- tapply(smalltable$percentage, smalltable$organization, FUN=sum)  

et enfin combiné ceci:

total <- data.frame (smalltable$country,smalltable$sector,smalltable$organization, N,financialshare) 
total 

C'est la petite table que je requiers!

Mais j'ai besoin de ceci pour tous mes 15 secteurs et dans chacun des 80 pays, ainsi j'ai besoin d'une sorte de fonction de boucle qui exécute une boucle de tous les secteurs et répète cette boucle pour chaque pays. Je dois faire ces tables aussi condensées que possible, regroupant toutes les informations sur 1 pays (donc 15 secteurs) dans une table. Les valeurs zéro doivent également être supprimées des tables pour économiser de l'espace.

Comment dois-je procéder?

+0

oui, mais avec tous les secteurs dans un pays spécifique dans un cadre. Donc pour l'échantillon je voudrais avoir 4 dataframes spécifiques au pays à transférer à excel – user1466195

Répondre

3

Je vais vous donner une réponse data.table

library(data.table) 
my_table=data.table(country, sector, organization, budget) 
by_org=my_table[, list(count=.N, budget=sum(budget)), 
        keyby=list(country, sector, organization)] 
total_budgets=my_table[, list(total_budget=sum(budget)), 
        keyby=list(country, sector)] 
joined_table= total_budgets[by_org] 
joined_table[,percentage:=budget/total_budget] 

EDIT de Matthieu: En 1.8.1, en utilisant := par groupe, la jointure n'est pas nécessaire si c'est plus facile et plus rapide et la colonne total_budget est ajoutée à droite ce qui est un endroit plus naturel que celui où elle utilise la jointure dans v1.8.0:

DT = data.table(country, sector, organization, budget) 
ans = DT[, list(count=.N, budget=sum(budget)), 
      keyby=list(country, sector, organization)] 
ans[, total_budget:=sum(budget), by=list(country,sector)] 
ans[, percentage:=budget/total_budget] 

Résultat (en utilisant v1.8.1):

country sector organization count budget total_budget percentage 
1:  a  a   a  1  2   9 0.2222222 
2:  a  a   b  1  4   9 0.4444444 
3:  a  a   c  1  3   9 0.3333333 
4:  a  b   c  1  5   5 1.0000000 
5:  a  c   a  1  7   16 0.4375000 
6:  a  c   b  1  9   16 0.5625000 
7:  b  a   a  1  5   5 1.0000000 
8:  b  b   b  2  7   13 0.5384615 
9:  b  b   c  1  6   13 0.4615385 
10:  b  c   b  2  3   3 1.0000000 
11:  c  b   a  2  11   16 0.6875000 
12:  c  b   b  1  1   16 0.0625000 
13:  c  b   c  1  4   16 0.2500000 
14:  c  c   b  1  5   8 0.6250000 
15:  c  c   c  1  3   8 0.3750000 
16:  d  a   b  1  2   6 0.3333333 
17:  d  a   c  1  4   6 0.6666667 
18:  d  b   a  2  8   8 1.0000000 
19:  d  c   b  1  4   10 0.4000000 
20:  d  c   c  1  6   10 0.6000000 

Deux choses à noter ici: d'abord votre question est un peu vague et contradictoires quant à ce que vous voulez réellement en ce qui compte et sommes vont, mais j'espère que mon extrait est assez explicite en ce qui concerne les calculs que je fais.

Deuxièmement, il n'est pas idiomatique dans R de faire défiler un grand nombre d'observations car cela a tendance à être lent. La plupart des gens qui ont programmé R pendant un certain temps ont tendance à utiliser des opérations vectorielles, plyr, data.table, ou d'autres paquets similaires.

Mais pour être complet, la construction de la boucle se présente comme suit:

for (item in list) 
{ 
    ... 
} 

itérer sur indices communs ...

for (i in 1:length(object)) 
{ 
    ... 
} 
+0

dans le pays A et le secteur A, il n'y a qu'une seule organisation de type A, mais votre liste affiche un compte de 3 – user1466195

+0

Ah désolé, je pense que j'ai mal compris votre question alors. Je vois votre réponse au commentaire de gd07. Je vais le lire et modifier mon post en conséquence. –

+0

parfait, merci – user1466195

2
library(plyr) 
ddply(table,.(country,sector), transform,count=as.vector(table(budget)),percentage=budget/sum(budget)) 

donne

country sector organization budget count percentage 
1  a  a   a  2  1 0.2222222 
2  a  a   b  4  1 0.4444444 
3  a  a   c  3  1 0.3333333 
4  a  b   c  5  1 1.0000000 
5  a  c   b  9  1 0.5625000 
6  a  c   a  7  1 0.4375000 
7  b  a   a  5  1 1.0000000 
8  b  b   b  4  1 0.3076923 
9  b  b   b  3  1 0.2307692 
10  b  b   c  6  1 0.4615385 
11  b  c   b  1  1 0.3333333 
12  b  c   b  2  1 0.6666667 
13  c  b   c  4  1 0.2500000 
14  c  b   a  5  1 0.3125000 
15  c  b   a  6  1 0.3750000 
16  c  b   b  1  1 0.0625000 
17  c  c   b  5  1 0.6250000 
18  c  c   c  3  1 0.3750000 
19  d  a   c  4  1 0.6666667 
20  d  a   b  2  1 0.3333333 
21  d  b   a  3  1 0.3750000 
22  d  b   a  5  1 0.6250000 
23  d  c   b  4  1 0.4000000 
24  d  c   c  6  1 0.6000000 
+0

Merci déjà pour cela, mais le pourcentage ne devrait pas être par entrée, mais par type d'organisation. Ainsi, aux lignes 11-12 et 21-22, le type d'organisation «a» est affiché deux fois pour le même pays et le même secteur, ce qui ne devrait pas être le cas. Ils doivent être additionnés pour former un groupe. Ensuite, les budgets sont également additionnés et le pourcentage compare les organisations de type 'a' avec les types 'b' et 'c'. Cela permettrait également d'effectuer un comptage qui sera supérieur à un. – user1466195

1

que vous avez défini ce parfaitement pour l'utilisation plyr. Par là, je veux dire que vous avez un processus qui fonctionne (presque) sur un sous-ensemble qui retourne exactement ce que vous voulez pour ce sous-ensemble, et maintenant vous devez juste faire une boucle sur tous les sous-ensembles possibles. J'ai réécrit votre code pour le rendre plus serré et contourner les éventuels manquants organization s.

library("plyr") 

ddply(table, .(country, sector), function(smalltable) { 
    smalltable <- ddply(smalltable, .(organization), summarise, 
         count=length(budget), budget=sum(budget)) 
    smalltable$percentage <- smalltable$budget/sum(smalltable$budget) 
    smalltable 
}) 

qui donne

country sector organization count budget percentage 
1  a  a   a  1  2 0.2222222 
2  a  a   b  1  4 0.4444444 
3  a  a   c  1  3 0.3333333 
4  a  b   c  1  5 1.0000000 
5  a  c   a  1  7 0.4375000 
6  a  c   b  1  9 0.5625000 
7  b  a   a  1  5 1.0000000 
8  b  b   b  2  7 0.5384615 
9  b  b   c  1  6 0.4615385 
10  b  c   b  2  3 1.0000000 
11  c  b   a  2  11 0.6875000 
12  c  b   b  1  1 0.0625000 
13  c  b   c  1  4 0.2500000 
14  c  c   b  1  5 0.6250000 
15  c  c   c  1  3 0.3750000 
16  d  a   b  1  2 0.3333333 
17  d  a   c  1  4 0.6666667 
18  d  b   a  2  8 1.0000000 
19  d  c   b  1  4 0.4000000 
20  d  c   c  1  6 0.6000000 

Notez que table n'est pas un bon nom pour une variable car il est aussi le nom d'une fonction de base.

+0

Le 'ddply 'imbriqué dans un autre' ddply' pourrait devenir assez lent à mesure que la taille des données augmente, iiuc. –

+0

@MatthewDowle Il pourrait, mais avec 7000 enregistrements, un regroupement externe de 1200 et un regroupement interne de 6, il devrait être raisonnable. Si ce n'est pas le cas, l'approche 'data.table' est meilleure. –