Скажите, что у меня есть этот список:
listexample = list(books = list(list(
title = "Book 1",
entry = "entry 1",
publisher = "Books Unlimited",
authors = list(
list(name = "bob", location = "north dakota"),
list(name = "susan", location = "california"),
list(name = "tim")),
isbn = "1358",
universities = list(
list(univ = "univ1"),
list(univ = "univ2"))
),
list(
title = "Book 2",
entry = "entry 2",
publisher = "Books Unified",
authors = list(
list(name = "tom", location = "north dakota"),
list(name = "sally", location = "california"),
list(name = "erica", location = "berlin")),
isbn = "1258",
universities = list(
list(univ = "univ5"),
list(univ = "univ2"),
list(univ = "univ99"),
list(univ = "univ2"),
list(univ = "univ3"))
)
),
misc = list(name = "Jim Smith", location = "Alaska"))
Как я могу создать фрейм данных (или тиббл тоже подойдет), где каждая строка является автором? Я хочу полностью игнорировать второй элемент основного списка (misc
). Я также хочу игнорировать universities
, isbn
и publisher
. Я все еще хочу сохранить title
, name
, location
, а также books
(имя первого элемента основного списка).
Я знаю, что rrapply
можно использовать для итеративного выполнения действий, но не уверен, уместно ли это в данном случае.
library(rrapply)
rrapply(listexample, how = "bind")
Вы можете использовать unnest_longer
и unnest_wider
от tidyr
.
listexample |>
tibble::enframe() |>
dplyr::filter(name == "books") |>
tidyr::unnest_longer(value) |>
tidyr::unnest_wider(value) |>
dplyr::select(title, authors) |>
tidyr::unnest_longer(authors) |>
tidyr::unnest_wider(authors)
Вы можете запускать код, добавляя по одной строке, чтобы увидеть, что все делает. Короче говоря, мы превращаем список в двухстрочный тиббл (первая строка — books
, вторая строка — misc
), а затем расширяем вложенную информацию.
Прочтите tidyr
«прямоугольную» виньетку для получения дополнительной информации. На самом деле, вы, вероятно, можете сократить код здесь, используя tidyr::hoist()
.
Спасибо, что отметили виньетку и за ответ.
1) Используйте tibblify
, чтобы создать тиббл, и выберите из него столбцы title
и authors
. Последний представляет собой столбец списка, так что unnest
это так.
library(dplyr)
library(tidyr)
library(tibblify)
listexample %>%
.$books %>%
tibblify %>%
select(title, authors) %>%
unnest(authors)
предоставление
# A tibble: 6 × 3
title name location
<chr> <chr> <chr>
1 Book 1 bob north dakota
2 Book 1 susan california
3 Book 1 tim <NA>
4 Book 2 tom north dakota
5 Book 2 sally california
6 Book 2 erica berlin
2) Вариантом вышеизложенного является использование tibblify
со спецификацией, как показано ниже. Спецификацию можно создать, запустив guess_tspec_df(listexample$books)
, а затем отредактировав ее до желаемого значения.
spec <- tspec_df(
tib_chr("title"),
tib_df(
"authors",
tib_chr("name"),
tib_chr("location", required = FALSE),
)
)
tibblify(listexample$books, spec) %>% unnest(authors)
В базе R, используя lapply
и do.call
, вы можете сделать
> lapply(listexample[[1L]], \(i) {
+ tmp = i[names(i) %in% c("authors", "title")]
+ tmp2 = do.call("rbind", lapply(l<-tmp[["authors"]], `length<-`, max(lengths(l))))
+ cbind.data.frame("title" = rep(tmp[["title"]], nrow(tmp2)), tmp2)
+ }) |> do.call(what = "rbind")
title name location
1 Book 1 bob north dakota
2 Book 1 susan california
3 Book 1 tim NULL
4 Book 2 tom north dakota
5 Book 2 sally california
6 Book 2 erica berlin
Это выглядит нормально, если список не большой? Возможно, сначала вам захочется пробежаться
listexample[[2L]] = NULL
. И тогда, я думаю, это просто вопрос переименования и удаления строк.