Saving Matrix within Function to Parent Environment - r

So I currently have several functions where I want to modify a matrix that was created outside the function, in order to use it as a counting variable for things that happen inside the function. The matrix is named cost_counter, and I want to add to it when certain events occur inside of multiple functions. However, I'd like the solution to still be able to be used in foreach() and be parallelizable.
I know that using <<- is not recommended, however I can't figure out how to use assign() to modify an existing matrix. Example code is below. I've defined the variable cost_counter at the beginning. The function below goes on for longer, but I'm just including the first part for an example of what is happening.
cost_counter <<- matrix(0,nrow = 2, ncol = 12*15)
I0 <- function(){
if (screen[i] == 1){
cost_counter[2,ages[i]] <<- 1 + cost_counter[2,ages[i]] + 1
if(HIV[i] == 1){
if(ages[i] > 35){
if(pv[(i-min_i+1),1] < (1-specP3)){
cost_counter[1,ages[i]] <<- cost_counter[1,ages[i]] + 1
if(contact[i] == 1){return(c(5,0))}
}
}
When I run, error message simply says
"Error in cost_counter[2, ages[i]] <<- cost_counter[2, ages[i]] + 1 :
object 'cost_counter' not found"
I would just like to be able to modify the matrix, and for it to be recognized.
Any help would be appreciated. Thanks!

just at the end f the function re assign the function's matrix to the global env using:
cost_counter <<- cost_counter

Related

R function to reverse a survey item produces NULL

I'm still new to writing my own functions. As an exercise and because I use it alot, I want to write a flexible function to easily reverse survey response scales. This is what I came up with:
rev_scale = function(var, new_var, scale){
for (i in 1:length(abs(var))){
new_var[i] = scale-abs(var[i])+1
}
}
Info on code
var = variable I want to reverse.
new_var = new column with the reversed variable
scale = how many points in the scale (eg. 5 for a 5-point scale)
The reason why I use 'abs' instead of just 'var' is that some dataframes also return value-labels, and I only want the values in this function.
Question
When applying this new function on a variable, R returns "NULL". However, if I run the for-loop separately, with the arguments 'imputed', my new variable is properly reversed.
Any ideas on what is happening here?
Thanks in advance!
### Example of the (working) for-loop with arguments 'imputed' ###
df <- data.frame(matrix(ncol = 1, nrow = 4))
df$var = c(1,2,3,4)
for (i in 1:length(abs(df$var))){
df$var_rev[i] = 4-abs(df$var[i])+1
}
df$var_rev
OUTPUT:
[1] 4 3 2 1
R does not use reference-variables (think pointers)*. So your new_var outside of your function does not get updated when refered to inside a function. Instead, R creates a new copy of new_var and updates that.
You should instead return the new value from your function. I.e.
rev_scale = function(var, scale){
res <- vector('numeric', length(var))
for (i in 1:length(abs(var))){
res[i] = scale-abs(var[i])+1
}
return(res)
}
Also note that I have removed new_var from the function's arguments. In other words, I have completely separated the functions input-arguments from its output.
The reason you get a NULL from the function is that in R, all functions returns somethings. If not specified, the function will return the last value of the last statement, except when the last statement is a control structure (ifs, loops) - then it defaults to a NULL.
* There are a couple of exceptions and work-arounds, but I will not go into that here.
Edit:
As benimwolfspelz noted, you do not need to explicitly iterate over each element in var, as R does this implicitly. Your entire function could be reduced to:
rev_scale = function(var, scale) {
scale-abs(var)+1
}
Secondly, in your for-loop, your can simplify length(abs(var)) to length(var) as abs(var) does not change the length of the vector.

creating list of outputs from a function

I would like to know how can I list the outputs of my function (it prints out vectors) so that I am able to know how many steps did it require until finding the optimal solution.
I have the following code and am just wondering what should I do at the end so that when printing out the vectors, it enumerates them one at a time as well. I am new to Rstudio and do see that some operations that have to do with matrices are not common in other programming languages.
I should say that I have already defined another function such as "gradient", but my concern is about the enumeration of the outputs for this particular function.
Sd=function(b0,epsilon=1e-5){
while (norm(gradient(b0))>epsilon) {
num1=(t(b0)%*%Q%*%gradient(b0)-t(y)%*%X%*%gradient(b0))/(t(gradient(b0))%*%Q%*%gradient(b0))
num2=norm(num1)
step=num2*gradient(b0)
b0=b0-step
print(t(b0))
}
}
Thank you for any help I can get.
Here's a generic answer that will show you how to approach this. Without access to your custom functions I can't give a more direct answer. It's generally helpful to give a minimal reproducible example.
That said, my basic suggestion is to use a counter variable, increment it once each loop, and include that in your printed output.
Here's a simplified example that's based on your code, but the only operation we're doing is taking repeated square roots. Note that the arrow operator <- is the best practice for assigning values. (I promise you get used to it!)
# set up a generic function for this minimal example
get_value <- function(x){
return (sqrt(x))
}
my_function <- function(b0, epsilon = 1.1){
# set up a counter variable
i <- 0
# our main loop
while (get_value(b0) > epsilon) {
# increment the counter
i <- i + 1
# do calculations
num1 <- get_value(b0)
# update our current solution
b0 <- num1
# print a message to the console with the counter and the value
message(paste0("Iteration: ",i,"\n",
"b0: ", b0))
}
# print a final message to the console when we stop
message(paste0("Final Iteration: ",i,"\n",
"Final b0: ", b0))
}
my_function(2)

How does lazy evaluation binds variable (in R)

I'm fairly new to R and I just noticed that the first call to a function seems to bind its environment parameters. How does this work ? (Or how is it it called, so I can look it up in the doc).
E.g.:
make.power <- function(n)
{
pow <- function(x)
{
x^n
}
}
i <- 3
cube <- make.power(i)
# print(cube(3)) # uncommenting this line change the value below
i <- 2
square <- make.power(i)
print(cube(3)) # this value changes depending on whether cube(3) was called before.
print(square(3))
I'm looking for a sample explanation of what's going on, or just the name of this feature, so I can look it up.
Thanks !

Loop within dataframe subset

This is probably a basic question in R, but I am trying to loop data within subsets of a larger data frame. I have added the 'data=sub240' line within the 'while' command, but this leads to a brackets error, which I suspect is indicative of a larger problem. Can anyone tell me how to run a loop on a subset of a dataframe? I don't think it is relevant, but I am using the 'optiscale' package within the loop.
{while (rsquared.differ > .00001 && niter <= 30 && data=sub240) {
niter <- niter + 1
reg.os<- lm(dvar.os ~ index.os + educ.os)
rsquared.differ <- summary(reg.os)$r.squared - previous.rsquared
previous.rsquared <- summary(reg.os)$r.squared
record <- c(record, niter, summary(reg.os)$r.squared, rsquared.differ)
if (rsquared.differ > .00001) {
dvar.pred <- predict(reg.os)
opscaled.dvar <- opscale(intknow, dvar.pred, level = 1, process = 1)
dvar.os <- opscaled.dvar$os
intknow240.pred <- (dvar.os - (reg.os$coefficients[1] +
(reg.os$coefficients[4]*educ.os)
))*
(1/reg.os$coefficients[2])
opscaled.intknow240 <- opscale(anes$intknow, intknow240.pred, level = 1, process = 1)
intknow240.os <- opscaled.intknow240$os
}}
data = sub240 is an assignment statement. You can assign things on their own line or in function definitions and calls, but you can only provide logical statements in a while loop definition. If you want logical equality, you need ==. But unless data changes in the loop AND you would like that to be a condition for the loop to break, then you don't want that inside your while statement. But generally, there is no need for that statement anyway. The way scoping works in R, the loop should still be able to access data if it is defined outside the loop.
Also, I'm pretty sure you don't need the bracket before while, only after. As your code stands, it won't run because that bracket is unclosed: You have three open brackets (before while, after while, and after if), but only two close brackets (that I could find, anyway).
Try something like this:
data <- sub240
while(rsquared.differ > 0.00001 && niter <=30){
# do stuff
}

R - using substitute within a nested function

I have a function that may end up being nested (Inner) and some other function (in general this function won't be known) that I'm calling Outer, and I would like Inner to be able to produce the same result regardless of the wrapper function (Outerin the below case).
Inner <- function(x,baz,bang){
# code stuff things ...
x.prime = as.character(substitute(x))
return(c(x.prime,y,z))
}
Outer <- function(y){
Inner(y)
}
Inner(a)
# "a" "stuff" "things" , which is what I'm expecting, in particular the "a".
Outer(a)
# "y" .... , but I was expecting to get "a"?
Of course I'm not dead set on using substitute if someone knows of a better method.
Does anyone have any clues how to get Inner to output the same result regardless if it is nested or not?
thanks in advance.
Here is a general outline that should help you solve your problem:
Inner <- function(x) {
my.call <- quote(substitute(x)) # we quote this here because we are going to re-use this expression
var.name <- eval(my.call)
for(i in rev(head(sys.frames(), -1L))) { # First frame doesn't matter since we already substituted for first level, reverse since sys.frames is in order of evaluation, and we want to go in reverse order
my.call[[2]] <- var.name # this is where we re-use it, modified to replace the variable
var.name <- eval(my.call, i)
}
return(var.name)
}
Outer <- function(y) Inner(y)
Outer2 <- function(z) Outer(z)
Now let's run the functions:
Inner(1 + 1)
# 1 + 1
Outer(2 + 2)
# 2 + 2
Outer2(3 + 3)
# 3 + 3
Inner always returns the outermost expression (you don't see y or z ever, just the expression as typed in .GlobalEnv.
The trick here is to use sys.frames(), and repeatedly substitute until we get to the top level.
Note this assumes that all the "Outer" functions just forward their argument on to the next inner one. Things likely get a lot more complicated / impossible if you have something like:
Outer <- function(y) Inner(y + 1)
This code does not check for that type of issue, but you probably should in your code. Also, keep in mind that the assumption here is that your functions will only be called from the R command line. If someone wraps their functions around yours, you might get unexpected results.

Resources