Putting user-defined on a list in for loop - r

I have problems storing user defined functions in R list when they are put on it in a for loop.
I have to define some segment-specific functions based on some parameters, so I create functions and put them on a list looping through segments with for-loop. The problem is I get same function everywhere on a result list.
The code looks like this:
n <- 100
segmenty <- 1:n
segment_functions <- list()
for (i in segmenty){
segment_functions[[i]] <- function(){return(i)}
}
When i run the code what I get is the same function (last created in the loop) for all indexes:
## for all k
segment_functions[[k]]()
[1] 100
There is no problem when I put the functions on list manually e.g.
segment_functions[[1]] <- function(){return(1)}
segment_functions[[2]] <- function(){return(2)}
segment_functions[[3]] <- function(){return(3)}
works just fine.
I honsetly have no idea what's wrong. Could you help?

You need to use the force function to ensure that the evaluation of i is done during the assignment into the list:
n <- 100
segmenty <- 1:n
segment_functions <- list()
f <- function(i) { force(i); function() return(i) }
for (i in segmenty){
segment_functions[[i]] <- f(i)
}

I'd use lapply and capture i in a clousre of the wrapper:
segment_functions <- lapply(1:100, function(i) function() i)

Related

Error message when using lapply to apply a function to multiple dataframes in a list.

My dataset looks like this, and I have a list of data.
Plot_ID Canopy_infection_rate DAI
1 YO01 5 7
2 YO01 8 14
3 YO01 10 21
What I want to do is to apply a function called "audpc_Canopyinfactionrate" to a list of dataframes.
However, when I run lapply, I get an error as below:
Error in FUN(X[[i]], ...) : argument "DAI" is missing, with no default
I've checked my list that my data does not shift a column.
Does anyone know what's wrong with it? Thanks
Here is part of my code:
#Read files in to list
for(i in 1:length(files)) {
lst[[i]] <- read.delim(files[i], header = TRUE, sep=" ")
}
#Apply a function to the list
densities <- list()
densities<- lapply(lst, audpc_Canopyinfactionrate)
#canopy infection rate
audpc_Canopyinfactionrate <- function(Canopy_infection_rate,DAI){
n <- length(DAI)
meanvec <- matrix(-1,(n-1))
intvec <- matrix(-1,(n-1))
for(i in 1:(n-1)){
meanvec[i] <- mean(c(Canopy_infection_rate[i],
Canopy_infection_rate[i+1]))
intvec[i] <- DAI[i+1] - DAI[i]
}
infprod <- meanvec * intvec
sum(infprod)
}
As pointed out in the comments, the problem lies in the way you are using lapply.
This function is built up like this: lapply(X, FUN, ...). FUN is the name of a function used to apply to the elements in a data.frame/list called X. So far so good.
Back to your case: You want to apply a function audpc_Canopyinfactionrate() to all data frames in lst. This function takes two arguments. And I think this is where things got mixed up in your code. Make sure you understand that in the way you are using lapply, you use lst[[1]], lst[[2]], etc. as the only argument in audpc_Canopyinfactionrate(), whereas it actually requires two arguments!
If you reformulate your function a bit, you can use lst[[1]], lst[[2]] as the only argument to your function, because you know that argument contains the columns you need - Canopy_infection_rate and DAI:
audpc_Canopyinfactionrate <- function(df){
n <- nrow(df)
meanvec <- matrix(-1, (n-1))
intvec <- matrix(-1, (n-1))
for(i in 1:(n-1)){
meanvec[i] <- mean(c(df$Canopy_infection_rate[i],
df$Canopy_infection_rate[i+1]))
intvec[i] <- df$DAI[i+1] - df$DAI[i]
}
infprod <- meanvec * intvec
return(sum(infprod))
}
Call lapply in the following way:
lapply(lst, audpc_Canopyinfactionrate)
Note: lapply can also be used with more than 1 argument, by using the ... in lapply(X, FUN, ...). In your case, however, I think this is not the best option.

R_ How to put a variable in a name

I have 50 files to read in R and I created this loop to help me. I would like to know if it is possible to do something like this in R.
How can I write it properly in R?
library(foreign)
for(i in 1:50 ){
tpi <- read.dbf('toto_%i%')
}
Help please.
We can do this using lapply
lst <- lapply(1:50, function(i) read.dbf(paste0("toto_", i)))
You want to use the function paste. As written your loop will overwrite tpi everytime it increments, so you will want to use a list to store the data.
toto = list()
for(i in 1:50)
{
toto[i] = read.dbf(paste0("toto_", i))
}
A shortcut using lapply gets the same results:
toto = lapply(1:50, function(x) read.dbf(paste0("toto_", x)))

R programming: save three dimensional outputs after loop

I am new to R and I would like to save the out puts after the loop
for (i in 1:5) {
for (d in 1:10) {
fonction1
fonction2
fonction3
}
}
At the end I would like to have 1 list-> contains 5 list-> contains 1*10 data frame -> contains certain number*3 numeric data. (I dont know if im saying it correctly, what i want to have is: like in Matlab, there is a 1*5 structure -> contains five 1*10 structure -> contain certain number*3 numeric data).
thanks in advance
Looks like you are looking after something like the following:
out <- list()
for (i in 1:5) {
outList <- list()
for (d in 1:10) {
outVect <- c()
outVect[1] <- fonction1()
outVect[2] <- fonction2()
outVect[3] <- fonction3()
outList[[d]] <- outVect
}
out[[i]] <- outList
}
Then you can look at:
str(out)
to see the structure of your answer
Try this:
lst <- lapply(1:5, function(i) {
lapply(1:10, function(d) {
data.frame(function1(),
function2(),
function3())
})
})
Assuming function1, function2 and function3 all return equal-length vectors, the above code should produce your desired object. You can use i and d identically as you would have used them in your for loop code.

Relooping a function over its own output

I have defined a function which I want to reapply to its own output multiple times. I tried
replicate(1000,myfunction)
but realised that this is just applying my function to my initial input 1000 times, rather than applying my function to the new output each time. In effect what I desire is:
function(function(...function(x_0)...))
1000 times over and being able to see the changes at each stage.
I have previous defined b as a certain vector of length 7.
b_0=b
C=matrix(0,7,1000)
for(k in 1:1000){
b_k=myfun(b_(k-1))
}
C=rbind(b_k)
C
Is this the right idea behind what I want?
You could use Reduce for this. For example
add_two <- function(a) a+2
ignore_current <- function(f) function(a,b) f(a)
Reduce(ignore_current(add_two), 1:10, init=4)
# 24
Normally Reduce expects to iterate over a set of new values, but in this case I use ignore_current to drop the sequence value (1:10) so that parameter is just used to control the number of times we repeat the process. This is the same as
add_two(add_two(add_two(add_two(add_two(add_two(add_two(add_two(add_two(add_two(4))))))))))
Pure functional programming approach, use Compose from functional package:
library(functional)
f = Reduce(Compose, replicate(100, function(x) x+2))
#> f(2)
#[1] 202
But this solution does not work for too big n ! Very interesting.
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
you can try a recursive function:
rec_func <- function(input, i=1000) {
if (i == 0) {
return(input)
} else {
input <- myfunc(input)
i <- i - 1
rec_func(input, i)
}
}
example
myfunc <- function(item) {item + 1}
> rec_func(1, i=1000)
[1] 1001

*apply in r to repeat a function

I've written a function that is a simulation, that outputs a vector of 100 elements, and I want to use the *apply functions to run the function many times and store the repeated output in a new vector for each time the simulation is run.
The function looks like:
J <- c(1:100)
species_richness <- function(J){
a <- table(J)
return(NROW(a))
}
simulation <- function(J,gens,ploton=FALSE,v=0.1){
species_richness_output <- rep(NA,gens)
for(rep in 1:gens){
index1 <- sample(1:length(J),1)
if(runif(1,0,1) < v){
J[index1] <- (rep+100)
}
else{
index2 <- sample(1:length(J),1)
while(index1==index2) {
index2 <- sample(1:length(J),1)
}
J[index1] <- J[index2]
}
species_richness_output[rep] <- species_richness(J)
}
species_abundance <- function(J){
a <- table(J)
return(a)
}
abuntable <- species_abundance(J)
print(abuntable)
octaves <- function(abuntable){
oct <- (rep(0,log2(sum(abuntable))))
for(i in 1:length(abuntable)){
oct2 <- floor(log2(abuntable[i])+1)
oct[oct2] <- oct[oct2]+1
}
print(oct)
}
# octaves(c(100,64,63,5,4,3,2,2,1,1,1,1))
if(ploton==TRUE){
hist(octaves(abuntable))
}
print(species_richness(J))
return(J)
}
simulation(J, 10000,TRUE,v=0.1)
So that's my function, it takes J a vector I defined earlier, manipulates it, then returns:
the newly simulated vector J of 100 elements
a function called octave that categorises the new vector
a histogram corresponding to the above "octave"
I have tried a number of variations: using lapply, mapply
putting args=args_from_original_simulation
simulation_repeated <- c(mapply(list, FUN=simulation(args),times=10000))
but I keep getting an error with the match.fun part of the mapply function
Error in match.fun(FUN) :
'simulation(J, 10000, FALSE, 0.1)' is not a function, character or symbol
This is despite the simulation I have written showing as being saved as a function in the workspace.
Does anyone know what this error is pointing to?
In this line:
simulation_repeated <- c(mapply(list, FUN=simulation(args),times=10000))
You are not giving a function to mapply. You are (essentially) passing the result of calling simulation(args) and simulation does not return a function.

Resources