Hi, I've looked all over for a solution to this, but haven't had much look in specifying what I want to do with appropriate search terms. Thus I'm turning to R-help. In the process of trying to write a simple function to rename individual column names in a data frame, I ran into the following problem: When I rename the columns within my function, I can't seem to get it to apply to the data frame in the global environment in a simple manner. Given: tempdf <- data.frame("a" = 1:6, "b" = 7:12) #I can rename a to g this way: names(tempdf)[names(tempdf)=="a"] <- "g" #Wanting to simplify this for the future, I have the function: colrename <- function(dframe, oldname, newname) { names(dframe)[names(dframe)==oldname] <- newname } colrename(tempdf, "a", "g") #However of course the change to tempdf stays within colrename(). I could add "return(names(dframe))" to the function and then call the function like: #names(tempdf) <- colrename(tempdf, "a", "g") #but at that point its not much simpler than the original: #names(tempdf)[names(tempdf)=="a"] <- "g" So, i'm wondering, is there a way to write code within that function so that the tempdf in the global environment gets changed? I thought of doing "names(dframe)[names(dframe)==oldname] <<- newname" but then of course it doesn't replace "dframe" with "tempdf" in the evaluation, so it seems to be a problem of looking at some variables within the function environment but others in the parent environment. Any help is greatly appreciated. Thanks, Jon -- Jon Zadra Department of Psychology University of Virginia P.O. Box 400400 Charlottesville VA 22904 (434) 982-4744 email: zadra at virginia.edu <http://www.google.com/calendar/embed?src=jzadra%40gmail.com>
Duncan Murdoch
2010-Oct-13 18:28 UTC
[R] Change global env variables from within a function
On 13/10/2010 2:19 PM, Jon Zadra wrote:> Hi, > > I've looked all over for a solution to this, but haven't had much look > in specifying what I want to do with appropriate search terms. Thus I'm > turning to R-help. > > In the process of trying to write a simple function to rename individual > column names in a data frame, I ran into the following problem: When I > rename the columns within my function, I can't seem to get it to apply > to the data frame in the global environment in a simple manner. > > Given: > > tempdf<- data.frame("a" = 1:6, "b" = 7:12) > > #I can rename a to g this way: > names(tempdf)[names(tempdf)=="a"]<- "g" > > #Wanting to simplify this for the future, I have the function: > colrename<- function(dframe, oldname, newname) { > names(dframe)[names(dframe)==oldname]<- newname > } > > colrename(tempdf, "a", "g") > > #However of course the change to tempdf stays within colrename(). I > could add "return(names(dframe))" to the function and then call the > function like: > #names(tempdf)<- colrename(tempdf, "a", "g") > #but at that point its not much simpler than the original: > #names(tempdf)[names(tempdf)=="a"]<- "g" > > So, i'm wondering, is there a way to write code within that function so > that the tempdf in the global environment gets changed? > I thought of doing "names(dframe)[names(dframe)==oldname]<<- newname" > but then of course it doesn't replace "dframe" with "tempdf" in the > evaluation, so it seems to be a problem of looking at some variables > within the function environment but others in the parent environment. > > Any help is greatly appreciated.Make the changes to a local copy, then save it to the global (or just return the local copy as the value of the global). For example, colrename<- function(dframe, oldname, newname) { names(dframe)[names(dframe)==oldname]<- newname dframe } called as tempdf<- colrename(tempdf, "a", "g") or if you really want to mess with things that don't belong to your function, colrename<- function(dframe, oldname, newname) { name<- deparse(substitute(dframe)) names(dframe)[names(dframe)==oldname]<- newname assign(name, dframe, env=globalenv()) } (but watch out if you call this with something other than a simple variable name as the first argument). Duncan Murdoch
Hello, Jon Zadra wrote:> Hi, > > I've looked all over for a solution to this, but haven't had much look > in specifying what I want to do with appropriate search terms. Thus I'm > turning to R-help. > > In the process of trying to write a simple function to rename individual > column names in a data frame, I ran into the following problem: When I > rename the columns within my function, I can't seem to get it to apply > to the data frame in the global environment in a simple manner.Not a direct answer to your question, but does the ?rename function in the reshape package do what you want? In general, the paradigm that I think R tries to promote is to call functions that *return values* that you can assign to object names, so calling "colrename" below to change an object in the global environment is warned against for its side effects. You could have the function return the modified data.frame, but of course that's what the "rename" function I mention above does already. You might also see ?transform.> > Given: > > tempdf <- data.frame("a" = 1:6, "b" = 7:12) > > #I can rename a to g this way: > names(tempdf)[names(tempdf)=="a"] <- "g" > > #Wanting to simplify this for the future, I have the function: > colrename <- function(dframe, oldname, newname) { > names(dframe)[names(dframe)==oldname] <- newname > } > > colrename(tempdf, "a", "g") > > #However of course the change to tempdf stays within colrename(). I > could add "return(names(dframe))" to the function and then call the > function like: > #names(tempdf) <- colrename(tempdf, "a", "g") > #but at that point its not much simpler than the original: > #names(tempdf)[names(tempdf)=="a"] <- "g" > > So, i'm wondering, is there a way to write code within that function so > that the tempdf in the global environment gets changed? > I thought of doing "names(dframe)[names(dframe)==oldname] <<- newname" > but then of course it doesn't replace "dframe" with "tempdf" in the > evaluation, so it seems to be a problem of looking at some variables > within the function environment but others in the parent environment. > > Any help is greatly appreciated. > > Thanks, > > Jon
R is primarily a function language not a macro language and what you are trying to do matches more with macro programming. The best approach is to think functionally and learn the more Rish ways of doing things (have the function return the changed data and the caller does the replacement, like has been shown in other responses). If you really want the macro behavior (and are willing to live with the consequences (don't complain that you were not warned)), then look at the defmacro function in the gtools package and the article in the reference section on its help page. -- Gregory (Greg) L. Snow Ph.D. Statistical Data Center Intermountain Healthcare greg.snow at imail.org 801.408.8111> -----Original Message----- > From: r-help-bounces at r-project.org [mailto:r-help-bounces at r- > project.org] On Behalf Of Jon Zadra > Sent: Wednesday, October 13, 2010 12:20 PM > To: r-help at r-project.org > Subject: [R] Change global env variables from within a function > > Hi, > > I've looked all over for a solution to this, but haven't had much look > in specifying what I want to do with appropriate search terms. Thus > I'm > turning to R-help. > > In the process of trying to write a simple function to rename > individual > column names in a data frame, I ran into the following problem: When I > rename the columns within my function, I can't seem to get it to apply > to the data frame in the global environment in a simple manner. > > Given: > > tempdf <- data.frame("a" = 1:6, "b" = 7:12) > > #I can rename a to g this way: > names(tempdf)[names(tempdf)=="a"] <- "g" > > #Wanting to simplify this for the future, I have the function: > colrename <- function(dframe, oldname, newname) { > names(dframe)[names(dframe)==oldname] <- newname > } > > colrename(tempdf, "a", "g") > > #However of course the change to tempdf stays within colrename(). I > could add "return(names(dframe))" to the function and then call the > function like: > #names(tempdf) <- colrename(tempdf, "a", "g") > #but at that point its not much simpler than the original: > #names(tempdf)[names(tempdf)=="a"] <- "g" > > So, i'm wondering, is there a way to write code within that function so > that the tempdf in the global environment gets changed? > I thought of doing "names(dframe)[names(dframe)==oldname] <<- newname" > but then of course it doesn't replace "dframe" with "tempdf" in the > evaluation, so it seems to be a problem of looking at some variables > within the function environment but others in the parent environment. > > Any help is greatly appreciated. > > Thanks, > > Jon > -- > Jon Zadra > Department of Psychology > University of Virginia > P.O. Box 400400 > Charlottesville VA 22904 > (434) 982-4744 > email: zadra at virginia.edu > <http://www.google.com/calendar/embed?src=jzadra%40gmail.com> > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting- > guide.html > and provide commented, minimal, self-contained, reproducible code.
David Winsemius
2010-Oct-13 20:01 UTC
[R] Change global env variables from within a function
On Oct 13, 2010, at 2:19 PM, Jon Zadra wrote:> Hi, > > I've looked all over for a solution to this, but haven't had much > look in specifying what I want to do with appropriate search terms. > Thus I'm turning to R-help. > > In the process of trying to write a simple function to rename > individual column names in a data frame, I ran into the following > problem: When I rename the columns within my function, I can't seem > to get it to apply to the data frame in the global environment in a > simple manner.There already is a function (or perhaps a composition of two functions) that does what you ask. It's the '<-' method for names() usually invoked in its dyadic form: names(object) <- character_vector > df <- data.frame(one=rnorm(10), two=rnorm(10)) > names(df) <- c("three", "four") > names(df) [1] "three" "four" In your case it would work like this: > names(tempdf)[ which(names(tempdf)=="a") ] <- "g" > names(tempdf) [1] "g" "b" -- David.> > Given: > > tempdf <- data.frame("a" = 1:6, "b" = 7:12) > > #I can rename a to g this way: > names(tempdf)[names(tempdf)=="a"] <- "g" > > #Wanting to simplify this for the future, I have the function: > colrename <- function(dframe, oldname, newname) { > names(dframe)[names(dframe)==oldname] <- newname > } > > colrename(tempdf, "a", "g") > > #However of course the change to tempdf stays within colrename(). I > could add "return(names(dframe))" to the function and then call the > function like: > #names(tempdf) <- colrename(tempdf, "a", "g") > #but at that point its not much simpler than the original: > #names(tempdf)[names(tempdf)=="a"] <- "g" > > So, i'm wondering, is there a way to write code within that function > so that the tempdf in the global environment gets changed? > I thought of doing "names(dframe)[names(dframe)==oldname] <<- > newname" but then of course it doesn't replace "dframe" with > "tempdf" in the evaluation, so it seems to be a problem of looking > at some variables within the function environment but others in the > parent environment. > > Any help is greatly appreciated. > > Thanks, > > Jon > -- > Jon Zadra > Department of Psychology > University of Virginia > P.O. Box 400400 > Charlottesville VA 22904 > (434) 982-4744 > email: zadra at virginia.edu > <http://www.google.com/calendar/embed?src=jzadra%40gmail.com> > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.David Winsemius, MD West Hartford, CT