Я хотел бы использовать функцию mutate_if()
dplyr для преобразования столбцов списка в столбцы кадра данных, но при попытке сделать это столкнусь с загадочной ошибкой. Я использую dplyr 0.5.0, purrr 0.2.2, R 3.3.0.
Базовая настройка выглядит так: у меня есть фрейм данных d
, некоторые столбцы которого являются списками:
d <- dplyr::data_frame(
A = list(
list(list(x = "a", y = 1), list(x = "b", y = 2)),
list(list(x = "c", y = 3), list(x = "d", y = 4))
),
B = LETTERS[1:2]
)
Я хотел бы преобразовать столбец списков (в данном случае d$A
) в столбец фреймов данных, используя следующую функцию:
tblfy <- function(x) {
x %>%
purrr::transpose() %>%
purrr::simplify_all() %>%
dplyr::as_data_frame()
}
То есть я бы хотел, чтобы столбец списка d$A
был заменен списком lapply(d$A, tblfy)
, который
[[1]]
# A tibble: 2 x 2
x y
<chr> <dbl>
1 a 1
2 b 2
[[2]]
# A tibble: 2 x 2
x y
<chr> <dbl>
1 c 3
2 d 4
Конечно, в этом простом случае я мог бы просто переназначить. Дело, однако, в том, что я хотел бы сделать это программно, в идеале с помощью dplyr, общеприменимым способом, который мог бы иметь дело с любым количеством столбцов списков.
Вот где я спотыкаюсь: когда я пытаюсь преобразовать столбцы списка в столбцы кадра данных с помощью следующего приложения
d %>% dplyr::mutate_if(is.list, funs(tblfy))
Я получаю сообщение об ошибке, которое не знаю, как интерпретировать:
Error: Each variable must be named.
Problem variables: 1, 2
Почему mutate_if()
не работает? Как правильно применить его, чтобы получить желаемый результат?
Замечание
Комментатор указал, что функция tblfy()
должна быть векторизована. Это разумное предложение. Но - если я не произвел некорректную векторизацию - это, похоже, не в корне проблемы. Подключив векторизованную версию tblfy()
,
tblfy_vec <- Vectorize(tblfy)
в mutate_if()
выходит из строя с ошибкой
Error: wrong result size (4), expected 2 or 1
Обновить
Получив некоторый опыт работы с мурлыканьем, я теперь считаю следующий подход естественным, хотя и несколько длинным:
d %>%
map_if(is.list, ~ map(., ~ map_df(., identity))) %>%
as_data_frame()
Это более или менее идентично решению @alistaire, приведенному ниже, но использует map_if()
, соответственно. map()
вместо mutate_if()
, соотв. Vectorize()
.
tblfy(d$A)
. Произошла ошибка, потому что вd$A
есть два списка. Вы не сравниваете яблоки с яблоками. В вашемlapply(d$A, tblfy)
вы указываете своей функции по одному списку за раз, поэтому это работает.tblfy(d$A[[1]])
иtblfy(d$A[[2]])
. В вашей функции dplyr вы предоставляете два списка. Изменитеtblfy
, чтобы принимать более одного списка, или измените вызов dplyr. Или, как просит MrFlick, подумайте шире о том, что вы создаете. - person Pierre L   schedule 07.07.2016tblfy_vec()
непосредственно кd$A
, я получаю список из 4, который совсем не соответствует моему пониманию, что векторизация создает функцию, которая работает со списком (или вектором) покомпонентно. - person egnha   schedule 07.07.2016tblfy
не работает для меня в образце набора данных. Проблема в том, что вам действительно нужно оценивать по строкам (или векторизовать) и обрабатывать ошибки, которые исходный код выдает, когда он не находится в функции. Что делает у меня работает, если вы можете превратить это в функцию:d %>% rowwise() %>% mutate(A = A %>% map_df(identity) %>% list()) %>% tidyr::unnest()
Вы можете векторизовать, чтобы избежатьrowwise
, т.е.d %>% mutate(A = Vectorize(function(x) x %>% map_df(identity) %>% list())(A)) %>% tidyr::unnest()
- person alistaire   schedule 07.07.2016