R dplyr::mutate ifelse 以全局变量为条件回收第一行的结果
R dplyr::mutate with ifelse conditioned on a global variable recycles result from first row
我很好奇为什么 dplyr::mutate()
调用中的 ifelse()
语句似乎只适用于我的数据框的第一行。这 returns 是一个单一的值,它在整个列中循环使用。由于在 ifelse()
的任何一种情况下评估的表达式仅在我的数据框的上下文中有效,我希望条件检查和结果表达式评估将作为一个整体在列上执行,而不仅仅是它们的第一个元素.
这是一个示例:我在数据框外定义了一个名为 checkVar
的变量。根据 checkVar
的值,我想在新列 z
中向我的数据框添加不同的值,这些值是作为现有列的函数计算的。
如果我这样做
checkVar <- 1
df <- data.frame( x=11:15, y=1:5 ) %>%
dplyr::mutate( z=ifelse(checkVar == 1, x/y, x-y) )
df
它returns
x y z
1 11 1 11
2 12 2 11
3 13 3 11
4 14 4 11
5 15 5 11
不是每行的 z 是 x 和 y 的商,而是用数据框第一行的 x 和 y 的商填充所有行。
但是,如果我指定 rowwise()
,我会得到我想要的结果:
df <- df %>%
dplyr::rowwise() %>%
dplyr::mutate( z=ifelse(checkVar == 1, x/y, x-y) ) %>%
dplyr::ungroup()
df
returns
# A tibble: 5 x 3
x y z
<int> <int> <dbl>
1 11 1 11.000000
2 12 2 6.000000
3 13 3 4.333333
4 14 4 3.500000
5 15 5 3.000000
当 x
和 y
仅定义为我的数据框的列时,为什么我必须明确指定 rowwise()
?
这与 dplyr::mutate
无关,但与 ifelse
的工作原理有关,这里是文档 ?ifelse:
ifelse returns a value with the same shape as test which is filled
with elements selected from either yes or no depending on whether the
element of test is TRUE or FALSE.
Usage
ifelse(test, yes, no)
和示例:
ifelse(T, c(1,2,3), c(2,3,4))
# [1] 1
您的第一个案例是向量化的,ifelse
将向量 x/y
和 x-y
作为 yes
和 no
参数,因为 checkVar == 1
returns TRUE(标量),ifelse
returns (x/y)[1]
,即向量 x/y
的第一个元素,即 11 并回收以填充新列 z
;
在你的第二种情况下,mutate
和 ifelse
每行执行一次,所以它被评估 五次 次,每次 returns该行的 x/y
值。
如果你的条件是标量,那么就不需要向量化ifelse
,if/else
更适合用:
checkVar <- 1
mutate(df, z = if(checkVar == 1) x/y else x-y)
# x y z
#1 11 1 11.000000
#2 12 2 6.000000
#3 13 3 4.333333
#4 14 4 3.500000
#5 15 5 3.000000
我很好奇为什么 dplyr::mutate()
调用中的 ifelse()
语句似乎只适用于我的数据框的第一行。这 returns 是一个单一的值,它在整个列中循环使用。由于在 ifelse()
的任何一种情况下评估的表达式仅在我的数据框的上下文中有效,我希望条件检查和结果表达式评估将作为一个整体在列上执行,而不仅仅是它们的第一个元素.
这是一个示例:我在数据框外定义了一个名为 checkVar
的变量。根据 checkVar
的值,我想在新列 z
中向我的数据框添加不同的值,这些值是作为现有列的函数计算的。
如果我这样做
checkVar <- 1
df <- data.frame( x=11:15, y=1:5 ) %>%
dplyr::mutate( z=ifelse(checkVar == 1, x/y, x-y) )
df
它returns
x y z
1 11 1 11
2 12 2 11
3 13 3 11
4 14 4 11
5 15 5 11
不是每行的 z 是 x 和 y 的商,而是用数据框第一行的 x 和 y 的商填充所有行。
但是,如果我指定 rowwise()
,我会得到我想要的结果:
df <- df %>%
dplyr::rowwise() %>%
dplyr::mutate( z=ifelse(checkVar == 1, x/y, x-y) ) %>%
dplyr::ungroup()
df
returns
# A tibble: 5 x 3
x y z
<int> <int> <dbl>
1 11 1 11.000000
2 12 2 6.000000
3 13 3 4.333333
4 14 4 3.500000
5 15 5 3.000000
当 x
和 y
仅定义为我的数据框的列时,为什么我必须明确指定 rowwise()
?
这与 dplyr::mutate
无关,但与 ifelse
的工作原理有关,这里是文档 ?ifelse:
ifelse returns a value with the same shape as test which is filled with elements selected from either yes or no depending on whether the element of test is TRUE or FALSE.
Usage
ifelse(test, yes, no)
和示例:
ifelse(T, c(1,2,3), c(2,3,4))
# [1] 1
您的第一个案例是向量化的,ifelse
将向量 x/y
和 x-y
作为 yes
和 no
参数,因为 checkVar == 1
returns TRUE(标量),ifelse
returns (x/y)[1]
,即向量 x/y
的第一个元素,即 11 并回收以填充新列 z
;
在你的第二种情况下,mutate
和 ifelse
每行执行一次,所以它被评估 五次 次,每次 returns该行的 x/y
值。
如果你的条件是标量,那么就不需要向量化ifelse
,if/else
更适合用:
checkVar <- 1
mutate(df, z = if(checkVar == 1) x/y else x-y)
# x y z
#1 11 1 11.000000
#2 12 2 6.000000
#3 13 3 4.333333
#4 14 4 3.500000
#5 15 5 3.000000