一个简单的问题,但我一直在寻找解决方案,但到目前为止仍然无济于事。
假设我有一个列表对象,我想提取特定的列表元素并将其作为数据帧列并排输出。如何以简单的方式使用tidyverse /管道实现此目的?尝试在下面解决它。
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"))
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"
我将补充原始管道,以便:
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
[是的,它确实起作用,但是在map_df()
中,我不得不放置一个相对较大的“魔术”数(任意输入30)以确保包括所有数据。有没有更简单的方法将$breaks
和$counts
用作数据帧?也许只用一个步骤而不是组合map_df()
然后组合select()
?
尽管此特定问题演示了histogram
类的情况,但我的一般问题不是关于直方图,而是关于列表对象的原理。 hist(plot = FALSE)
的输出的好处是,它会生成一个元素长度不等的对象,这说明了一个问题,该问题需要灵活的解决方案来解决元素长度的差异。
基于下面的RémiCoulaud(选择的)解决方案,解决列表元素长度不相等的情况的方法是使它们相等,并固定在最长的元素上。然后,这不再是问题。工作管道如下:
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)
谢谢!
我对第一个关于histogram
问题的最佳答案是here。
我确实想做同样的事情,实际上您不需要使用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
NA
是必需的,因为您的计数少于中断值。
编辑1
hist
类的特殊性必须予以考虑。就像说@Cole。如果您想要列表对象的解决方案,则应查看下面的答案。
如果您的问题只是从list
传递到data.frame
。选择仅带有list
的示例可能更合适。而且,如果我们不存在从历史记录类传递到data.frame的问题。没有问题。实际上,r中的list
与data.frame
相同。所以你可以做:
library(dplyr)
l <- list(breaks = c(1, 2, 3, 4),
counts = c(10, 34, 54, 78),
other = rep("A", 4))
如果需要小标题:
l %>% as_tibble %>% select(breaks:counts)
如果您想要一个data.frame:
l %>% data.frame
我希望它能澄清您的问题。
编辑2
对于具有不等长元素的list
,请参阅there。一世lengths
为您提供list
每个元素的长度。用以下方法将所有大小相同的元素标准化后:
lapply(l, `length<-`, max(lengths(l)))
您只需要绑定它们并将其转换为data.frame。您可以在整个管道中使用
dplyr
语法,但它也像这样工作:
as.data.frame(do.call(cbind, lapply(l, `length<-`, max(lengths(l)))))
带管道:
lapply(l, `length<-`, max(lengths(l))) %>% do.call(what = cbind) %>% data.frame
总之,在创建
length
之后,必须指定最大data.frame
。
length<-
参见there,该函数为您提供了从开始到给出值的所有元素,在本例中为5。如果向量较短,则会自动引入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
复杂因素的一部分是hist()
对象的列表具有不同的长度:
我们可以使用imap
和enframe
将列表中的每个元素转换为带有name
(行号)和value
(元素名称)的数据帧。然后,我们可以使用reduce
和full_join
合并所有数据帧。最后,我们可以选择所需的列。这种方法不需要指定“魔术”数字。