当我在本文中使用<code>dplyr::case_when<code>而不是<code>if<code>时,我注意到了下面的这种行为。如果第二个分支的输出是一个显式字符串,它将按预期工作,但如果指定了<code>x</code>本身,结果将发生变化。
为什么只有< code>case_when给出不同的结果?
x <- character(0)
dplyr::case_when(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ "Not empty")
#> [1] "Empty"
dplyr::case_when(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ x)
#> character(0)
if (rlang::is_empty(x)) "Empty" else if (!rlang::is_empty(x)) "Not empty"
#> [1] "Empty"
if (rlang::is_empty(x)) "Empty" else if (!rlang::is_empty(x)) x
#> [1] "Empty"
ifelse(rlang::is_empty(x), "Empty", "Not empty")
#> [1] "Empty"
ifelse(rlang::is_empty(x), "Empty", x)
#> [1] "Empty"
由reprex软件包(v2.0.1)于2022年8月16日创建
这是因为< code>case_when试图将所有公式循环到一个共同的长度。文件上说:
LHS 和 RHS 的长度可能相同,为 1 或 n。n 的值在所有情况下都必须一致。n == 0 的情况被视为 n != 1 的变体。
在你的第二个例子中,你提供了一个长度为0的向量作为其中一个公式的RHS,这就是返回长度为0的向量的原因;只是巧合,返回值和false case的RHS一样。
在考虑以下示例时,此行为似乎不那么令人惊讶:
library(dplyr, warn.conflicts = FALSE)
case_when(TRUE ~ 1, FALSE ~ numeric(0))
#> numeric(0)
case_when(TRUE ~ 1, FALSE ~ numeric(1))
#> [1] 1
case_when(TRUE ~ 1, FALSE ~ numeric(2))
#> [1] 1 1
case_when(TRUE ~ 1, FALSE ~ numeric(3))
#> [1] 1 1 1
case_when
和ifelse
之间的一个很大区别是,case_when
将右侧参数强制为相同的类型。从 ?case_when
:
RHS 不需要是合乎逻辑的,但所有 RHS 的计算结果都必须为相同类型的向量。
它还可能引发错误。
dplyr::case_when(rlang::is_empty(x) ~ 1, !rlang::is_empty(x) ~ "2")
# Error in names(message) <- `*vtmp*` :
# 'names' attribute [1] must be the same length as the vector [0]
dplyr::case_when(rlang::is_empty(x) ~ "1", !rlang::is_empty(x) ~ "2")
[1] "1"
这些信息肯定可以更具体。
如前所述,这并不能解释我认为case_when
源代码中的错误,特别是validate_case_when_length
:
m <- dplyr:::validate_case_when_length(query, value, fs, error_call = error_call)
在这种情况下会错误地返回0。
mycase_when <- function (...)
{
fs <- dplyr:::compact_null(rlang:::list2(...))
n <- length(fs)
error_call <- current_env()
if (n == 0) {
abort("No cases provided.", call = error_call)
}
query <- vector("list", n)
value <- vector("list", n)
default_env <- caller_env()
quos_pairs <- dplyr:::map2(fs, seq_along(fs), dplyr:::validate_formula, default_env = default_env,
dots_env = current_env(), error_call = error_call)
for (i in seq_len(n)) {
pair <- quos_pairs[[i]]
query[[i]] <- eval_tidy(pair$lhs, env = default_env)
value[[i]] <- eval_tidy(pair$rhs, env = default_env)
if (!is.logical(query[[i]])) {
abort_case_when_logical(pair$lhs, i, query[[i]],
error_call = error_call)
}
}
m <- dplyr:::validate_case_when_length(query, value, fs, error_call = error_call)
print(paste('m',m))
print(paste('value', value))
print(paste('value[[1]][1]', value[[1]][1]))
out <- value[[1]][rep(NA_integer_, m)]
replaced <- rep(FALSE, m)
print(paste('out 1',out))
for (i in seq_len(n)) {
out <- dplyr:::replace_with(out, query[[i]] & !replaced, value[[i]],
NULL, error_call = error_call)
replaced <- replaced | (query[[i]] & !is.na(query[[i]]))
}
# print(paste('out 2',out))
out
}
mycase_when(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ "Not empty")
mycase_when(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ x)
mycase_when(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ "Not empty")
[1] "m 1"
[1] "value Empty" "value Not empty"
[1] "value[[1]][1] Empty"
[1] "out 1 NA"
[1] "Empty"
mycase_when(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ x)
[1] "m 0"
[1] "value Empty" "value character(0)"
[1] "value[[1]][1] Empty"
[1] "out 1 "
character(0)
这可能是case_when
或其内部助手函数中的错误。我们可以在case_when
的源代码中放置浏览器
,以查看在这两种情况下会发生什么。某些内部函数必须通过:
调用。
f <- function (...) {
browser()
fs <- dplyr:::compact_null(rlang::list2(...))
n <- length(fs)
error_call <- rlang::current_env()
if (n == 0) {
abort("No cases provided.", call = error_call)
}
query <- vector("list", n)
value <- vector("list", n)
default_env <- rlang::caller_env()
quos_pairs <- purrr::map2(fs, seq_along(fs), dplyr:::validate_formula, default_env = default_env,
dots_env = rlang::current_env(), error_call = error_call)
for (i in seq_len(n)) {
pair <- quos_pairs[[i]]
query[[i]] <- rlang::eval_tidy(pair$lhs, env = default_env)
value[[i]] <- rlang::eval_tidy(pair$rhs, env = default_env)
if (!is.logical(query[[i]])) {
dplyr:::abort_case_when_logical(pair$lhs, i, query[[i]],
error_call = error_call)
}
}
m <- dplyr:::validate_case_when_length(query, value, fs, error_call = error_call)
out <- value[[1]][rep(NA_integer_, m)]
replaced <- rep(FALSE, m)
for (i in seq_len(n)) {
out <- dplyr:::replace_with(out, query[[i]] & !replaced, value[[i]],
NULL, error_call = error_call)
replaced <- replaced | (query[[i]] & !is.na(query[[i]]))
}
out
}
和 dplyr
中的助手内部replace_with
,
replacer <- function (x, i, val, name, reason = NULL, error_call = rlang::caller_env()) {
if (is.null(val)) {
return(x)
}
dplyr:::check_length(val, x, name, reason, error_call = error_call)
dplyr:::check_type(val, x, name, error_call = error_call)
dplyr:::check_class(val, x, name, error_call = error_call)
i[is.na(i)] <- FALSE
if (length(val) == 1L) {
x[i] <- val
}
else {
x[i] <- val[i]
}
x
}
然后通过
x <- character(0)
f(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ "x")
f(rlang::is_empty(x) ~ "Empty", !rlang::is_empty(x) ~ x)
关键在于值m
,即在工作情况下导致1L
的值,在故障情况下是0L
<代码>输出变为字符(0)
,而不是初始化为NA
,长度为1。
已替换
应为逻辑向量,指示值是否已替换。在故障情况下,rep(FALSE,0L)
是逻辑(0)
,稍后通过查询!已替换
<代码>错误
当传递给替换程序时
会给出一个特殊的子集操作字符(0)[logical(0)]
,即给出角色(0)
。
问题内容: 我尝试将matlab代码转换为numpy,并发现numpy与std函数的结果不同。 在matlab中 在numpy中 这正常吗?我应该如何处理呢? 问题答案: NumPy函数采用一个可选参数:“自由度增量”。默认情况下是。对其进行设置以获取MATLAB结果: 要添加更多上下文,在计算方差(标准偏差为平方根)时,通常将其除以我们拥有的值的数量。 但是,如果我们从较大的分布中选择元素的随机
这是一个优化问题,我正试图用我使用的opl代码来解决(稍微有点扭曲)。 opl代码为我提供了两种解决方案,即:{Product12,Product31} 当我使用docplex将此代码翻译为python语言时,我使用以下代码: 我明白了: ***问题没有解决方案 我不明白为什么我有不同的结果,有人能帮我吗? 先谢谢你。 当做
问题内容: 情况一: 输出: 2005年7月8日星期五00:00:00 GMT-0700(PST) 案例二: 输出: Thu Jul 07 2005 17:00:00 GMT-0700(PST) 为什么第二次解析不正确? 问题答案: 在第5版规范发布之前,该Date.parse方法完全依赖于实现(除后者返回数字而不是a之外,其他方法new Date(string)等效)。在第5版规范中,添加了该要
问题内容: 查看以下代码,并请解释为什么该方法和函数给出两个不同的输出。 输出: 问题答案: 计算子字符串的非重叠出现次数: 返回substring sub 的不重叠出现的次数。 在字符串中恰好有一个这样的子字符串出现的位置:就在开头。因此计数 应该 返回。 一般来说,空字符串将匹配给定字符串中的 所有位置 ,包括开始和结束处的正确 位置 ,因此计数应 始终 为长度加1: 这是因为空字符串被认为存
Java 中的字节长度为 8 位。一个
当我跑的时候。使用CPLEX的NET 4应用程序,我在不同的机器上得到不同的输出。在我的开发机器上,CPLEX输出一个结果(异常并卡在某个大值上),在所有其他机器上,结果都可以。 首先,我认为它与操作系统有关,因为我的开发机器上同时有视窗7 x64和视窗8 x64,所以我尝试在两个系统上运行应用程序。结果是一样的——有缺陷。 然后我试着在两台不同的台式机上运行,效果很好。我甚至在虚拟机内部进行了尝