У меня есть тиббл в аккуратном формате с тремя атрибутами - серией, одним из его возможных следующих элементов и вероятностью следующего элемента.
library(dplyr)
bases <- sapply(1:20, function(x){paste(sample(letters[1:3], 3, replace = T), collapse = " ")})
nplus1 <- sample(letters, 20, replace = T)
probs <- runif(20)
t <- as_tibble(data.frame(bases, nplus1, probs))
head(t)
# A tibble: 6 x 3
bases nplus1 probs
<fct> <fct> <dbl>
1 b a c r 0.409
2 c b b p 0.176
3 a b c s 0.468
4 a b a n 0.348
5 b a b c 0.733
6 b a b e 0.0525
В конце концов, я бы хотел использовать list2env()
, чтобы выполнить поиск по хэшу по базе. Для этого я разделил таблицу на список таблиц, сгруппированных по базе, используя split()
. Тиблы имеют порядка миллионов строк, и split()
достаточно быстр.
t_split <- split(t, t$bases)
t_split[1:3]
$`a a c`
# A tibble: 1 x 3
bases nplus1 probs
<fct> <fct> <dbl>
1 a a c i 0.661
$`a b a`
# A tibble: 1 x 3
bases nplus1 probs
<fct> <fct> <dbl>
1 a b a n 0.348
$`a b c`
# A tibble: 2 x 3
bases nplus1 probs
<fct> <fct> <dbl>
1 a b c s 0.468
2 a b c h 0.0324
Оттуда к списку элементов применяется цикл for для преобразования таблиц с интенсивным использованием памяти в списки. Насколько я понимаю, цикл for работает быстрее при таком преобразовании на месте, чем lapply
.
# helper function transforms tibble to vector
flatten <- function(table){
l <- list(np1 = table$nplus1, probs=table$probs)
return(l)
}
# for loop
loop <- function(table.list){
list.names <- names(table.list)
for( n in list.names ){
table.list[[n]] <- flatten(table.list[[n]])
}
table.list <- setNames(table.list, list.names)
return(table.list)
}
loop(t_split)
Несмотря на то, что шаг разделения по группам является быстрым, четыре цикла, которые сглаживают отдельные элементы, занимают целую вечность, около 12 часов для нерасщепленной таблицы с примерно 1,5 миллионами строк.
Что-то выделяется здесь как особенно неэффективное? Есть ли лучший и более быстрый способ переформатировать эти данные?