如何从数据框中提取列表?

5

考虑这个简单的例子

> weird_df <- data_frame(col1 =c('hello', 'world', 'again'),
+                       col_weird = list(list(12,23), list(23,24), NA))
> 
> weird_df
# A tibble: 3 x 2
   col1  col_weird
  <chr>     <list>
1 hello <list [2]>
2 world <list [2]>
3 again  <lgl [1]>

我需要提取col_weird中的值。我该如何做?我知道如何在Python中实现,但不知道如何在R中实现。期望输出为:

> good_df
# A tibble: 3 x 3
   col1   tic   toc
  <chr> <dbl> <dbl>
1 hello    12    23
2 world    23    24
3 again    NA    NA

2
unlist(weird_df$col_weird[[1]]) unlist(weird_df$col_weird[[2]]) - Enrique Pérez Herrero
1
你可以尝试使用以下代码:weird_df %>% rowwise() %>% mutate(col_weird = list(unlist(col_weird))) %>% ungroup %>% unnest %>% group_by(col1) %>% mutate(rn = c('tic', 'toc')[row_number()]) %>% spread(rn, col_weird) - akrun
1
如果是“yes,则不要使用它”,我并不知道是否已经发布了一些解决方案。 - akrun
1
我的解决方案是基于您发布的示例。因此,如果结构不同,您可能需要更新示例。 - akrun
1
根据更新后的问题,我的解决方案仍然适用。另一个选项是 library(purrr);library(reshape2);weird_df$col_weird %>% map(unlist) %>% setNames(., weird_df$col1) %>% melt %>% group_by(L1) %>% mutate(rn = c('tic', 'toc')[row_number()]) %>% spread(rn, value) - akrun
显示剩余6条评论
5个回答

4
如果将列表列折叠成字符串,您可以使用tidyr中的separate。我使用purrr中的map循环遍历列表列并使用toString创建字符串。
library(tidyr)
library(purrr)

weird_df %>%
     mutate(col_weird = map(col_weird, toString ) ) %>%
     separate(col_weird, into = c("tic", "toc"), convert = TRUE)

# A tibble: 3 x 3
   col1   tic   toc
* <chr> <int> <int>
1 hello    12    23
2 world    23    24
3 again    NA    NA

实际上,您可以直接使用separate而不需要toString部分,但最终您将得到“list”作为其中一个值。
weird_df %>%
     separate(col_weird, into = c("list", "tic", "toc"), convert = TRUE) %>%
     select(-list)

这促使我使用 tidyr::extract,只需要正确的正则表达式即可很好地工作。不过,如果您的列表列更加复杂,写出正则表达式可能会很麻烦。

weird_df %>%
     extract(col_weird, into = c("tic", "toc"), regex = "([[:digit:]]+), ([[:digit:]]+)", convert = TRUE)

嗯,非常非常干净。我有点嫉妒。 - ℕʘʘḆḽḘ

2
weird_df <- data_frame(col1 = c('hello', 'world'),
                   col_weird = list(list(12,23), list(23,24)))

library(dplyr)
weird_df %>%
  dplyr::mutate(tic = unlist(magrittr::extract2(col_weird, 1)),
                toc = unlist(magrittr::extract2(col_weird, 2)),
                col_weird = NULL)

最近更新:请注意,现在col_weird包含list(NA, NA)
weird_df <- data_frame(col1 = c('hello', 'world', 'again'),
                  col_weird = list(list(12,23), list(23,24), list(NA, NA)))

library(dplyr)
weird_df %>%
 dplyr::mutate(col_weird = matrix(col_weird),
 tic = sapply(col_weird, function(x) magrittr::extract2(x, 1)),
 toc = sapply(col_weird, function(x) magrittr::extract2(x, 2)),
 col_weird = NULL)

太好了!我们为什么要在这里使用 magrittr - ℕʘʘḆḽḘ
1
magrittr::extract2[[ 的替代品,它用于使 R 管道更易读。 - Enrique Pérez Herrero
1
当您编写R包时,需要使用NSE函数,例如mutate_和在roxygen2中使用@importFrom。然后,添加@importFrom magrittr extract2会非常有用。 - Enrique Pérez Herrero
这个解决方案似乎会因为缺失值而失败。你有什么想法吗?问题已更新...抱歉,再次感谢! - ℕʘʘḆḽḘ
1
Enrico,你还在吗? :D - ℕʘʘḆḽḘ
显示剩余2条评论

2

有了基本的R,您可以通过I()实现这一点:

weird_df <- data.frame(col1 =c('hello', 'world'), 
   col_weird = I(list(list(12,23),list(23,24))))

weird_df
>    col1 col_weird
  1 hello    12, 23
  2 world    23, 24

2

以下是使用 purrr/tidyverse/reshape2 的一种方法。我们在 map 中使用 unlist 将 'col_weird' 转换为 list,用 'col1' 设置 list 的名称,将其转换为长格式(long)并按 'L1' 分组,创建一个 'rn' 列并将其通过 spread 转回为宽格式(wide)。

library(tidyverse)
library(reshape2)
weird_df$col_weird %>%
     map(unlist) %>% 
     setNames(., weird_df$col1) %>%
     melt %>% 
     group_by(L1) %>%
     mutate(rn = c('tic', 'toc')[row_number()]) %>%
     spread(rn, value) %>%
     left_join(weird_df[-2], ., by = c(col1 = "L1"))

1
这真的很不错,但你觉得我的解决方案怎么样?它似乎更简单。 - ℕʘʘḆḽḘ

2

好的,我想到了一个简单的方法

> weird_df %>% 
+   rowwise() %>%
+   mutate(tic = col_weird[[1]],
+          tac = ifelse(length(col_weird) == 2, col_weird[[2]], NA)) %>% 
+   select(-col_weird) %>% ungroup()
# A tibble: 3 x 3
   col1   tic   tac
  <chr> <dbl> <dbl>
1 hello    12    23
2 world    23    24
3 again    NA    NA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接