data.table эквивалент tidyr :: complete с group_by с включенным и по синтаксису - PullRequest
0 голосов
/ 07 февраля 2019

Проблема:

Что такое data.table эквивалент tidyr команды complete с группой by?

Какая связь между on и by для 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"))
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

Цель состоит в том, чтобы получить следующее:

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

примерно так:

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

, но это не работает, и документация data.table относительно этого аспекта синтаксиса очень мала.

Недостаточно решений:

Следующие сообщения SO посвящены аналогичным проблемам, но не дают достаточных решений в этом контексте.

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Следующее вернет желаемый результат.

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 голосов
/ 07 февраля 2019

complete сохраняет другие несвязанные столбцы, поэтому я добавлю один ...

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

Чтобы завершить комбинации аксб для каждого с, я бы создал новую таблицу с этими комбинациями (точно так же, какуже в ответе @ G.Grothendieck) и update-join, чтобы получить d и другие некомбинированные столбцы:

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

В качестве альтернативы, вы можете выполнить внутреннее (?) объединение, хотя это неэффективно, поскольку оно создаетдве новые таблицы:

dt[mDT, on=cvars]

# or more concisely....

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

Или выполните одно внутреннее объединение для by= группы (из @eddi):

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

Для сравнения в тидиверсе:

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    
0 голосов
/ 07 февраля 2019

Попробуйте это:

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

давая:

    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
...