Modify Variable Within R Function

modify variable within R function

There are ways as @Dason showed, but really - you shouldn't!

The whole paradigm of R is to "pass by value". @Rory just posted the normal way to handle it - just return the modified value...

Environments are typically the only objects that can be passed by reference in R.

But lately new objects called reference classes have been added to R (they use environments). They can modify their values (but in a controlled way). You might want to look into using them if you really feel the need...

Memory efficient way to modify a variable within a function

This question was already discussed here:

Pass an object to a function without copying it on change

Your second approach does not really solve the problem. Here is the test I ran with the results of mem_used()

library(pryr)
mem_used()
#41.3 MB

x <- matrix(1:1000000000, ncol=1000)
mem_used()
#4.04GB

f2<- function(x){
print(mem_used())
x = deparse(substitute(x))
print(mem_used())
x = get(x, envir = globalenv())
x<- x+1
print(mem_used())
x
}

x <- f2(x)
#4.04 GB
#4.04 GB
#12 GB
mem_used()
#8.04GB

R: modify variables defined in function

I'm sorry to say, that you've correctly identified using functions for your solution, but completely overstepped. But let's take the questions one-by-one:

Is there a way to access the variables defined inside foo?

No, this is by design that what's defined in a function stays within the function, and is only accessible from the function and its children (i.e., whatever the function itself is calling).

Is there a way to ... modify/overwrite the default values?

This is what function arguments are for, as you correctly deduced. But the solution is simpler; first, for the input variables:

foo <- function(var1 = 1, var2 = 3) {
var3 <- var1 + var2
var4 <- var3 * var2
return(c(var1, var2, var3, var4))
}

Note: Your return statement is very difficult to read, and potentially dangerous if you need, say, a 5th intermediate variable. It, too, will be returned, and you cannot guarantee the order of the returned variables.

If you need named variables, use a named vector:

  return(c(v1=var1, s2=var2, var3=var3, m4=var4))

If your returned values are more complex than some scalar values, just use list instead of the simple c.

but what about the variables that are calculated based on other ones?

This is where it gets fun; there are several options depending on the complexity of what you want to do and how much flexibility the user should have. First, we can try to extend the above solution to include the computed values and only calculate them if not given:

foo <- function(var1 = 1, var2 = 3, var3, var4) {
if (missing(var3))
var3 <- var1 + var2
if (missing(var4))
var4 <- var3 * var2
return(c(var1, var2, var3, var4))
}

The function missing simply tells you, if the argument var3 was provided. R is a bit funny here as in other languages, function arguments without defaults must be given when calling the function. R doesn't play like that and will only require the variable if you ask for it.

But, if var3 and var4 are simple calculations, couldn't they just be defined in the function signature?

  foo <- function(var1 = 1, var2 = 3, var3 = var1 + var2, var4 = var3 * var2) {
return(c(var1, var2, var3, var4))
}

Turns out it works in this case but don't do it!. It will not work for more complex data types (lists, data frames) and it is bad coding style, because it also makes the function less readable.

R function wont modify global variable

I think I know what is wrong

Change data <- table to data <<- table within your function

You are assigning the result to the local environment for the function, whilst the <<- will be assigning it to the global environment.

I would propose you try the following

library(rvest)
getData <- function(url) { html_table(read_html(url)) }

data <- getData("https://steemdb.com/accounts/reputation?page=1")

Or even better

library(rvest)
getData <- function(url) { html_table(read_html(url)) }
steemdb.url <-"https://steemdb.com/accounts/reputation?page="

data <- lapply(1:100, function(i) getData(paste0(steemdb.url, i)) )
data <- do.call(rbind, data)
View(data)

1:100 will get you the first 100 pages.

write r function to modify value in data frame

If we are passing column name as string, then use [[ instead of $ and return the dataset

MakeBinary <- function(varName, dfName){
dfName[[varName]][dfName[[varName]] >= 1] <- 1
dfName
}

MakeBinary("Var2", df)

example with mtcars

MakeBinary("carb", head(mtcars))
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 1
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 1
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 1
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

Unquoted arguments for variable names can be passed as well, but it needs to be converted to string

MakeBinary <- function(varName, dfName){
varName <- deparse(substitute(varName))
dfName[[varName]][dfName[[varName]] >= 1] <- 1
dfName
}

MakeBinary(Var2, df)

Using a reproducible example with mtcars

MakeBinary(carb, head(mtcars))
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 1
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 1
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 1
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

Can non-global variables be modified inside a function in R?

It is possible to update a global variable, in a function using get and assign function. Below is the code, which does the same :

heatmap.matrix <- matrix(rep(0,40000), nrow=200, ncol=200)

# foo function should just update a single cell of the declared matrix
varName <- "heatmap.matrix"
foo <- function() {
heatmap.matrix.copy <- get(varName)
heatmap.matrix.copy[40,40] <- 100
assign(varName, heatmap.matrix.copy, pos=1)
}

heatmap.matrix[40,40]
#[1] 0
foo()
heatmap.matrix[40,40]
# [1] 100

you should read up a bit on environments concept. The best place to start is http://adv-r.had.co.nz/Environments.html

How can I change variable value in R apply function?

It is because variable assignment within a function is lost when the function terminates. As Zheyuan Li rightly pointed out, assigning to the global environment gets around this as this way the assignment is not lost upon termination.

I prefer using the assign() function as you can explicitly determine where the variable is stored (not always the case with <<-).

idx=1

f <- function(x){

assign('idx', idx+1, envir = globalenv())
print(c("current progress", idx))
return(1)

}

res=sapply(1:3,f)


Related Topics



Leave a reply



Submit