[英]trying to write a piecewise function in R
我对 R 还很陌生,想写一个分段 function,我的代码不起作用,如果你能帮忙请评论:
a<-rnorm(1000)
ifelse(0<a & a<=.3,C=sqrt(30*a),NA)
ifelse(.3<a & a<=.7,C=5*a+15/10),NA)
ifelse(.7<a & a<=1,c=8-sqrt(-30*a+30),NA)
谢谢你
三个问题:
=
不是赋值运算符,它是命名 arguments 的语法。ifelse()
function 调用参数列表中分配,而是分配结果c = ifelse(
0 < a & a <= 0.3, sqrt(30 * a),
ifelse(
0.3 < a & a <= 0.7, 5 * a + 15 / 10,
ifelse(0.7 < a & a <= 1, 8 - sqrt(-30 * a + 30), NA)
)
)
但是,这不是很可读。 您可以使用 'dplyr' package 中的case_when()
来使代码更具可读性:
c = case_when(
0 < a & a <= 0.3 ~ sqrt(30 * a),
0.3 < a & a <= 0.7 ~ 5 * a + 15 / 10
0.7 < a & a <= 1 ~ 8 - sqrt(-30 * a + 30)
TRUE ~ NA
)
这两种解决方案都有一个不幸的副作用,即由于 NaN 值(由计算负数平方根的代码引起)而引发警告。 有关解决此问题的方法,请参阅G. Grothendieck 的回答。
关于问题中的代码:
分配应该在 ifelse 之外完成,而不是在里面
ifelse 将首先评估所有值的两条腿,所以如果你传递一个负数a
它会尝试取负数的平方根,即使没有选择这条腿。 因此,最好避免在此处完全使用ifelse
。
嵌套的 ifelse 可能很难遵循。
以下解决方案避免ifelse
。 第一个使用 if... else... 。 与ifelse
不同,它只评估实际使用的腿。 它仅适用于标量,但我们可以使用Vectorize
将我们写入的标量 function 转换为接受向量的 function。
第二种解决方案将a
的值从其他值中分离出来,它们介于 0 和 1 之间,这样我们就永远不会尝试对负数取平方根,因此 NA 不参与主计算。 它使用成语 cond1 * y1 + cond2 * y2 +... 其中 y1, y2, ... 是数字非 NA 表达式,而 cond1, cond2, ... 是互斥条件。 对于每个向量分量,只有一个条件为 TRUE,因此 R 将相应的表达式乘以 1 保持它,而其他表达式乘以 0 消除它们。
1)使用 if/else 并将其矢量化。 这甚至适用于 a 的负值而不发出警告,否则可能由于负平方根而发出警告并且不使用包。
f <- Vectorize(function(a)
if (0 < a & a <= 0.3) sqrt(30 * a)
else if (0.3 < a & a <= 0.7) 5 * a + 15 / 10
else if (0.7 < a & a <= 1) 8 - sqrt(-30 * a + 30)
else NA)
a <- seq(0, 1, 0.01)
c <- f(a)
head(c)
## [1] NA 0.5477226 0.7745967 0.9486833 1.0954451 1.2247449
tail(c)
## [1] 6.775255 6.904555 7.051317 7.225403 7.452277 8.000000
plot(c ~ a, type = "l")
2)另一种方法是以矢量化方式进行,但单独处理导致 NA 的值,以便它永远不会尝试取负数的平方根。 同样,这不使用任何包。
f2 <- function(x) {
ix <- x > 0 & x <= 1
a <- x[ix]
replace(NA * x, ix, (0 < a & a <= 0.3) * sqrt(30 * a) +
(0.3 < a & a <= 0.7) * (5 * a + 15 / 10) +
(0.7 < a & a <= 1) * (8 - sqrt(-30 * a + 30)))
}
# test
c2 <- f(a)
identical(c, c2)
## [1] TRUE
在 10 之后的第二个ifelse
语句中有一个额外的括号。您可以删除它或添加另一对。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.