使用 tidyverse 从列表到数据框,选择特定的列表元素

Emm*_*man 6 r tidyverse

一个简单的问题,但我已经寻找了解决方案,但到目前为止无济于事。

假设我有一个列表对象,我想提取特定的列表元素并将它们作为数据框列并排输出。如何通过 tidyverse/piping 以简单的方式实现这一点?下面尝试解决。

数据

some_data <-
structure(list(x = c(23.7, 23.41, 23.87, 24.18, 24.15, 24.31, 
23.14, 23.72, 24.12, 23.47, 23.59, 23.29, 23.24, 23.5, 23.56, 
23.16, 23.62, 23.67, 23.84, 23.69, 23.7, 23.68, 24.2, 23.77, 
23.74, 23.64, 24.39, 24.05, 24.51, 23.6, 24.29, 23.31, 23.96, 
24.07, 24.37, 23.77, 23.64, 24, 23.68, 24.02, 23.36, 23.54, 23.34, 
23.69, 23.79, 23.8, 23.7, 24.45, 23.27, 23.57, 23.02, 24.23, 
23.41, 23.6, 24.02, 23.94, 24.06, 23.97, 23.38, 23.46, 24, 23.89, 
23.51, 23.72, 23.83, 23.96, 23.84, 23.52, 24.36, 23.94, 23.82, 
24.04, 24.05, 23.6, 23.52, 24.13, 23.43, 23.33, 24.01, 23.99, 
24.46, 24.23, 24.19, 23.83, 23.8, 23.93, 23.79, 23.48, 23.26, 
24.04, 23.93, 23.98, 23.86, 23.49, 24.17, 23.7, 23.54, 23.55, 
23.67, 23.66)), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"
), row.names = c(NA, -100L), spec = structure(list(cols = list(
    x = structure(list(), class = c("collector_double", "collector"
    ))), default = structure(list(), class = c("collector_guess", 
"collector")), skip = 1), class = "col_spec"))
Run Code Online (Sandbox Code Playgroud)

我想要这个数据的 `hist()` 函数的值输出

library(tidyverse)

some_data$x %>% 
   as.numeric() %>% 
   hist(breaks = seq(from = 23, to = 24.6, by = 0.2),
        plot = FALSE)

## $breaks
## [1] 23.0 23.2 23.4 23.6 23.8 24.0 24.2 24.4 24.6

## $counts
## [1]  3  9 20 23 19 16  7  3

## $density
## [1] 0.15 0.45 1.00 1.15 0.95 0.80 0.35 0.15

## $mids
## [1] 23.1 23.3 23.5 23.7 23.9 24.1 24.3 24.5

## $xname
## [1] "."

## $equidist
## [1] TRUE

## attr(,"class")
## [1] "histogram"
Run Code Online (Sandbox Code Playgroud)

因此,假设我希望将 `$breaks` 和 `$counts` 并排作为数据框

我将补充原始管道,以便:

some_data$x %>% 
   as.numeric() %>% 
   hist(breaks = seq(from = 23, to = 24.6, by = 0.2),
        plot = FALSE) %>%
##
   map_df(~.[1:30]) %>%
   select(bins = breaks, 
          frequency = counts)
##

## # A tibble: 30 x 2
##     bins frequency
##    <dbl>     <int>
##  1  23           3
##  2  23.2         9
##  3  23.4        20
##  4  23.6        23
##  5  23.8        19
##  6  24          16
##  7  24.2         7
##  8  24.4         3
##  9  24.6        NA
## 10  NA          NA
## # ... with 20 more rows
Run Code Online (Sandbox Code Playgroud)

所以是的,它确实有效,但map_df()我必须输入一个相对较大的“魔术”数字(我任意输入 30)以确保包含所有数据。有没有更简单的方法来获取$breaks$counts作为数据框?也许甚至只需一步而不是组合map_df()然后select()

评论

虽然这个特定问题展示了histogram类的情况,但我的一般问题不是关于直方​​图,而是关于列表对象的原则。输出的hist(plot = FALSE)好处是它生成了一个具有不等长元素的对象,这证明了一个需要灵活解决方案来解决元素长度差异的问题。

解决方案

基于下面Rémi Coulaud的(选择的)解决方案,解决列表元素长度不等的情况的方法是使它们相等,锚定到最长的元素。那么,这不再是问题了。工作管道如下:

library(tidyverse)

some_data$x %>% 
  as.numeric() %>% 
  hist(breaks = seq(from = 23, to = 24.6, by = 0.2),
       plot = FALSE) %>%
  lapply(., `length<-`, max(lengths(.))) %>%  ## make all elements as the length of the longest one
  map_df(~.) %>%
  select(bins = breaks, 
         frequency = counts)
Run Code Online (Sandbox Code Playgroud)

谢谢!

Rém*_*aud 1

我为第一个问题找到的最佳答案histogram在这里

我试图做同样的事情,事实上你不需要使用hist函数,因为最后你想要一个data.frame.

一种解决方案是:

library(tidyverse)
breaks <- seq(from = 23, to = 24.6, by = 0.2)
df <- data.frame(breaks = breaks,
           frequency = c(some_data$x %>% 
  as.numeric() %>%
  findInterval(vec = breaks) %>%
  tabulate(), NA))

df
Run Code Online (Sandbox Code Playgroud)

NA是必需的,因为您的计数少于中断值。

编辑1

的特异性hist必须考虑类别就像@Cole 说的。如果您想要列表对象的解决方案,您应该查看下面的答案。

如果您的问题只是从 a 传递list到 a data.frame。选择仅包含 的示例可能更合适list。此外,如果我们没有从 hist 类传递到 data.frame 的问题。没有问题。事实上,list在 r 中与 相同data.frame。所以你可以这样做:

library(dplyr)
l <- list(breaks = c(1, 2, 3, 4),
          counts = c(10, 34, 54, 78),
          other = rep("A", 4))
Run Code Online (Sandbox Code Playgroud)

如果需要小标题:

l %>% as_tibble %>% select(breaks:counts)
Run Code Online (Sandbox Code Playgroud)

如果你想要一个数据框:

l %>% data.frame
Run Code Online (Sandbox Code Playgroud)

我希望它能澄清你的问题。

编辑2

对于list不等长元素,请参阅此处。我 lengths给出了 的每个元素的长度list。将所有元素标准化为相同大小后:

lapply(l, `length<-`, max(lengths(l)))
Run Code Online (Sandbox Code Playgroud)

您只需绑定它们并将其转换为 data.frame 即可。您可以在整个管道中使用dplyr语法,但它的工作原理也如下:

as.data.frame(do.call(cbind, lapply(l, `length<-`, max(lengths(l)))))
Run Code Online (Sandbox Code Playgroud)

带管:

lapply(l, `length<-`, max(lengths(l))) %>%
  do.call(what = cbind) %>%
  data.frame
Run Code Online (Sandbox Code Playgroud)

总之,似乎必须指定length创建后的最大值data.frame

see There函数为您提供从开始到您给出的值(在我的示例中为 5)的所有元素length<-。如果您的向量较短,它会自动引入值。NA

例如:

l <- list(breaks = c(1, 2, 3, 4),
          counts = c(10, 34, 54, 78),
          other = rep("A", 4),
          diff = rep("B", 3))

`length<-`(l$breaks, 5)
[1]  1  2  3  4 N
Run Code Online (Sandbox Code Playgroud)