过时的数据掩码。在 `dplyr::mutate()` 结束后解析 `xxxxxx` 为时已晚
Obsolete data mask. Too late to resolve `xxxxxx` after the end of `dplyr::mutate()`
作为我对 的回答的一部分,我提出了一种完全通用的机制,通过该机制,一个数据帧可以根据存储在另一个数据帧中的条件进行过滤。 OP 叫我出去(该死的!)并要求我实施。
我的解决方案要求我将 函数 存储在过滤器数据框中。这是可能的: 显示如何。
作为一个基本示例,请考虑
library(tidyverse)
longFilterTable <- tribble(
~var, ~value,
"gear", list(3),
) %>%
mutate(
func=pmap(
list(value),
~function(x) x == ..1[[1]]
)
)
longFilterTable
# A tibble: 1 x 3
var value func
<chr> <list> <list>
1 gear <list [1]> <fn>
这是一种非常复杂的说法,即“select 只有 mtcars
的那些行 gear
是 3
。这行得通:
mtcars %>% filter(longFilterTable$func[[1]](gear)) %>% head(3)
mpg cyl disp hp drat wt qsec vs am gear carb
Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
<11 rows deleted for brevity>
现在假设我希望标准更加灵活。例如,我可能想要 select 一个值范围或一个固定值。这似乎是上面过滤器数据集的合理扩展:
longFilterTable <- tribble(
~var, ~value, ~condition,
"gear", list(3), "equal",
"wt", list(3,4, 3.9), "range",
) %>%
mutate(
func=pmap(
list(value, condition),
~function(x) {
case_when(
condition == "equal" ~ x == ..1[[1]],
condition == "range" ~ x >= ..1[[1]][1] & x <= ..1[[1]][2],
TRUE ~ x
)
}
)
)
longFilterTable
# A tibble: 2 x 4
var value condition func
<chr> <list> <chr> <list>
1 gear <list [1]> equal <fn>
2 wt <list [3]> range <fn>
但现在当我尝试应用过滤器时,我得到:
mtcars %>% filter(longFilterTable$func[[1]](gear))
Show Traceback
Rerun with Debug
Error: Problem with `filter()` input `..1`.
x Obsolete data mask.
x Too late to resolve `condition` after the end of `dplyr::mutate()`.
ℹ Did you save an object that uses `condition` lazily in a column in the `dplyr::mutate()` expression ?
ℹ Input `..1` is `longFilterTable$func[[1]](gear)`.
我试过 deparse()
、substitute()
、expression()
、force()
和 eval()
的各种组合,但无济于事。谁能找到解决方案?
您的问题是 case_when
的所有选项总是被评估并检查正确的输出格式
x <- 1
dplyr::case_when(x < 2 ~ TRUE,
x < 0 ~ FALSE)
#> [1] TRUE
dplyr::case_when(x < 2 ~ TRUE,
x < 0 ~ stop())
#> Error in eval_tidy(pair$rhs, env = default_env):
在你的例子中,你想使用第一个选项,检查是否相等。然而,范围条件也被评估,但没有第二个值存储在 value
列表中,结果只是 NA
s 的向量,因此错误。从 case_when
切换到常规 if else 子句可以解决此问题。
library(purrr)
library(dplyr)
longFilterTable <- tribble(
~var, ~value, ~condition,
"gear", list(3), "equal",
"wt", list(3.4, 3.9), "range",
) %>%
mutate(
func=pmap(
list(value, condition),
~function(x) {
if(..2 == "equal") x == ..1[[1]]
else if (..2 == "range") x >= ..1[[1]] & x <= ..1[[2]]
else TRUE
}
)
)
mtcars %>% filter(longFilterTable$func[[2]](drat))
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
作为我对
我的解决方案要求我将 函数 存储在过滤器数据框中。这是可能的:
作为一个基本示例,请考虑
library(tidyverse)
longFilterTable <- tribble(
~var, ~value,
"gear", list(3),
) %>%
mutate(
func=pmap(
list(value),
~function(x) x == ..1[[1]]
)
)
longFilterTable
# A tibble: 1 x 3
var value func
<chr> <list> <list>
1 gear <list [1]> <fn>
这是一种非常复杂的说法,即“select 只有 mtcars
的那些行 gear
是 3
。这行得通:
mtcars %>% filter(longFilterTable$func[[1]](gear)) %>% head(3)
mpg cyl disp hp drat wt qsec vs am gear carb
Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
<11 rows deleted for brevity>
现在假设我希望标准更加灵活。例如,我可能想要 select 一个值范围或一个固定值。这似乎是上面过滤器数据集的合理扩展:
longFilterTable <- tribble(
~var, ~value, ~condition,
"gear", list(3), "equal",
"wt", list(3,4, 3.9), "range",
) %>%
mutate(
func=pmap(
list(value, condition),
~function(x) {
case_when(
condition == "equal" ~ x == ..1[[1]],
condition == "range" ~ x >= ..1[[1]][1] & x <= ..1[[1]][2],
TRUE ~ x
)
}
)
)
longFilterTable
# A tibble: 2 x 4
var value condition func
<chr> <list> <chr> <list>
1 gear <list [1]> equal <fn>
2 wt <list [3]> range <fn>
但现在当我尝试应用过滤器时,我得到:
mtcars %>% filter(longFilterTable$func[[1]](gear))
Show Traceback
Rerun with Debug
Error: Problem with `filter()` input `..1`.
x Obsolete data mask.
x Too late to resolve `condition` after the end of `dplyr::mutate()`.
ℹ Did you save an object that uses `condition` lazily in a column in the `dplyr::mutate()` expression ?
ℹ Input `..1` is `longFilterTable$func[[1]](gear)`.
我试过 deparse()
、substitute()
、expression()
、force()
和 eval()
的各种组合,但无济于事。谁能找到解决方案?
您的问题是 case_when
的所有选项总是被评估并检查正确的输出格式
x <- 1
dplyr::case_when(x < 2 ~ TRUE,
x < 0 ~ FALSE)
#> [1] TRUE
dplyr::case_when(x < 2 ~ TRUE,
x < 0 ~ stop())
#> Error in eval_tidy(pair$rhs, env = default_env):
在你的例子中,你想使用第一个选项,检查是否相等。然而,范围条件也被评估,但没有第二个值存储在 value
列表中,结果只是 NA
s 的向量,因此错误。从 case_when
切换到常规 if else 子句可以解决此问题。
library(purrr)
library(dplyr)
longFilterTable <- tribble(
~var, ~value, ~condition,
"gear", list(3), "equal",
"wt", list(3.4, 3.9), "range",
) %>%
mutate(
func=pmap(
list(value, condition),
~function(x) {
if(..2 == "equal") x == ..1[[1]]
else if (..2 == "range") x >= ..1[[1]] & x <= ..1[[2]]
else TRUE
}
)
)
mtcars %>% filter(longFilterTable$func[[2]](drat))
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1