2012-03-26 6 views
5

L'objectif est de créer des indicateurs pour une variable facteur/chaîne dans une trame de données. Cette trame de données a des rangées> 2mm, et en exécutant R sur Windows, je n'ai pas l'option d'utiliser plyr avec .parallel = T. Donc, je prends la route "diviser pour régner" avec plyr et reshape2.Génération d'indicateurs dans de grandes trames de données

Exécution fonte et fonte manque de mémoire, et en utilisant

ddply(idata.frame(items) , c("ID") , function(x){ 
     ( colSums(model.matrix(~ x$element - 1)) > 0 ) 
} , .progress="text")  

ou

ddply(idata.frame(items) , c("ID") , function(x){ 
      ( elements %in% x$element ) 
    } , .progress="text") 

prend un certain temps. L'approche la plus rapide est l'appel à tapply ci-dessous. Voyez-vous un moyen d'accélérer cela? L'instruction% in% s'exécute plus vite que l'appel model.matrix. Merci.

set.seed(123) 

dd <- data.frame(
    id = sample(1:5, size=10 , replace=T) , 
    prd = letters[sample(1:5, size=10 , replace=T)] 
) 

prds <- unique(dd$prd) 

tapply(dd$prd , dd$id , function(x) prds %in% x) 
+0

Je suis confus par votre exemple. Vous divisez 'dd $ prd' par' dd $ id', puis demandez quelles valeurs de 'prds' sont représentées dans chaque id - mais' prds' n'est pas trié (!) Voulez-vous 'prds <- sort (unique (dd $ prd)) '(ça me ferait beaucoup plus de sens ...)? –

+0

Tant que les indicateurs (les logiques) correspondant aux éléments disponibles dans prds ont le même ordre entre les ID, peu importe la façon dont ils sont triés. –

+0

OK. Voir mon autre question, dans ma réponse ci-dessous ... –

Répondre

4

Pour ce problème, les paquets bigmemory et bigtabulate pourraient être vos amis. Voici un exemple un peu plus ambitieux:

library(bigmemory) 
library(bigtabulate) 

set.seed(123) 

dd <- data.frame(
    id = sample(1:15, size=2e6 , replace=T), 
    prd = letters[sample(1:15, size=2e6 , replace=T)] 
) 

prds <- unique(dd$prd) 

benchmark(
bigtable(dd,c(1,2))>0, 
table(dd[,1],dd[,2])>0, 
xtabs(~id+prd,data=dd)>0, 
tapply(dd$prd , dd$id , function(x) prds %in% x) 
) 

Et les résultats de l'analyse comparative (je suis apprendre de nouvelles choses tout le temps):

          test replications elapsed relative user.self sys.self user.child sys.child 
1      bigtable(dd, c(1, 2)) > 0   100 54.401 1.000000 51.759 3.817   0   0 
2     table(dd[, 1], dd[, 2]) > 0   100 112.361 2.065422 107.526 6.614   0   0 
4 tapply(dd$prd, dd$id, function(x) prds %in% x)   100 178.308 3.277660 166.544 13.275   0   0 
3    xtabs(~id + prd, data = dd) > 0   100 229.435 4.217478 217.014 16.660   0   0 

Et qui montre bigtable gagner par une quantité considérable. Les résultats sont à peu près tous les prds sont dans tous les ID, mais voir ?bigtable pour plus de détails sur le format des résultats.

+0

Merci beaucoup. –

+0

L'exécution vient de se terminer (en utilisant bigtable) sur l'ensemble de données réel (!). –

1

Votre utilisation de la fonction %in% me semble inversée. Et si vous voulez un résultat vrai/faux pour chaque ligne de données, vous devez utiliser% en% comme une opération vectorielle ou ave. Bien que cela ne soit pas nécessaire ici, vous pourriez vouloir l'utiliser s'il y avait une fonction plus complexe qui devait être appliquée à chaque élément.

set.seed(123) 

dd <- data.frame(
    id = sample(1:5, size=10 , replace=T) , 
    prd = letters[sample(1:5, size=10 , replace=T)] 
) 

prds <- unique(dd$prd) 
target.prds <- prds[1:2] 
dd$prd.in.trgt <- with(dd, prd %in% target.prds) 
+0

Il y aura autant d'indicateurs qu'il y a de 'prds' (ou' target.prds'): 'c (1,2,3)% dans% c (1)' indiquera que 1 est dans cet enregistrement, mais ni 2 ou 3. –

+0

Vous ne pouvez pas simplement redéfinir% en% pour être quelque chose que ce n'est pas. Et un dataframe a besoin de tous les éléments pour avoir un nombre régulier d'entrées par ligne. Vous devez utiliser une structure de données qui accepte un nombre variable si "hits", ... soit une matrice logique de TRUEs et FALSEs ou une liste. –

+0

Je ne suis pas sûr de comprendre ce que vous dites. L'appel à '% in%' retournera toujours le même nombre de logiques. J'ai commencé avec 'fonction (x) unique (x $ prd)' dans l'appel 'tapply', et cela aurait produit un tableau irrégulier. –

2

Pouvez-vous dire un peu plus comment le problème serait l'échelle en termes de nombre de niveaux, le nombre de pièces d'identité, etc. (si vous gardez le nombre de niveaux fixes, puis pour les individus suffisamment la matrice d'indicateurs vous 're calculera-t-il tous TRUE/all 1 ...)? Je pensais que xtabs serait plus rapide, mais ce n'est pas un exemple de cette taille ...

library(rbenchmark) 
benchmark(
      tapply(dd$prd , dd$id , function(x) prds %in% x), 
      xtabs(~id+prd,data=dd)>0) 

    test  replications elapsed relative 
1 tapply(...)    100 0.053 1.000000 
2 xtabs(...) > 0   100 0.120 2.264151 
+0

Il y a 13,5 millions d'éléments (sur 780 000 ID, donc plusieurs éléments par ID).Il y a 83 éléments différents dans prd. Merci d'avoir attiré mon attention sur rbenchmark en passant. –

Questions connexes