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从权重数据帧构造参数的函数。
密切模仿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)