2013-08-14 5 views
1

Si j'ai un data.tableR - data.table par groupe par - l'ordre des clés et des clés manquantes

> DT1 <- data.table(A=rep(c('A', 'B'), 3), 
        B=rep(c(1,2,3), 2), 
        val=rnorm(6), key='A,B') 
> DT1 
    A B  val 
1: A 1 -1.6283314 
2: B 2 0.5337604 
3: A 3 0.9991301 
4: B 1 1.1421400 
5: A 2 0.1230095 
6: B 3 0.4988504 

et je veux sous-ensemble de plus d'une clé, comme ceci:

> DT1[J('A', 1)]                
    A B   val 
1: A 1 -0.004898047 

Cependant, la jointure dépend de l'ordre des clés, donc la valeur de la clé A doit toujours venir en premier. Cela ne fonctionnera pas, même si vous spécifiez des noms (soit comme J() ou comme list()):

> DT1[J(1, 'A')] 
Error in `[.data.table`(DT1, J(1, "A")) : 
    x.'A' is a character column being joined to i.'V1' which is type 'double'. Character columns must join to factor or character columns. 

> DT1[J(B=1, A='A')] 
Error in `[.data.table`(DT1, J(B = 1, A = "A")) : 
    x.'A' is a character column being joined to i.'B' which is type 'double'. Character columns must join to factor or character columns. 

Y at-il une syntaxe où vous pouvez faire ce genre de regroupement par i sans connaître l'ordre des clés?

Ajouté: Un autre cas d'utilisation serait si je voulais seulement sous-ensemble B et non par A - est-il un moyen d'ignorer les clés dans le sous-ensemble? Les réponses actuelles qui créent des fonctions wrapper pour J ne semblent pas permettre cela.

EDIT: Certains ont mentionné le faire le chemin data.frame. Je sais que vous pouvez utiliser un vecteur de valeurs logiques au sous-ensemble, mais cela est lent comme il le fait une analyse de la table entière:

> DT1 <- data.table(A=rep(c(1,2,3), 100000), B=rep(c('A', 'B'), 150000), val=rnorm(300000), key='A,B') 
> system.time(DT1[DT1$A==1, DT1$B=="A"])          
    user system elapsed 
    0.080 0.000 0.054 
> system.time(DT1[J(1, 'A')]) 
    user system elapsed 
    0.004 0.000 0.004 

Quelques références aux discussions connexes: (1)

+0

Votre exemple ne semble pas être reproductible en raison de 'rnorm'. Quel est le problème avec 'DT1 [DT1 $ A == 'A' & DT1 $ B == 1,]'? –

+0

S'il vous plaît voir mon edit - essentiellement la méthode n'est pas une jointure et est beaucoup plus lent. – hgcrpd

+0

pour "ignorer" les touches que vous devez joindre par * toutes * les touches précédentes, par ex. 'DT1 [J (unique (A), 1)]' et je devine à un certain point les avantages de la jointure deviennent discutables lorsque je fais cela – eddi

Répondre

2

Que diriez-vous .. .

myJ <- function(key,...) do.call(data.table,list(...))[,key,with=FALSE] 
DT1[myJ(B=1,A='A',key=key(DT1))] 

ou

myJ1 <- function(...) myJ(key(DT1),...) 
DT1[myJ1(B=1,A='A')] 

de cette façon, vous devez étiqueter le i tems correctement.

+0

Je trouve généralement pratique de prêter attention à la commande et d'économiser de précieuses frappes/fouillis en omettant les noms. (Autrement dit, j'utilise la syntaxe normale 'J' ...) – Frank

2

Dans l'esprit de @ la réponse de Frank, mais en essayant d'obtenir la clé automagiquement:

myJ2 = function(...) { 
    # 'x' a couple of frames above is where the original data.table sits 
    data.table(..., key = key(get('x', parent.frame(n = 3)))) 
} 

DT1[myJ2(B=1, A='A')] 
# A B  val 
#1: A 1 0.4328698 
+0

+1. Oui, c'est mieux. En plus de vos automagicks, j'ai oublié que "key" pourrait être un argument de 'data.table'. – Frank

Questions connexes