Самый быстрый способ многократного подмножества фрейма данных с различными условиями? - PullRequest
0 голосов
/ 09 июля 2020

У меня есть фрейм данных, подобный показанному ниже (игрушечный пример)

> dt
 A B C D
1 0 0 0 1
2 0 0 0 1
3 0 1 0 1
4 1 1 0 0
5 1 0 0 1

, и список однострочных фреймов данных, как показано ниже

[[1]]
  A C
1 1 0

[[2]]
  A D
1 0 1

.
.

Затем мне нужно повторно подмножество большего фрейма данных dt на основе меньших фреймов данных, так что для каждого из меньших фреймов данных я получаю все и только те строки dt, в которых столбцы, соответствующие меньшим столбцам фрейма данных, имеют значения, которые соответствуют значениям в меньшем фрейм данных. Таким образом, результатом для двух небольших dfs, показанных выше, должен быть список, как показано ниже, созданный путем подмножества dt или объединения dt и небольших фреймов данных соответствующим образом:

[[1]]
  A B C D
2 1 0 0 1
5 1 1 0 0

[[2]]
  A B C D
1 0 0 0 1
3 0 0 0 1
4 0 1 0 1

.
.

После изучения ответов на аналогичные вопросы по SO и в других местах , Я до сих пор не знаю, как быстрее всего этого добиться. В частности, я пробовал использовать для этого data.table, но считаю, что делаю что-то не так, так как не могу сделать это особенно быстро (все еще новичок в data.table ...). Установка ключа не кажется такой уж полезной, так как ключ (и) придется повторно устанавливать повторно. Я также пробовал dplyr semi_join (), но для меня это было не быстрее, чем base. Ниже приведен полный пример игрушки с некоторыми результатами тестирования в комментариях. Детальные результаты не так важны - дело в том, что вариант, использующий только базу, самый быстрый, и я серьезно сомневаюсь, что моя попытка, например, с data.table, является оптимальным решением data.table. Мы будем очень благодарны за любые предложения, как сделать это более эффективно, фактический вариант использования включает повторение такого рода подмножества / объединения много раз и в настоящее время является основным узким местом.

1 Ответ

0 голосов
/ 09 июля 2020

Я не получаю таких же значений, как вы, но с данными этого примера

set.seed(1L)

dt <- data.frame(A = sample(c(0,1), 5, replace = T), 
                 B = sample(c(0,1), 5, replace = T),
                 C = sample(c(0,1), 5, replace = T),
                 D = sample(c(0,1), 5, replace = T))

cvals <- replicate(10, dt[sample(1:nrow(dt), 1), sort(sample(1:length(dt), 2)) ], simplify = FALSE)

мы можем выполнить задачу в Base-R с помощью

lapply(cvals, function(x) dt[apply(dt[,colnames(x)],1, function(y) all(unlist(y) == unlist(x))),])

[[1]]
  A B C D
2 1 0 0 1
5 1 1 0 0

[[2]]
  A B C D
1 0 0 0 1
3 0 0 0 1
4 0 1 0 1

[[3]]
  A B C D
5 1 1 0 0

[[4]]
  A B C D
1 0 0 0 1
2 1 0 0 1
3 0 0 0 1

[[5]]
  A B C D
1 0 0 0 1
2 1 0 0 1
3 0 0 0 1
4 0 1 0 1

[[6]]
  A B C D
1 0 0 0 1
2 1 0 0 1
3 0 0 0 1
4 0 1 0 1

[[7]]
  A B C D
4 0 1 0 1

[[8]]
  A B C D
4 0 1 0 1

[[9]]
  A B C D
1 0 0 0 1
3 0 0 0 1
4 0 1 0 1

[[10]]
  A B C D
2 1 0 0 1
...