R - 如何使用参数列表过滤数据以生成多个数据框和图形
R - how to filter data with a list of arguments to produce multiple data frames and graphs
我正在寻找一种使用过滤器参数列表来生成不同对象的方法。我有一个数据集,我想为其制作多个图表。但是,我希望所有这些图表都基于数据集的子集。为了便于说明,我制作了以下数据。
df <- data.frame(type = c("b1", "b2", "b1", "b2"),
yield = c("15", "10", "5", "0"),
temperature = c("2", "21", "26", "13"),
Season = c("Winter", "Summer", "Summer", "Autumn"),
profit = c(TRUE, TRUE, FALSE, FALSE))
此外,我有一个过滤器参数列表。
filters <- c("brand=='b1'",
"profit",
"Season=='Summer'",
"profit==FALSE",
"yield >= 10",
"")
我想要的是我可以使用 for 循环让所有这些过滤器生成具有过滤数据的对象,然后绘制图形。我已经通过以下方式进行了尝试。
for(i in 1:length(filters)){
assign(paste0("df", i), filter(df, factor(filters[i])))
assign(paste0("plot", i), ggplot(database, aes(x = temperature, y = yield)) + geom_point())
}
然而,这不起作用,因为 filter()
函数不接受 <fct>
作为参数,也不接受 <chr>
(例如,"brand=='b1'"
)。我想要的是 brand=='b1'
,所以 filter()
接受它作为参数。有人有想法吗?
此外,作为一个附加问题,我想将整个过程自动化并以组合图结束,所以 grid.arrange()
最后。当然,我可以通过 length(filters)
的一些设计来自动化 ncol
和 nrow
。但是如何在 grid.arrange()
中获取所有生成的图?这应该在 for 循环之外,对吧?这里有什么想法吗?
您可以使用 eval
和 parse
来完成。
此外,在自定义函数上使用 lapply
听起来比使用 assign
的 for
循环更合理。结果是 ggplot
个对象的列表。
将 gridExtra
包中的所有图表一起设置 grid.arrange
效果很好。您只需将图表列表分配给名为 grobs
.
的参数
library(dplyr)
library(ggplot2)
df <- data.frame(type = c("b1", "b2", "b1", "b2"),
yield = c(15, 10, 5, 0),
temperature = c("2", "21", "26", "13"),
Season = c("Winter", "Summer", "Summer", "Autumn"),
profit = c(TRUE, TRUE, FALSE, FALSE))
filters <- list("type=='b1'",
"profit",
"Season=='Summer'",
"profit==FALSE",
"yield >= 10",
"TRUE")
myfun <- function(fltr, df){
df <- filter(df, eval(parse(text = fltr)))
ggplot(df, aes(x = temperature, y = yield)) + geom_point()
}
ggs <- lapply(filters, myfun, df = df)
gridExtra::grid.arrange(grobs = ggs)
我对您的数据进行了一些更改:yield 必须是数字,因为您使用的过滤器仅适用于数字向量,而最后一个过滤器(为空)现在等于 "TRUE" [我以为你想把所有事情都考虑进去]
与其将过滤器存储为字符串,不如将它们存储为一个 quosures。例如
library(rlang)
filters <- quos(type=='b1',
profit,
Season=='Summer',
profit==FALSE,
yield >= 10,
TRUE)
然后你可以很容易地用 purrr::map
映射这些
library(dplyr)
library(purrr)
library(ggplot2)
map(filters, ~df %>% filter(!!!.x) %>%
ggplot(aes(x = temperature, y = yield)) + geom_point())
假设最后注释中的输入数据修复了问题中显示的数据中的一些不一致,使温度和产量数值化并将profit == FALSE
提高到!profit
。定义一个函数 Plot
,它采用过滤器、子集 df
并绘制它。然后将其应用于每个 filter
并使用 grid.arrange
。这使用了 ggplot2 和 gridExtra 但没有额外的包并且没有明确使用 eval
。
(grid.arrange
行的替代方法是 cowplot::plot_grid(plotlist=plots)
,它的布局略有不同。)
library(ggplot2)
library(gridExtra)
Plot <- function(x) {
data <- do.call("subset", list(df, parse(text = x)))
ggplot(data, aes(temperature, yield)) + geom_line() + geom_point() + ggtitle(x)
}
plots <- Map(Plot, filters)
do.call("grid.arrange", plots)
备注
df <- data.frame(brand = c("b1", "b2", "b1", "b2"),
yield = c(15, 10, 5, 0),
temperature = c(2, 21, 26, 13),
Season = c("Winter", "Summer", "Summer", "Autumn"),
profit = c(TRUE, TRUE, FALSE, FALSE))
filters <- c("brand=='b1'",
"profit",
"Season=='Summer'",
"!profit",
"yield >= 10",
TRUE)
我正在寻找一种使用过滤器参数列表来生成不同对象的方法。我有一个数据集,我想为其制作多个图表。但是,我希望所有这些图表都基于数据集的子集。为了便于说明,我制作了以下数据。
df <- data.frame(type = c("b1", "b2", "b1", "b2"),
yield = c("15", "10", "5", "0"),
temperature = c("2", "21", "26", "13"),
Season = c("Winter", "Summer", "Summer", "Autumn"),
profit = c(TRUE, TRUE, FALSE, FALSE))
此外,我有一个过滤器参数列表。
filters <- c("brand=='b1'",
"profit",
"Season=='Summer'",
"profit==FALSE",
"yield >= 10",
"")
我想要的是我可以使用 for 循环让所有这些过滤器生成具有过滤数据的对象,然后绘制图形。我已经通过以下方式进行了尝试。
for(i in 1:length(filters)){
assign(paste0("df", i), filter(df, factor(filters[i])))
assign(paste0("plot", i), ggplot(database, aes(x = temperature, y = yield)) + geom_point())
}
然而,这不起作用,因为 filter()
函数不接受 <fct>
作为参数,也不接受 <chr>
(例如,"brand=='b1'"
)。我想要的是 brand=='b1'
,所以 filter()
接受它作为参数。有人有想法吗?
此外,作为一个附加问题,我想将整个过程自动化并以组合图结束,所以 grid.arrange()
最后。当然,我可以通过 length(filters)
的一些设计来自动化 ncol
和 nrow
。但是如何在 grid.arrange()
中获取所有生成的图?这应该在 for 循环之外,对吧?这里有什么想法吗?
您可以使用 eval
和 parse
来完成。
此外,在自定义函数上使用 lapply
听起来比使用 assign
的 for
循环更合理。结果是 ggplot
个对象的列表。
将 gridExtra
包中的所有图表一起设置 grid.arrange
效果很好。您只需将图表列表分配给名为 grobs
.
library(dplyr)
library(ggplot2)
df <- data.frame(type = c("b1", "b2", "b1", "b2"),
yield = c(15, 10, 5, 0),
temperature = c("2", "21", "26", "13"),
Season = c("Winter", "Summer", "Summer", "Autumn"),
profit = c(TRUE, TRUE, FALSE, FALSE))
filters <- list("type=='b1'",
"profit",
"Season=='Summer'",
"profit==FALSE",
"yield >= 10",
"TRUE")
myfun <- function(fltr, df){
df <- filter(df, eval(parse(text = fltr)))
ggplot(df, aes(x = temperature, y = yield)) + geom_point()
}
ggs <- lapply(filters, myfun, df = df)
gridExtra::grid.arrange(grobs = ggs)
我对您的数据进行了一些更改:yield 必须是数字,因为您使用的过滤器仅适用于数字向量,而最后一个过滤器(为空)现在等于 "TRUE" [我以为你想把所有事情都考虑进去]
与其将过滤器存储为字符串,不如将它们存储为一个 quosures。例如
library(rlang)
filters <- quos(type=='b1',
profit,
Season=='Summer',
profit==FALSE,
yield >= 10,
TRUE)
然后你可以很容易地用 purrr::map
library(dplyr)
library(purrr)
library(ggplot2)
map(filters, ~df %>% filter(!!!.x) %>%
ggplot(aes(x = temperature, y = yield)) + geom_point())
假设最后注释中的输入数据修复了问题中显示的数据中的一些不一致,使温度和产量数值化并将profit == FALSE
提高到!profit
。定义一个函数 Plot
,它采用过滤器、子集 df
并绘制它。然后将其应用于每个 filter
并使用 grid.arrange
。这使用了 ggplot2 和 gridExtra 但没有额外的包并且没有明确使用 eval
。
(grid.arrange
行的替代方法是 cowplot::plot_grid(plotlist=plots)
,它的布局略有不同。)
library(ggplot2)
library(gridExtra)
Plot <- function(x) {
data <- do.call("subset", list(df, parse(text = x)))
ggplot(data, aes(temperature, yield)) + geom_line() + geom_point() + ggtitle(x)
}
plots <- Map(Plot, filters)
do.call("grid.arrange", plots)
备注
df <- data.frame(brand = c("b1", "b2", "b1", "b2"),
yield = c(15, 10, 5, 0),
temperature = c(2, 21, 26, 13),
Season = c("Winter", "Summer", "Summer", "Autumn"),
profit = c(TRUE, TRUE, FALSE, FALSE))
filters <- c("brand=='b1'",
"profit",
"Season=='Summer'",
"!profit",
"yield >= 10",
TRUE)