I've created a simple loop to calculate the efficiency of some simulated data. It performs perfectly well whilst as a loop:
NSE_cal <- NULL
for(i in 1:6) {
Qobs <- flowSummary_NSE1[[i]][[3]]
Qsim <- flowSummary_NSE1[[i]][[1]]
object_cal <- NSEsums("NSE")
NSE_cal <- c(NSE_cal, object_cal)
}
#NSE_cal
#[1] 0.8466699 0.7577019 0.8128499 0.9163561 0.7868013 0.8462228
However, I want to apply this loop quite a few times - I need to vary the object flowSummary_NSE# and I have four different transformation types to apply. As a start, I put the loop inside a function, with only transformation needing to be specified, like so:
badFunction <- function(transformation){
NSE_cal <- NULL
for(i in 1:6) {
Qobs <- flowSummary_NSE1[[i]][[3]]
Qsim <- flowSummary_NSE1[[i]][[1]]
object_cal <- NSEsums(transformation)
NSE_cal <- c(NSE_cal, object_cal)
}
print(NSE_cal)
}
badFunction("NSE")
# [1] 0.8462228 0.8462228 0.8462228 0.8462228 0.8462228 0.8462228
The function has exactly the same information input as in the for loop on its own, except, for some reason, it outputs the same value for each case of i.
It is clear that I have done something wrong. But as far as I can see, it must be something simple contained to the function itself. However, incase it is an error elsewhere, I have attached the code that generates the necessary data and dependent functions (here)
Any help would be much appreciated
You need to pass objects into the nested function as arguments.
In your function_NSEsums.r script change the first line to NSEsums <- function(i, Qobs, Qsim) {
In your example_script.r change your code to the following:
badFunction <- function(transformation){
NSE_cal <- NULL
for(i in 1:6) {
Qobs <- flowSummary_NSE1[[i]][[3]]
Qsim <- flowSummary_NSE1[[i]][[1]]
object_cal <- NSEsums(transformation, Qobs = Qobs, Qsim = Qsim)
NSE_cal <- c(NSE_cal, object_cal)
}
print(NSE_cal)
}
badFunction("NSE")
[1] 0.8466699 0.7577019 0.8128499 0.9163561 0.7868013 0.8462228
Related
I regularly come up against the issue of how to categorise dataframes from a list of dataframes according to certain values within them (E.g. numeric, factor strings, etc). I am using a simplified version using vectors here.
After writing messy for loops for this task a bunch of times, I am trying to write a function to repeatedly solve the problem. The code below returns a subscripting error (given at the bottom), however I don't think this is a subscripting problem, but to do with my use of return.
As well as fixing this, I would be very grateful for any pointers on whether there are any cleaner / better ways to code this function.
library(plyr)
library(dplyr)
#dummy data
segmentvalues <- c('1_P', '2_B', '3_R', '4_M', '5_D', '6_L')
trialvec <- vector()
for (i in 1:length(segmentvalues)){
for (j in 1:20) {
trialvec[i*j] <- segmentvalues[i]
}
}
#vector categorisation
vcategorise <- function(categories, data) {
#categorises a vector into a list of vectors
#requires plyr and dyplyr
assignment <- list()
catlength <- length(categories)
for (i in 1:length(catlength)){
for (j in 1:length(data)) {
if (any(contains(categories[i], ignore.case = TRUE,
as.vector(data[j])))) {
assignment[[i]][j] <- data[j]
}
}
}
return (assignment)
}
result <- vcategorise(categories = segmentvalues, data = trialvec)
Error in *tmp*[[i]] : subscript out of bounds
You are indexing assignments -- which is ok, even if at an index that doesn't have a value, that just gives you NULL -- and then indexing into what you get there -- which won't work if you get NULL. And NULL you will get, because you haven't allocated the list to be the right size.
In any case, I don't think it is necessary for you to allocate a table. You are already using a flat indexing structure in your test data generation, so why not do the same with assignment and then set its dimensions afterwards?
Something like this, perhaps?
vcategorise <- function(categories, data) {
assignment <- vector("list", length = length(data) * length(categories))
n <- length(data)
for (i in 1:length(categories)){
for (j in 1:length(data)) {
assignment[(i-1)*n + j] <-
if (any(contains(categories[i],
ignore.case = TRUE,
as.vector(data[j])))) {
data[j]
} else {
NA
}
}
}
dim(assignment) <- c(length(data), length(categories))
assignment
}
It is not the prettiest code, but without fully understanding what you want to achieve, I don't know how to go further.
I'm trying to save each iteration of this for loop in a vector.
for (i in 1:177) {
a <- geomean(er1$CW[1:i])
}
Basically, I have a list of 177 values and I'd like the script to find the cumulative geometric mean of the list going one by one. Right now it will only give me the final value, it won't save each loop iteration as a separate value in a list or vector.
The reason your code does not work is that the object ais overwritten in each iteration. The following code for instance does what precisely what you desire:
a <- c()
for(i in 1:177){
a[i] <- geomean(er1$CW[1:i])
}
Alternatively, this would work as well:
for(i in 1:177){
if(i != 1){
a <- rbind(a, geomean(er1$CW[1:i]))
}
if(i == 1){
a <- geomean(er1$CW[1:i])
}
}
I started down a similar path with rbind as #nate_edwinton did, but couldn't figure it out. I did however come up with something effective. Hmmmm, geo_mean. Cool. Coerce back to a list.
MyNums <- data.frame(x=(1:177))
a <- data.frame(x=integer())
for(i in 1:177){
a[i,1] <- geomean(MyNums$x[1:i])
}
a<-as.list(a)
you can try to define the variable that can save the result first
b <- c()
for (i in 1:177) {
a <- geomean(er1$CW[1:i])
b <- c(b,a)
}
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)
I am trying to keep an assigned object from a function (building a ts function to begin to model a univariate process, simple I know!). I am having trouble finding a method to keep objects in my workspace. It works fine just using a for loop but I would like to parameterize the following:
ts.builder<-function(x,y,z){
for(i in 9:13){
assign(paste(x,i,sep="_"),ts(yardstick[1:528,i], freq=24))
assign(paste(y,i,sep="_"),ts(yardstick[529:552,i], freq=24))
assign(paste(z,i,sep="_"),ts(yardstick[1:552,i], freq=24))
}
}
ts.builder("yard.book.training","yard.book.small.valid", "yard.book.valid")
Any pointers?
I am thinking it may need a return statement, yet I have not found this to be of use yet.
Untested (a reproducible example helps a lot):
ts.builder <- function() {
xd <- list()
yd <- list()
zd <- list()
for (i in 9:13) {
xd[[i]] <- ts(yardstick[1:528,i], freq=24)
yd[[i]] <- ts(yardstick[529:552,i], freq=24)
zd[[i]] <- ts(yardstick[1:552,i], freq=24)
}
list(yard.book.training=xd, yard.book.small.valid=yd, yard.book.valid=zd)
}
l <- ts.builder()
Then here are the returned values:
l$yard.book.training[[9]]
etc.
I have created a function to call a function on each row in a dataset. I would like to have the output as a vector. As you can see below the function outputs the results to the screen, but I cannot figure out how to redirect the output to a vector that I can use outside the function.
n_markers <- nrow(data)
p_values <-rep(0, n_markers)
test_markers <- function()
{
for (i in 1:n_markers)
{
hets <- data[i, 2]
hom_1 <- data[i, 3]
hom_2 <- data[i, 4]
p_values[i] <- SNPHWE(hets, hom_1, hom_2)
}
return(p_values)
}
test_markers()
Did you just take this code from here? I worry that you didn't even try to figure it out on your own first, but hopefully I am wrong.
You might be overthinking this. Simply store the results of your function in a vector like you do with other functions:
stored_vector <- test_markers()
But, as mentioned in the comments, your function could probably be reduced to:
stored_vector <- sapply(1:nrow(data), function(i) SNPHWE(data[i,2],data[i,3],data[i,4]) )