Как объединить список data.tables без получения разделенных столбцов? - PullRequest
0 голосов
/ 23 ноября 2018

Я собираюсь объединить большие наборы данных.Вот почему я пробую data.table и в восторге от его скорости.

# base R
system.time(
  M1 <- Reduce(function(...) merge(..., all=TRUE), L)
  )
# user  system elapsed 
# 5.05    0.00    5.20 

# data.table    
library(data.table)
L.dt <- lapply(L, function(x) setkeyv(data.table(x), c("sid", "id")))
system.time(
  M2 <- Reduce(function(...) merge(..., all=TRUE), L.dt)
  )
# user  system elapsed 
# 0.12    0.00    0.12

Оба подхода дают одинаковые значения, однако есть некоторые столбцы, которые разделяются с data.table.

база R:

set.seed(1)
car::some(M1, 5)
#        sid    id         V3        V4          a         b
# 60504    1 60504 -0.6964804 -1.210195         NA        NA
# 79653    1 79653 -2.5287163 -1.087546         NA        NA
# 111637   2 11637  0.7104236        NA -1.7377657        NA
# 171855   2 71855  0.2023342        NA -0.6334279        NA
# 272460   3 72460 -0.5098994        NA         NA 0.2738896

data.table:

set.seed(1)
car::some(M2, 5)
#    sid    id       V3.x        V4      V3.y          a         V3         b
# 1:   1 60504 -0.6964804 -1.210195        NA         NA         NA        NA
# 2:   1 79653 -2.5287163 -1.087546        NA         NA         NA        NA
# 3:   2 11637         NA        NA 0.7104236 -1.7377657         NA        NA
# 4:   2 71855         NA        NA 0.2023342 -0.6334279         NA        NA
# 5:   3 72460         NA        NA        NA         NA -0.5098994 0.2738896

Я что-то пропустил?Или есть простой способ решить эту проблему - объединить разделенные столбцы?(Я не хочу использовать какие-либо другие пакеты.)

Данные

fun <- function(x){
  set.seed(x)
  data.frame(cbind(sid=x, id=1:1e5, matrix(rnorm(1e5*2), 1e5)))
}
tmp <- lapply(1:3, fun)
df1 <- tmp[[1]]
df2 <- tmp[[2]]
df3 <- tmp[[3]]
rm(tmp)
names(df2)[4] <- c("a")
names(df3)[4] <- c("b")
L <- list(df1, df2, df3)

Связанные: 1 , 2

1 Ответ

0 голосов
/ 23 ноября 2018

Аргумент by в base::merge по умолчанию равен intersect(names(x), names(y)), где x и y - это две таблицы, которые должны быть объединены.Следовательно, base::merge также использует V3 в качестве ключа объединения.

В аргументе by в data.table::merge по умолчанию используются столбцы общего ключа между двумя таблицами (то есть sid и id вэтот случай).И поскольку таблицы имеют столбцы с именем V3, к новым столбцам добавляются суффиксы.

Таким образом, если вы хотите объединить все общие столбцы, вы можете определить общие столбцы, задать ключи, а затем объединить:

commcols <- Reduce(intersect, lapply(L, names))
L.dt <- lapply(L, function(x) setkeyv(data.table(x), commcols))
M2 <- Reduce(function(...) merge(..., all=TRUE), L.dt)
...