Store values in For Loop - r

I have a for loop in R in which I want to store the result of each calculation (for all the values looped through). In the for loop a function is called and the output is stored in a variable r in the moment. However, this is overwritten in each successive loop. How could I store the result of each loop through the function and access it afterwards?
Thanks,
example
for (par1 in 1:n) {
var<-function(par1,par2)
c(var,par1)->var2
print(var2)
So print returns every instance of var2 but in var2 only the value for the last n is saved..is there any way to get an array of the data or something?

initialise an empty object and then assign the value by indexing
a <- 0
for (i in 1:10) {
a[i] <- mean(rnorm(50))
}
print(a)
EDIT:
To include an example with two output variables, in the most basic case, create an empty matrix with the number of columns corresponding to your output parameters and the number of rows matching the number of iterations. Then save the output in the matrix, by indexing the row position in your for loop:
n <- 10
mat <- matrix(ncol=2, nrow=n)
for (i in 1:n) {
var1 <- function_one(i,par1)
var2 <- function_two(i,par2)
mat[i,] <- c(var1,var2)
}
print(mat)
The iteration number i corresponds to the row number in the mat object. So there is no need to explicitly keep track of it.
However, this is just to illustrate the basics. Once you understand the above, it is more efficient to use the elegant solution given by #eddi, especially if you are handling many output variables.

To get a list of results:
n = 3
lapply(1:n, function(par1) {
# your function and whatnot, e.g.
par1*par1
})
Or sapply if you want a vector instead.
A bit more complicated example:
n = 3
some_fn = function(x, y) { x + y }
par2 = 4
lapply(1:n, function(par1) {
var = some_fn(par1, par2)
return(c(var, par1)) # don't have to type return, but I chose to make it explicit here
})
#[[1]]
#[1] 5 1
#
#[[2]]
#[1] 6 2
#
#[[3]]
#[1] 7 3

Related

Summing multiple values from a data frame using a loop

I have a single data frame data and a vector cryptos <- c("btc","eth","bnb","xrp") (where "btc" and etc. are the names of crypto currencies). I need to create a FOR loop that would sum the values of each coin.
So far, I've managed to 'return' every value with a print function:
cryptos <- c("btc","eth","bnb","xrp")
for(i in 1:4) {
print(data[data$crypto_name == cryptos[i], 3]) #where 3 is the number of a column with crypto values
}
So it prints the given currencies' values:
[1] 45065
[1] 2190.07
[1] 459.61
[1] 1.12
Yet, I do not want to print these values, just sum them with the use of a loop. Please tell me, how could I possibly do this.
Is this what you need?
sum( data[data$crypto_name %in% cryptos, 3] )
A basic sum loop is trival:
s = 0
for(i in 1:4) {
s = s + data[data$crypto_name == cryptos[i], 3]
}
s

Finding all combinations using recursion in R

I'm having issue with returning values from recursive functions, hoping you could help me out. I have a list with a bunch of matrices, each matrix representing a set of possible combinations and generated using combn(). As an example, this could be 3 matrices inside the list:
# set 1 has 4 elements, do nCk = 4C1:
set1 <- c("b2","b3","b4","b5")
set1 <- combn(set1,1,simplify = T)
# set 2 has 3 elements, choose 2:
set2 <- c("c1","c2","b2")
set2 <- combn(set2,2,simplify = T)
# set 3 has 10 elements, choose 1:
set3 <- combn(c(1:10),1, simplify = T)
If we were to print set2, for instance, it would have 2 rows (choose 2), and 3 columns (3C2 = 3):
> set2
[,1] [,2] [,3]
[1,] "c1" "c1" "c2"
[2,] "c2" "b2" "b2"
I need get all possible 4-element combinations (1 element per set above). I can do this using a while loop and simulating a state machine, but that solution is clunky and makes for long code. I know this can be done using recursion as I was able to print the 120 combinations correctly (code below), but when trying to return them or save them in a variable, either I get a <font color="red">subscript out of bounds error or the results repeat thousands of times. I want to avoid global variables too, this will be embedded in a rather large project, so I'd prefer to avoid bloating my workspace with more variables than needed.
Of course, when deployed the number of sets will be dynamic, and the elements per set will change too. The sets aren't too big either, so I would love to implement a recursive approach!
Working code to print:
combb <- function(allsets, number, carry){
if(number>length(allsets)){
print(carry)
return()
} else{
for(j in 1:length(allsets[[number]][1,])){
newcarry <- c(carry, allsets[[number]][,j])
number2 <- number + 1
combb(allsets, number2, newcarry)
}
}
}
Thank you!
I found that it was very hard to carry the results back and forth, as it required flags and lists or a different solution. What I did instead was create a wrapper function where I created a local variable. The recursive function is defined inside, and accesses ("globally") the variable mentioned above. Then, that variable is returned by the wrapper:
combb <- function(allsets){
carry <- integer(0)
height <- 0L
for (j in 1:length(allsets)) {
height <- height + length(allsets[[j]][, 1])
}
output <- matrix(allsets[[1]][0, 1], nrow = height, ncol = 0)
combb1 <- function(allsets, number, carry) {
if(number > length(allsets)){
output <<- cbind(output, carry, deparse.level = 0)
return()
} else{
for (j in 1:length(allsets[[number]][1,])) {
# Only add unique combinations (some combinations are vectors)
if((TRUE %in% (allsets[[number]][, j] %in% carry)) == FALSE) {
newcarry <- c(carry, allsets[[number]][, j], use.names = FALSE)
number2 <- number + 1
combb1(allsets, number2, newcarry)
} else{
next()
}
}
}
}
combb1(allsets, 1, carry)
return(output)
}
As you can see from that solution, recursion is neat (combb1 function) and doesn't clutter any of the global/workspace variables.

Transform a function into something that lapply works on properly (lists)

I'm trying to make a list with 10 elements, each element consisting of 5 * i items drawn from a uniform distribution, i being the ith entry, and I want to use lapply.
Currently I made this function:
z_list <- list()
z_list_generator <- function(n) {
for(i in 1:n){
a <- runif(5 * i)
tmp <- list(a)
mybiglist[[i]] <- tmp
}
mybiglist
}
This function does give the correct outcome when I just put z_list_generator(2), it prints a list with the first element consisting of 5 elements, the second of 10 elements.
What I want to achieve is that I do lapply(some number, z_list_generator) such that it generates this same list, and such that when I do length(lapply(some number, z_list_generator)), the outcome is 'some number'.
Do you mean something like this?
z_list_generator <- function(k) lapply(1:k, function(i) runif(5 * i))
set.seed(2018) # Fixed random seed for reproducibility
z_list_generator(2)
#[[1]]
#[1] 0.33615347 0.46372327 0.06058539 0.19743361 0.47431419
#
#[[2]]
# [1] 0.3010486 0.6067589 0.1300121 0.9586547 0.5468495 0.3956160 0.6645386
# [8] 0.9821123 0.6782154 0.8060278
length(z_list_generator(2))
#[1] 2
Your z_list_generator is strange.
1) You do not initialise mybiglist in your function code. It probably modifies some global variable.
2) You assign mybiglist elements with another list (of lenght 1), which first element contains a sample from a uniform distrubution. Better assign a, not tmp there.

For loops referring to differently numbered objects

in R I have a list of 100 phlyo objects called called Newick1, Newick2, Newick3, etc. I want to do pairwise comparisons between the trees (e.g. all.equal.phylo(Newick1, Newick2)) but am having difficulty figuring out how to do this efficiently since each file has a different name.
I think something like the for loop below will work, but how do I designate a different file for each iteration of the loop? For obvious reasons the [i] and [j] I put in the code below don't work, but I don't know what to replace them with.
Thank you very much!
for (i in 1:99) {
for (j in i+1:100) {
all.equal.phylo(Newick[i], Newick[j]) -> output[i,j]
} }
try mget() to reference multiple objects by name
> x1 <- x2 <- x3 <-1
> mget(paste0("x",1:3))
$x1
[1] 1
$x2
[1] 1
$x3
[1] 1
You can try a variation on the following:
# make a two column dataframe
# and filter the identical values
df <- expand.grid(1:100,1:100)
names(df) <- c('i','j')
df <- df[!df$i == df$j,]
# example function that takes two parameters
addtwo <- function(i,j){i + j}
# apply that function across rows of the dataframe
results <- mapply(addtwo, df$i, df$j)
# using the same logic,
# your function would look something like this
getdistance <- function(i,j, newicks=NEWICKS) {
all.equal.phylo(newicks[i], newicks[j])
}
# and apply it like this
results <- mapply(getdistance, df$i, df$j)
Key concepts:
expand.grid()
mapply()

How to change final result of loop as a data frame

x1=c(55,60,75,80)
x2=c(30,20,15,23)
x3=c(4,3,2,6)
x=data.frame(x1,x2,x3)
From this function :
NAins=function(x,alpha=0.3){
x.n=NULL
for (i in 1:ncol(x)){
S= sort(x[,i], decreasing=TRUE)
N= S[ceiling(alpha*nrow(x))]
x.n= ifelse(x[,i]>N, NA, x[,i])
print(x.n) }
}
How to save the final result as adataframe look like the original dataset ?however I used data.frame(x.nmar) .
and How to get the result out of the loop ?.
Better to use lapply here to avoid side effect of the for-loop:
NAins <- function(x,alpha=0.3){
Nr <- nrow(x)
lapply(x,function(col){
S <- sort(col, decreasing=TRUE)
N <- S[ceiling(alpha*Nr)]
ifelse(col>N, NA, col)
})
Then you can coerce the result to a data.frame:
as.data.frame(NAins(dx))
Converting the comment to answer
If you want to achieve this the loop way, you will need to predefine a matrix or a data frame and then fill it up (In your case you can just use your original x data.frame because the function will not update the original data set in the global environment). After the loop ends, you will need to return it because all the variables you've created within the function will be removed. print isn't being saved anywhere neither. Also, running ceiling(alpha*nrow(x)) in a loop doesn't make sense as it always stays the same. Neither the ifelse is needed if you only have a single alternative each time. See below
NAins=function(x, alpha = 0.3){
N <- ceiling(alpha * nrow(x)) ## Run this only once (take out of the loop)
for(i in 1:ncol(x)){
S <- sort(x[, i], decreasing = TRUE)
x[x[, i] > S[N], i] <- NA # don't use `ifelse`, you only inserting one value
}
x # return the result after the loop ends
}
Test
NAins(x)
# x1 x2 x3
# 1 55 NA 4
# 2 60 20 3
# 3 75 15 2
# 4 NA 23 NA

Resources