【问题标题】:Apply a function across all combinations of variables and store the plot in a list where we can plot all (or part) of the ggplot lists在所有变量组合中应用一个函数,并将绘图存储在一个列表中,我们可以在其中绘制所有(或部分)ggplot 列表
【发布时间】:2020-02-09 14:36:31
【问题描述】:

我有一些数据(鸢尾花数据集),还有一个名为decisionplot 的绘图函数。我的问题是如何将decisionplot 函数(输出ggplot 图)应用于我数据中的所有变量组合。也就是在我们拥有的iris数据集中;

"Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"

我想将函数decisionplot应用于以下组合:

"Sepal.Length" "Sepal.Width"
"Sepal.Length" "Petal.Length"
"Sepal.Length" "Petal.Width"

"Sepal.Width" "Petal.Length"
"Sepal.Width" "Petal.Width"

"Petal.Length" "Petal.Width"

将这些绘图组合存储在一个列表中,我可以在一个网格上绘制不同的输出。

数据和decisionplot函数如下:

data(iris)
df <- iris %>% 
  filter(Species != "setosa") %>% 
  mutate(Species = +(Species == "virginica"))


decisionplot <- function(model, data, class = NULL, model_type = "NA", predict_type = "class",
                         resolution = 300, main, showgrid = TRUE, ...) {

  if(!is.null(class)){
    cl <- data[,class]
  }
  else{
    cl <- 1
  }

  k <- length(unique(cl))



  # make grid
  r <- sapply(data[,1:2], range, na.rm = TRUE)
  xs <- seq(r[1,1], r[2,1], length.out = resolution)
  ys <- seq(r[1,2], r[2,2], length.out = resolution)
  g <- cbind(rep(xs, each=resolution), rep(ys, time = resolution))
  colnames(g) <- colnames(r)
  g <- as.data.frame(g)

  ### guess how to get class labels from predict
  ### (unfortunately not very consistent between models)
  if(model_type == "xgboost"){
    message(paste0("Running Model ", model_type))
    p <- predict(object = model, newdata = xgboost::xgb.DMatrix(data = as.matrix(g)), type = predict_type)
    #p <- ifelse(p > tail(sort(p),1000)[1000], "Bankrupt", "Non-Bankrupt")
    p <- ifelse(p > 0.50, "Bankrupt", "Non-Bankrupt")
  }
  else {
    message(paste0("Running Model ", model_type))
    p <- predict(model, g, type = predict_type)
  }
  if(is.list(p)) p <- p$class
  if(is.logical(p)) p <- ifelse(p == TRUE, "Non-Bankrupt", "Bankrupt")
  p <- as.factor(p)

  plot_data <- cbind(g, p) %>% 
    setNames(c("X1", "X2", "Y")) %>% 
    mutate(class_num = case_when(
      Y == "Non-Bankrupt" ~ 1,
      Y == "Bankrupt" ~ 2
    ))
  ggplot() +
    geom_point(aes(x = X1, y = X2, colour = Y),
               data = plot_data) +
    geom_contour(aes(x = X1, y = X2, z = class_num),
                 bins = 2,
                 data = plot_data, size = 0.001) +
    geom_point(aes(x = Xvar1, y = Xvar2, color = factor(Yvar)),
               size = 3,
               data = data) +
    geom_point(aes(x = Xvar1, y = Xvar2),
               size = 3,
               shape = 1,
               #alpha = 0.2,
               data = data) +
    labs(title = paste(main),
         x = var1_to_plot,
         y = var2_to_plot)

}

然后我设置我想要通过函数的变量并创建我的boundary_data:

var1_to_plot = "Sepal.Length"
var2_to_plot = "Sepal.Width"

boundary_data <- df %>% 
  dplyr::select(rlang::eval_tidy(var1_to_plot), rlang::eval_tidy(var2_to_plot), Species) %>% 
  mutate(Species = factor(Species)) %>% 
  setNames(c("Xvar1", "Xvar2", "Yvar")) %>% 
  data.frame()

我终于创建了我的逻辑模型并运行decisionplot 函数。

model <- glm(Yvar ~., data = boundary_data, family = binomial(link='logit'))
class(model) <- c("lr", class(model))
predict.lr <- function(object, newdata, ...)
  predict.glm(object, newdata, type = "response") > .5
decisionplot(model, boundary_data, predict_type = "response", class = "Yvar", model_type = "Logistic", main = "Logistic Regression")

这给了我:

但是我想让它成为变量的所有组合之一(因为这里它只考虑Sepal.Width 和Sepal.Length)。

如何在网格上绘制不同的ggplot 变量组合?还是将图存储为列表?

编辑

我目前拥有以下内容 - 它为我提供了 12 个不同组合的列表。每个列表还有 2 个列表,一个数据集和一个逻辑模型。

var_combos <- expand.grid(colnames(df[,1:4]), colnames(df[,1:4])) %>% 
  filter(!Var1 == Var2)


iter_function = function(dat, V1, V2, Y){
  data = dat %>% 
    select(rlang::eval_tidy(V1), rlang::eval_tidy(V2), Y) %>% 
    mutate(Y = factor(rlang::eval_tidy(Y)))

  # Logistic Model
  model = glm(rlang::eval_tidy(Y) ~ ., data = data, family = binomial(link = 'logit'))
  class(model) <- c("lr", class(model))
  predict.lr <- function(object, newdata, ...){
    predict.glm(object, newdata, type = "response") > .5
  }
  return(list(data, model))
}

boundary_lists <- map2(
  .x = var_combos$Var1,
  .y = var_combos$Var2,
  ~iter_function(dat = df, V1 = .x, V2 = .y, Y = df$Species)
)

现在我想将这些列表中的每一个应用于decisionplot 函数。我不断收到. not found。

map2(
  .x = .[[1]],
  .y = .[[2]],
  ~decisionplot(model = .x, data = .y, predict_type = "response", class = "Species", model_type = "Logistic", main = "Logistic Regression")
)

如何映射列表列表的功能? (我意识到我没有给它从iter_function() 创建的boundary_lists 列表)

【问题讨论】:

  • 我将使用gtools::combinations 生成所有成对组合,然后使用purrr::pmap 迭代所有组合以应用您的函数并生成绘图。这将为您提供一个绘图列表,您可以将其用作cowplot::plot_grid 等函数的输入。
  • @rpolicastro 或者地块列表也可以很容易地与patchwork::wrap_plots一起使用
  • 我有所有不同的组合使用var_combos &lt;- expand.grid(colnames(df[,1:4]), colnames(df[,1:4])) %&gt;% filter(!Var1 == Var2) - 我只是在想如何最好地提取每一行和pmap 每个组合来构造一个新数据框列表,这将是一个@列表987654350@ 数据帧。
  • 我几乎拥有它(我添加了一个 EDIT)。我现在只需要知道如何使用map2() 映射列表的第一个和第二个元素。

标签: r ggplot2


【解决方案1】:

我认为最简单的方法是利用嵌套数据,结合purrr::map 函数。这样,您可以将所有内容保存在一个数据框中,而不必使用列表列表。请参阅https://r4ds.had.co.nz/many-models.html 了解有关使用嵌套数据的入门知识。

首先,我将您的iter_function 分成两部分:一个用于创建数据集,另一个用于创建模型。

create_data <- function(dat, V1, V2) {
  data = dat %>% 
    select(rlang::eval_tidy(V1), rlang::eval_tidy(V2), Y = Species) %>% 
    mutate(Y = as.factor(Y))
  return(data)
}

create_model <- function(data){
  # Logistic Model
  model = glm(Y ~ ., data = data, family = binomial(link = 'logit'))
  class(model) <- c("lr", class(model))
  predict.lr <- function(object, newdata, ...){
    predict.glm(object, newdata, type = "response") > .5
  }
  return(model)
}

然后,我可以创建类似于您的代码的var_combos(但我使用来自tidyr 的crossing 而不是expand.grid,因为这会转换为小标题)。请注意,完整的数据集也在数据框中的data 列中。根据您的数据集大小,这可能效率低下。

var_combos <- crossing(var1 = colnames(df[,1:4]),
                       var2 = colnames(df[,1:4]),
                       data = list(df)) %>% 
  filter(var1 != var2)

最后,使用map 函数,我可以将过滤后的数据、模型和绘图存储在数据框中的列中。

var_combos <- var_combos %>%
  mutate(data = pmap(list(data, var1, var2), create_data),
         model = map(data, create_model),
         plot = pmap(list(model, data, var1, var2), decisionplot, 
                     predict_type = "response", class = "Y",
                     model_type = "Logistic", main = "Logistic Regression")
         )

现在所有内容都存储在同一个数据框中。然后,您可以使用上述 cmets 中描述的方法之一绘制 plot 列的内容。
请注意,我必须将var1_to_plot, var2_to_plot 添加到decisionplot 的函数参数中才能使其工作(在model, data 之后)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 2018-12-23
    • 1970-01-01
    相关资源
    最近更新 更多