繁体   English   中英

试图在 R 中编写分段 function

[英]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)

谢谢你

三个问题:

  1. 当直接用作 function 调用的参数列表的一部分时, =不是赋值运算符,它是命名 arguments 的语法。
  2. 不要尝试ifelse() function 调用参数列表中分配,而是分配结果
  3. 您当前正在执行三个不同的计算。 真的,你只想执行一个。 要解决此问题,您需要嵌套调用:
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 的回答

关于问题中的代码:

  1. 分配应该在 ifelse 之外完成,而不是在里面

  2. ifelse 将首先评估所有值的两条腿,所以如果你传递一个负数a它会尝试取负数的平方根,即使没有选择这条腿。 因此,最好避免在此处完全使用ifelse

  3. 嵌套的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM