[SOLVED] How can a make the sum of two step functions (R-stepfun) of class "stepfun"?

Issue

From the example here I tried to make the sum as class "stepfun". I thought, as.stepfun is the right choice, but my ideas don’t work. What is wrong?

y1 <- c(0, 1, 2, 0)
x1 <- c(1, 2, 3)
f1 <- stepfun(x = x1, y = y1)
print(class(f1))
# [1] "stepfun"  "function" #  OK!!!
plot(f1)

y2 <- c(0, 1, 0)
x2 <- c(1.5, 2.5)
f2 <- stepfun(x = x2, y = y2)
plot(f2)

fs <- function(x, f1, f2) {
  # y <- f1(x) + f2(x) #  OK
  # y <- as.stepfun(x = x, y = y, ties = "ordered", right = FALSE) # does not work
  # return(y) #           does not work
  return(f1(x) + f2(x))
}
print(class(fs)) # [1] "function"
# attributes(fs) # no new information...

fm <- function(x, f1, f2) {
  return(f1(x) * f2(x))
}
print(class(fm)) # [1] "function"

Example as. for data.frame which works as expected:

z <- c(1, 2)
class(z) #    [1] "numeric"
class(as.data.frame(z)) #    [1] "data.frame"

About internals of stepfun

function (x, y, f = as.numeric(right), ties = "ordered", right = FALSE) 
{
  if (is.unsorted(x)) 
    stop("stepfun: 'x' must be ordered increasingly")
  n <- length(x)
  if (n < 1) 
    stop("'x' must have length >= 1")
  n1 <- n + 1L
  if (length(y) != n1) 
    stop("'y' must be one longer than 'x'")
  rval <- approxfun(x, y[-if (right) 
    n1
  else 1], method = "constant", yleft = y[1L], yright = y[n1], 
    f = f, ties = ties)
  class(rval) <- c("stepfun", class(rval))
  attr(rval, "call") <- sys.call()
  rval
}

Solution

Thanks to the answers from @jblood94, @user2554330 and @rbm here I found an elegant way which I plan to use in my case. I hope that also helps others:

par(mfrow = c(2, 2))
y1 <- c(0, 1, 2, 0)
x1 <- c(1, 2, 3)
f1 <- stepfun(x = x1, y = y1)

y2 <- c(0, 1, 0)
x2 <- c(1.5, 2.5)
f2 <- stepfun(x = x2, y = y2)

plot(f1)
plot(f2)

'+.stepfun' <- function(f1, f2) {
  xs1 <- get("x", envir = environment(f1))
  xs2 <- get("x", envir = environment(f2))
  xs <- sort(unique(c(x1, x2)))
  ys <- f1(c(xs[1] - 1, xs)) + f2(c(xs[1] - 1, xs))
  return(stepfun(x = xs, y = ys))
}
f1 + f2
print(class(f1 + f2))
plot(f1 + f2, main = "Sum f1+f2")

'*.stepfun' <- function(f1, f2) {
  xs1 <- get("x", envir = environment(f1))
  xs2 <- get("x", envir = environment(f2))
  xs <- sort(unique(c(x1, x2)))
  ys <- f1(c(xs[1] - 1, xs)) * f2(c(xs[1] - 1, xs))
  return(stepfun(x = xs, y = ys))
}
f1 * f2
print(class(f1 * f2))
plot(f1 * f2, main = "Sum f1*f2")

par(mfrow = c(1, 1))

Answered By – Christoph

Answer Checked By – Jay B. (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *