Самый быстрый способ выбрать несколько элементов из списка для создания фрейма данных - PullRequest
3 голосов
/ 29 мая 2020

У меня есть список, содержащий несколько кадров data.frames. Я хочу выбрать каждый n-й data.frame из списка и объединить их в один data.frame, который можно записать в csv.

Вот пример структуры списка:

one.title <- data.frame(id = '1a', title = 'first title')

one.author <- data.frame(first_name = c('Susan', 'Alice'),
                     last_name  = c('Smith', 'Johnson') )

second.title <- data.frame(id = '2b', title = 'second_title')

second.author <- data.frame(first_name = c('Sarah', 'Mary'),
                        last_name  = c('Davis', 'Proctor') )

one.list <- list()

one.list[[1]]$title <- one.title
one.list[[1]]$author <- one.author
one.list[[2]]$title <- second.title
one.list[[2]]$author <- second.author

Вот мое текущее решение, которое создает единственный фрейм данных для полей «авторы»:

build_author_table <- function(result.l){

  list_to_df <- function(i){

  x <- result.l[[i]]$author

  return(x)
}


authors_df_l <-(lapply(1:length(result.l), FUN = list_to_df))

authors_df <- do.call("rbind", lapply(authors_df_l, as.data.frame))

return(authors_df)
}

Это дает результат, который я хочу:

    first_name last_name
1      Susan     Smith
2      Alice   Johnson
3      Sarah     Davis
4       Mary   Proctor

Но, как вы, вероятно, можете представьте себе, что при масштабировании до тысяч записей с гораздо большими текстовыми полями в data.frame это очень медленно.

Может ли кто-нибудь предложить более быстрый и эффективный способ создания окончательного data.frame?

Ответы [ 3 ]

2 голосов
/ 29 мая 2020

Ваш строительный код не сработал, но я построил тот, который, как мне кажется, похож на то, во что вы стреляете.

List of 2
 $ :List of 2
  ..$ title :'data.frame':  1 obs. of  2 variables:
  .. ..$ id   : Factor w/ 1 level "1a": 1
  .. ..$ title: Factor w/ 1 level "first title": 1
  ..$ author:'data.frame':  2 obs. of  2 variables:
  .. ..$ first_name: Factor w/ 2 levels "Alice","Susan": 2 1
  .. ..$ last_name : Factor w/ 2 levels "Johnson","Smith": 2 1
 $ :List of 2
  ..$ title :'data.frame':  1 obs. of  2 variables:
  .. ..$ id   : Factor w/ 1 level "2b": 1
  .. ..$ title: Factor w/ 1 level "second_title": 1
  ..$ author:'data.frame':  2 obs. of  2 variables:
  .. ..$ first_name: Factor w/ 2 levels "Mary","Sarah": 2 1
  .. ..$ last_name : Factor w/ 2 levels "Davis","Proctor": 1 2

Если это то, о чем вы думали, это отлично работает, вы действительно получаете предупреждение, потому что строки символов являются факторами. Их можно игнорировать или при создании начального фрейма данных использовать stringAsFactors = F в качестве аргумента

library(purrr) 
map_dfr(one.list, "author")
1 голос
/ 29 мая 2020

Вот лучшее решение (протестировано):

data.table::rbindlist(lapply(one.list, "[[", "author"))

Решение с мурлыканьем красивое, но не такое быстрое. Результаты теста:

microbenchmark(build_author_table(one.list),
    data.table::rbindlist(lapply(one.list, "[[", "author")),
    map_dfr(one.list, "author"))
Unit: microseconds
                                                    expr     min       lq      mean   median       uq        max neval cld
                            build_author_table(one.list) 170.693 190.9460  239.2987 206.4505 272.3815    494.477   100   a
 data.table::rbindlist(lapply(one.list, "[[", "author"))  69.562  88.5590  270.4926  99.1750 152.6735  15068.116   100   a
                             map_dfr(one.list, "author") 214.832 245.2825 2374.5980 281.3210 340.1270 206562.846   100   a
0 голосов
/ 29 мая 2020

Попробуйте следующее:



one.title <- data.frame(id = '1a', title = 'first title')

one.author <- data.frame(first_name = c('Susan', 'Alice'),
                         last_name  = c('Smith', 'Johnson') )

second.title <- data.frame(id = '2b', title = 'second_title')

second.author <- data.frame(first_name = c('Sarah', 'Mary'),
                            last_name  = c('Davis', 'Proctor') )

one.list <- list(
  list(title = one.title, author =  one.author),
  list(title = second.title, author =  second.author)
)



authors_df_l = lapply(one.list, function(item) item$author)

do.call("rbind",authors_df_l)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...