如何从数据帧构造case_when的参数?

Gio*_*tti 5 r dplyr tidyverse rlang

我正在尝试基于温度创建许多不同的加权方案。

我创建了一个数据框,其中包含8个向量的所有可能组合(每个向量代表一个温度范围)。因此,数据框的列是特定的温度范围,行是权重。

我想将温度范围作为参数传递给case_when,并遍历权重数据帧的每一行,根据实际温度为每一行创建一个新变量,并根据权重数据中的信息为该温度创建关联的权重帧。

使用以下文章,我能够创建一个函数来生成权重数据框:

以编程方式将dplyr :: case_when与参数一起使用

但是我不知道如何case_when使用权重数据帧构造参数。

创建所有可能权重的数据框的功能

library(rlang)
library(tidyverse)

create_temp_weights <- function(
  from = 31,
  to = 100,
  by = 10,
  weights = exprs(between(., 31, 40) ~ c(0, 0.2),
                  between(., 41, 50) ~ c(0.5, 0.8),
                  between(., 51, 90) ~ c(0.8, 1),
                  between(., 91, 100) ~ c(0.2, 0.8),
                  TRUE ~ c(-0.1, 0))
) {

  # use 999 to map other temperatures to last case
  map(c(seq(from, to, by), 999), ~ case_when(!!!weights)) %>%
    set_names(c(map_chr(seq(from, to, by),
                      ~ str_c("temp_", ., "_", . + by - 1)), "temp_other")) %>%
  cross_df(.)

}

temp_weights <- create_temp_weights()
Run Code Online (Sandbox Code Playgroud)

使用用于构造权重的温度矢量创建小标题

test_tibble <- tibble(temp = seq_len(100))

head(test_tibble)
Run Code Online (Sandbox Code Playgroud)

以下case_when是我尝试使用权重数据帧以编程方式生成的内容。

library(rlang)
library(tidyverse)

create_temp_weights <- function(
  from = 31,
  to = 100,
  by = 10,
  weights = exprs(between(., 31, 40) ~ c(0, 0.2),
                  between(., 41, 50) ~ c(0.5, 0.8),
                  between(., 51, 90) ~ c(0.8, 1),
                  between(., 91, 100) ~ c(0.2, 0.8),
                  TRUE ~ c(-0.1, 0))
) {

  # use 999 to map other temperatures to last case
  map(c(seq(from, to, by), 999), ~ case_when(!!!weights)) %>%
    set_names(c(map_chr(seq(from, to, by),
                      ~ str_c("temp_", ., "_", . + by - 1)), "temp_other")) %>%
  cross_df(.)

}

temp_weights <- create_temp_weights()
Run Code Online (Sandbox Code Playgroud)

所以我要寻找的是一个case_when从权重数据帧构造参数的函数。

Aur*_*èle 1

密切模仿OP:

windows <- 
  str_extract_all(names(temp_weights), "\\d+") %>% 
  modify(as.integer) %>% 
  modify_if(negate(length), ~ c(-Inf, Inf)) %>% 
  set_names(names(temp_weights))

temp <- test_tibble$temp

res <-
  map_dfc(
    seq_len(nrow(temp_weights)), 
    ~ {
      row <- .
      rlang::eval_tidy(expr(case_when(
        !!! imap(
          windows, 
          ~ expr(
            between(temp, !! .x[1], !! .x[2]) ~ !! temp_weights[[.y]][row]
          )
        )
      )))
    }
  ) %>% 
  set_names(paste0("temp_wt_", seq_along(.)))

all.equal(res, test_tibble2)
#> [1] TRUE 
Run Code Online (Sandbox Code Playgroud)

稍微更有效(不对case_when每个重量组合重复):

res2 <- 
  rlang::eval_tidy(expr(case_when(
    !!! imap(
      windows, 
      ~ expr(
        between(temp, !! .x[1], !! .x[2]) ~ list(!! temp_weights[[.y]])
      )
    )
  ))) %>% 
  do.call(what = rbind) %>% 
  as_tibble() %>% 
  set_names(paste0("temp_wt_", seq_along(.)))

all.equal(res2, test_tibble2)
#> [1] TRUE   
Run Code Online (Sandbox Code Playgroud)