4
votes

data.table équivalent de tidyr :: complete avec group_by avec on et by syntax

Quel est l'équivalent data.table de la commande complete de tidyr avec le groupe by ?

Quelle est la relation entre on et by pour data.table ?

Exemple:

setDT(dt)[CJ(a=a,b=b,unique=TRUE), on=.(a,b) , by = .(c)]

L'objectif est d'obtenir ce qui suit: p >

a  b c
1  4 x
1  5 x
1  6 x
1  7 x
2  4 x
2  5 x
2  6 x
2  7 x
3  8 y
3  9 y
3 10 y
3 11 y
4  8 y
4  9 y
4 10 y
4 11 y

donc quelque chose à peu près comme ceci:

dt=data.table(a = c(1,1,2,2,3,3,4,4) , b = c(4,5,6,7,8,9,10,11) , c = c("x","x","x","x","y","y","y","y"))
show(dt)

   a  b c
1: 1  4 x
2: 1  5 x
3: 2  6 x
4: 2  7 x
5: 3  8 y
6: 3  9 y
7: 4 10 y
8: 4 11 y

mais cela ne fonctionne pas et le code data.table > la documentation est mince sur cet aspect de la syntaxe.

Solutions insuffisantes:

Les articles SO suivants abordent des problèmes similaires, mais ne fournissent pas de solutions suffisantes dans ce contexte.


0 commentaires

3 Réponses :


5
votes

Essayez ceci:

    c a  b
 1: x 1  4
 2: x 1  5
 3: x 1  6
 4: x 1  7
 5: x 2  4
 6: x 2  5
 7: x 2  6
 8: x 2  7
 9: y 3  8
10: y 3  9
11: y 3 10
12: y 3 11
13: y 4  8
14: y 4  9
15: y 4 10
16: y 4 11

donnant:

dt[, CJ(a = a, b = b, unique = TRUE), by = "c"]


4 commentaires

Pourquoi on n'est-il plus nécessaire?


on est utilisé pour faire une fusion mais il n'y a pas de fusion ici.


dans le jeu de données réel, j'ai perdu toutes les colonnes supplémentaires. ma faute,. je vais mettre à jour l'exemple


Dans ce cas, effectuez une fusion par la suite.



1
votes

Ce qui suit renverra le résultat souhaité.

library(data.table)
dt=data.table(a = c(1,1,2,2,3,3,4,4) , 
              b = c(4,5,6,7,8,9,10,11) , 
              c = c("x","x","x","x","y","y","y","y"))
dttrue <- fread('a  b c
                1  4 x
                1  5 x
                1  6 x
                1  7 x
                2  4 x
                2  5 x
                2  6 x
                2  7 x
                3  8 y
                3  9 y
                3 10 y
                3 11 y
                4  8 y
                4  9 y
                4 10 y
                4 11 y')
dt2 <- dt[,CJ(a=a,b=b,unique = TRUE),by = c]
all.equal(dt2[,.(a,b,c)], dttrue) #true


0 commentaires

5
votes

complete conserve d'autres colonnes non liées, je vais donc en ajouter une ...

library(dplyr); library(tidyr)
data.frame(dt) %>% group_by(c) %>% complete(a, b)

# A tibble: 16 x 4
# Groups:   c [2]
   c         a     b d    
   <chr> <dbl> <dbl> <chr>
 1 x         1     4 K    
 2 x         1     5 L    
 3 x         1     6 <NA> 
 4 x         1     7 <NA> 
 5 x         2     4 <NA> 
 6 x         2     5 <NA> 
 7 x         2     6 M    
 8 x         2     7 N    
 9 y         3     8 O    
10 y         3     9 P    
11 y         3    10 <NA> 
12 y         3    11 <NA> 
13 y         4     8 <NA> 
14 y         4     9 <NA> 
15 y         4    10 Q    
16 y         4    11 R    

Pour compléter les combos axb pour chaque c, je ferais un nouveau table avec ces combos (exactement comme déjà dans la réponse de @ G.Grothendieck) et update-join pour obtenir d et d'autres colonnes non combo:

dt[, .SD[CJ(a = a, b = b, unique = TRUE), on = .(a, b)], by = c]

Alternativement, vous pouvez faire un jointure interne (?), bien que cela soit inefficace car cela crée deux nouvelles tables:

dt[mDT, on=cvars]

# or more concisely....

dt[dt[, CJ(a = a, b = b, unique=TRUE), by=c], on=.(a,b,c)]

Ou, faites une jointure interne par groupe by = ( de @eddi):

mDT = dt[, CJ(a = a, b = b, unique=TRUE), by=c]
cvars = copy(names(mDT))
ovars = setdiff(names(dt), cvars)

mDT[, (ovars) := dt[.SD, on=cvars, mget(sprintf("x.%s", ovars))]]
setcolorder(mDT, names(dt))

    a  b c    d
 1: 1  4 x    K
 2: 1  5 x    L
 3: 1  6 x <NA>
 4: 1  7 x <NA>
 5: 2  4 x <NA>
 6: 2  5 x <NA>
 7: 2  6 x    M
 8: 2  7 x    N
 9: 3  8 y    O
10: 3  9 y    P
11: 3 10 y <NA>
12: 3 11 y <NA>
13: 4  8 y <NA>
14: 4  9 y <NA>
15: 4 10 y    Q
16: 4 11 y    R

Pour comparaison dans le tidyverse:

library(data.table)
dt = data.table(
  a = c(1,1,2,2,3,3,4,4) , 
  b = c(4,5,6,7,8,9,10,11) , 
  c = c("x","x","x","x","y","y","y","y"),
  d = LETTERS[10 + 1:8])

   a  b c d
1: 1  4 x K
2: 1  5 x L
3: 2  6 x M
4: 2  7 x N
5: 3  8 y O
6: 3  9 y P
7: 4 10 y Q
8: 4 11 y R


1 commentaires

Je ferais dt [ .SD [CJ (a = a, b = b, unique = TRUE), on =. (A, b)], by = c] s'il n'y a pas ' t trop de valeurs c .