10
votes

fusionner une donnée.table avec elle-même après une recherche de référence

Si j'ai le data.Table.tables dt et voisins : xxx

n est une table de recherche. Chaque fois que ok == 0 , je veux rechercher le Y1 dans N et utiliser cette valeur pour x et le IDX . A titre d'exemple, rangée 4 de DT: xxx

y1 de n pour d est E : xxx

et IDX pour la ligne 4 est 1. Donc j'utiliserais: xxx

je veux que ma sortie soit un data.table comme dt [ok == 0] avec tout le x les valeurs remplacées par leur n ['y1' '] x valeur: xxx

Je peux penser à quelques façons de Faire cela avec la base R ou avec plyr ... et peut-être que c'est tard vendredi ... mais quelles que soient les séquences de fusion que cela nécessiterait dans data.table est au-delà moi!


0 commentaires

3 Réponses :


4
votes
crdt(1e6)
system.time(fun(DT,n)[J(0)])
       User      System     elapsed 
      4.213       0.162       4.374 

crdt(1e7)
system.time(fun(DT,n)[J(0)])
       User      System     elapsed 
    195.685       3.949     199.592 

1 commentaires

+1 de toute façon. Il est probable que les deux paste0 ralentissent i ; C'est (presque) toujours fait mieux avec une clé de 2 colonnes.



4
votes

Réponse super compliquée:

> library(rbenchmark)
> benchmark(fun(DT,n)[J(0)],setkey(setkey(setkey(DT,y)[setkey(n,y),nomatch=0],idx,y1)[setkey(J(idx,y,new.x=x),idx,y),x:=new.x],ok)[list(0)])
                                                                                                                                  test
1                                                                                                                     fun(DT, n)[J(0)]
2 setkey(setkey(setkey(DT, y)[setkey(n, y), nomatch = 0], idx, y1)[setkey(J(idx, y, new.x = x), idx, y), `:=`(x, new.x)], ok)[list(0)]
  replications elapsed relative user.self sys.self user.child sys.child
1          100   13.21 1.000000     13.08     0.02         NA        NA
2          100   15.08 1.141559     14.76     0.06         NA        NA
> crdt(1e5)
> benchmark(fun(DT,n)[J(0)],setkey(setkey(setkey(DT,y)[setkey(n,y),nomatch=0],idx,y1)[setkey(J(idx,y,new.x=x),idx,y),x:=new.x],ok)[list(0)])
                                                                                                                                  test
1                                                                                                                     fun(DT, n)[J(0)]
2 setkey(setkey(setkey(DT, y)[setkey(n, y), nomatch = 0], idx, y1)[setkey(J(idx, y, new.x = x), idx, y), `:=`(x, new.x)], ok)[list(0)]
  replications elapsed relative user.self sys.self user.child sys.child
1          100  150.49 1.000000    148.98     0.89         NA        NA
2          100  155.33 1.032162    151.04     2.25         NA        NA
>


1 commentaires

Super compliqué peut-être, mais c'est intelligent et agréablement rapide sur des données plus grandes (que j'ai!)



8
votes

Grande question. En utilisant les fonctions dans les autres réponses et enroulez la réponse de Blue dans une fonction bleu code>, que diriez-vous de ce qui suit. Les points de repère incluent le temps nécessaire à la touche code> dans tous les cas.

crdt(1e5)
origDT = copy(DT)
benchmark(blue={DT=copy(origDT); system.time(blue())},
          red={DT=copy(origDT); system.time(red())},
          fun={DT=copy(origDT); system.time(fun(DT,n))},
          replications=3, order="relative")

test replications elapsed relative user.self sys.self user.child sys.child
 red            3   1.107    1.000     1.100    0.004          0         0
blue            3   5.797    5.237     5.660    0.120          0         0
 fun            3   8.255    7.457     8.041    0.184          0         0

crdt(1e6)
[ .. snip .. ]
test replications elapsed relative user.self sys.self user.child sys.child
 red            3  14.647    1.000    14.613    0.000          0         0
blue            3  87.589    5.980    87.197    0.124          0         0
 fun            3 197.243   13.466   195.240    0.644          0         0

identical(blueans[,list(idx,x,y,ok,y1)],redans[order(idx,y1)])
# [1] TRUE


5 commentaires

Je suis systématiquement surpris de la puissance de data.table . Faire ce type d'opération à l'aide d'un autre paquet (ou de base R) nécessiterait à la fois plus de lignes de code et plus de temps! Bien fait et merci pour l'aide comme toujours.


Pour la postérité, si cela ne vous dérangerait pas d'ajouter des commentaires à certaines des lignes de votre fonction pour expliquer comment ils travaillent et pourquoi vous avez choisi cette technique, ce serait génial!


Cool, j'apprends de nouvelles choses. NE PAS CLÉ / TRY si vous avez juste besoin de rechercher une fois. Sous-ensemble Le jeu de données de données que vous recherchez avant de faire des jointures. Dans la ligne ans [ y1: n [y, y1, mul = "premier"]]] , le y est scopé en termes de ANS (comme la FAQ confirme en 2.13). Si vous connaissez que vos données sont mappées en tête-à-tête, utilisez multi = "premier" . Question: Dans ANS [ X: = DT [ANS [ LISTE (IDX, Y1)], X, MULT = "PREMIER"]]] , est Liste (IDX, Y1) < / Code> interprété dans la portée de ANS en raison du premier support externe ans , ou en raison du deuxième interne ANS support?


@Bluemagister Great, c'est tout sur place. Pour répondre à la dernière partie, c'est parce que ans [ liste (IDX, Y1)] est d'abord exécuté, et ce résultat est transmis comme i du dt [.. .] pièce extérieure.


@Justin Pas de problème, commentaires maintenant ajoutés.