我有两组变量,例如变量 a
和变量 a_avail
。我正在尝试根据 a
的值更改 a_avail
的值,并且想知道是否可以将 across
与 glue
一起使用。
这是我尝试过的。没有产生错误,但由于所有返回的值都是 NA,因此胶水似乎没有获取 .x_avail
的值:
library(tidyverse)
df <- tibble(a = c(0, 1, 0, 0, 0),
a_avail = c(1, 1, 1, 0, 0),
b = c(1, 1, 1, 0, 0),
b_avail = c(1, 0, 0, 1, 0))
df2 <- df %>%
mutate(across(.cols = c(a, b),
.fns = ~case_when(
glue::glue("{.x}_avail") == 1 ~ .x,
glue::glue("{.x}_avail") == 0 ~ as.numeric(NA)
),
.names = "{.col}_new"))
df2
#> # A tibble: 5 x 6
#> a a_avail b b_avail a_new b_new
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 0 1 1 1 NA NA
#> 2 1 1 1 0 NA NA
#> 3 0 1 1 0 NA NA
#> 4 0 0 0 1 NA NA
#> 5 0 0 0 0 NA NA
由 reprex package (v0.3.0) 于 2021 年 2 月 12 日创建
答案 0 :(得分:2)
不是 tidyverse 解决方案,但这应该可行
library(tidyverse)
df <- tibble(a = c(0, 1, 0, 0, 0),
a_avail = c(1, 1, 1, 0, 0),
b = c(1, 1, 1, 0, 0),
b_avail = c(1, 0, 0, 1, 0))
v1 <- list('a','b')
v2 <- list('a_avail','b_avail')
v3 <- as.data.frame(mapply(function(x,y){ifelse(df[[y]] == 0, NA,df[[x]])} , v1,v2,
SIMPLIFY = TRUE))
names(v3) <- paste0(v1,"_new")
df3 <- cbind(df, v3)
答案 1 :(得分:2)
您遇到的主要问题是引用列本身,而不仅仅是将字符串(或 glue
对象)与数字进行比较。您可能会组合一个 tidyeval 函数,但(可能)更简单的方法是将数据重新整形为长格式,以便为原始值提供一列,为可用性提供一列,在新列中添加比较,然后重新整形.这也将进行缩放,因此您不必指定要执行此操作的所有列,或手动准确匹配原始数据。
第一个技巧是用某种方式标记原始列,这样您就可以拆分例如"a"
来自 "avail"
。为此,将另一个字符串附加到只有单个字符的名称上。 (您可以使用不同的方法来选择列。)使用 ID 标记行——您可以稍后删除此列。第二个技巧是在枢轴函数中使用特殊的 ".value"
项。
我建议您一步一步地完成重塑步骤,看看它们是如何工作的,并根据需要进行调整。
library(dplyr)
library(tidyr)
df %>%
rename_with(~paste(., "orig", sep = "_"), matches("^[a-z]$")) %>%
tibble::rowid_to_column() %>%
pivot_longer(-rowid, names_to = c("col", ".value"), names_sep = "_") %>%
mutate(new = if_else(avail == 1, orig, NA_real_)) %>%
pivot_wider(id_cols = rowid, names_from = col, values_from = orig:new,
names_glue = "{col}_{.value}")
#> # A tibble: 5 x 7
#> rowid a_orig b_orig a_avail b_avail a_new b_new
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 0 1 1 1 0 1
#> 2 2 1 1 1 0 1 NA
#> 3 3 0 1 1 0 0 NA
#> 4 4 0 0 0 1 NA 0
#> 5 5 0 0 0 0 NA NA
答案 2 :(得分:2)
我认为通过 purrr
包可以轻松实现您想要的输出。在某种程度上,我们使用 across
函数而不是使用 map2
,因为我们同时处理 2 个变量,并且为了我们的目的,我们希望逐行迭代它们:
library(dplyr)
library(purrr)
df <- tibble(a = c(0, 1, 0, 0, 0),
a_avail = c(1, 1, 1, 0, 0),
b = c(1, 1, 1, 0, 0),
b_avail = c(1, 0, 0, 1, 0))
df %>%
mutate(a_new = map2_dbl(a, a_avail, ~ ifelse(.y == 1, .x, NA)),
b_new = map2_dbl(b, b_avail, ~ ifelse(.y == 1, .x, NA)))
# A tibble: 5 x 6
a a_avail b b_avail a_new b_new
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0 1 1 1 0 1
2 1 1 1 0 1 NA
3 0 1 1 0 0 NA
4 0 0 0 1 NA 0
5 0 0 0 0 NA NA
在这种情况下,最好仔细考虑哪个函数最能满足您的目的,并与您提供的参数集最匹配。在这里,由于我们处理的是按行操作,因此我更愿意使用 purrr
包函数。
答案 3 :(得分:2)
Ronak Shah 在他对相关 answer 的 question 中提出了一种绝妙的方法,我将在下面复制。
其实就是两件事
mutate(across..
内使用列/变量名而不是值 cur_column()
应与 .
或 .x
相对。get()
也可以与 glue
一起使用,以便 R 将其识别为变量。这样做
df %>%
mutate(across(.cols = c(a, b),
.fns = ~case_when(
get(glue::glue("{cur_column()}_avail")) == 1 ~ .x,
get(glue::glue("{cur_column()}_avail")) == 0 ~ NA_real_
),
.names = "{.col}_new"))
# A tibble: 5 x 6
a a_avail b b_avail a_new b_new
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0 1 1 1 0 1
2 1 1 1 0 1 NA
3 0 1 1 0 0 NA
4 0 0 0 1 NA 0
5 0 0 0 0 NA NA