R Function That Uses Its Output as Its Own Input Repeatedly

Relooping a function over its own output

A loop would work just fine here.

apply_fun_n_times <- function(input, fun, n){
for(i in 1:n){
input <- fun(input)
}
return(input)
}

addone <- function(x){x+1}

apply_fun_n_times(1, addone, 3)

which gives

> apply_fun_n_times(1, addone, 3)
[1] 4

Passing the output of a function back to the input multiple times

EDIT: After clarification

So, if it is some known (limited) number of times you would like to apply p in succession, this would be one way (I have assumed some simple functions for sp and bp for illustration):

sp <- function(x) return(x+1)
bp <- function(x) return(2*x)
p <- function(x) return(sp(bp(x)))

# Applying p 3 times in succession:
p_old <- 1
for (i in 1:3){
p_new = p(p_old)
p_old = p_new
}

p_new
#> [1] 15
# Which is the same as
p(p(p(1)))
#> [1] 15

Created on 2020-09-11 by the reprex package (v0.3.0)

I am not quite sure what use case you have in mind (because that can easily lead to an infinite "loop", but here is one (admittedly contrived) example of a function which sums some numbers regardless in how many lists they can be nested which is using a call of the same function in the function definition itself:

sum_of_c_or_list <- function(x){

if (!is.list(x)) return(sum(x))
else {
x = unlist(x)
x = sum_of_c_or_list(x)
return(x)
}
}
sum_of_c_or_list(1:3)
#> [1] 6
sum_of_c_or_list(list(1,2,3))
#> [1] 6
sum_of_c_or_list(list(list(1,2,3)))
#> [1] 6

Created on 2020-09-11 by the reprex package (v0.3.0)

Call function on its own output, N times

Is there a simple/fast way to do this

Yes, this is a trivial loop:

N = 3
for(i in 1:N) {
data = fun(data)
}

without using slow loops?

This is not slow.

Loops in R are slower than vectorized operations. However, since each iteration depends on the previous result, this cannot be vectorized. With R's JIT compilation, a for loop will likely be faster than common ways in R to hide loops, like *apply functions. And anyway, it's difficult to make most of the *apply functions update their inputs for successive iterations, as is needed here. (JIT compilation has been enabled by default for many years now.)

How to rbind output of repeated function to a df - vectorized

You can use lapply(), and do.call()

do.call(rbind, lapply(l1, f1))

Running a function repeatedly and appending its output

I am not sure if I understood you correctly. Do you want to do something like the following?

out <- lapply(X=1:10,FUN=function(x) ssa(x0, a, nu, tf=100)$data)

This would do 10 runs and put the resulting data lists in a list. You could then access,e.g., the data from the second run with out[[2]].

How to repeat a code for multiple times and store the output of each iteration in the same dataframe?

In the absence of a reproducible example, the following uses an example from the {Metrics} package documentation to construct your dataframe dp. Augment as appropriate.

Further you need to provide parameters to your function. In this case we supply the data frame dp (which you call in your function).

Lastly, replicate() returns an array/matrix. We reformat this into a "long" format and then coerce it to a data frame.

library(Metrics)

# simulate the data -----------------------------------------
actual <- c(1.1, 1.9, 3.0, 4.4, 5.0, 5.6)
predicted <- c(0.9, 1.8, 2.5, 4.5, 5.0, 6.2)

dp <- data.frame(
true_norm = actual
, dp_threshold_norm = predicted
)

# make function work -----------------------------------------
getValue <- function(dp) { # we define a parameter dp for the function
mae <- mae(dp$true_norm, dp$dp_threshold_norm)
rmse <- rmse(dp$true_norm, dp$dp_threshold_norm)
per_metrics <- c(mae,rmse)
return(per_metrics) # return value
}

# apply function multiple times with replicate()
# check this to understand the returned data format
replicate(n = 10, expr = getValue(dp))

# result ---------------------------------------------
## store in variable
result <- replicate(n = 10, expr = getValue(dp))

## coerce to "long data frame" - here we set ncol 2 for 2 variables
result <- matrix(result, ncol = 2)

## coerce to data frame
result <- as.data.frame.array(result)

This yields:

result

V1 V2
1 0.2500000 0.2500000
2 0.3341656 0.3341656
3 0.2500000 0.2500000
4 0.3341656 0.3341656
5 0.2500000 0.2500000
6 0.3341656 0.3341656
7 0.2500000 0.2500000
8 0.3341656 0.3341656
9 0.2500000 0.2500000
10 0.3341656 0.3341656

You can now rename the columns as required.

How can you apply a function repeatedly while updating the input

Use Reduce:

test_df %>% Reduce(function(...) separate_rows(..., sep = "_"), 2:3, init = .)

giving:

# A tibble: 26 x 3
x y z
<dbl> <chr> <chr>
1 1 10 1
2 1 10 2
3 1 10 3
4 1 10 4
5 1 10 5
6 1 11 1
7 1 11 2
8 1 11 3
9 1 11 4
10 1 11 5
# ... with 16 more rows

reduce from purrr also works (switch the first two args and use .init rather than init for that) but has no real advantage here.

How to pass the output of a function to another function in R?

There are quite a few things going on here, and it really partly depends on if you are showing us a very simplified version. For example, are you really doing the same thing to x, y, z in the first function or are you possibly doing different things?

First, the i, j and k vectors that you are creating in func1() do not exist outside of func1().
As @akrun said you could rectify this bye making them into a vector (if they are always of the same type) or a list and then returning that.

So then you could get, say,

func1 <- function(x, y, z) {
k <- x*2
j <- y*2
i <- z*2
c(k, j, i)
}

At which point you could a a parameter to your second function.

func2 <- function(x, y, z) {
ijk <- func1(x, y, z)
prod(ijk)

}

Of course even easier if you can vectorize func1() (but I don't know how much you simplified).

func1v2 <- function(x, y, z) {

2* c(k, j, i)
}



Related Topics



Leave a reply



Submit