Randall Goodwin
2012-Jan-01 19:58 UTC
[R] How to pass in a list of variables as an argument to a function?
Hello, I have some code that currently works fine and I am endeavoring to convert the major pieces of it into functions. This involves taking "hard coded" names of variables that are used in various places and figuring out how to abstract them out into functions where the arguments (i.e. a list of variables)?can be passed to the parent function and used within that function for various purposes. Here is some code that comes close to replicating some of the cases I am trying to solve. Basically, the same list of variables comes up many times in the current code (where nothing is really a function). Now that I am converting everything to a function, I'd like to specify the list of variables once and use that list throughout the code in other places. The list of variables does not have to be of class = list. more generally, it could be any class that can be converted such that it is usable in paste(), aggregate() and reshape() as in the example below. I have tried various things to make it work.. using paste() and noquote() in combination to build a string that is identical to the arguments that these functions accept, however R interprets them as a string, not as individual arguments. Thanks in advance, Randall ################################################################# # libraries used library(reshape) # create some data similar to use case myData = data.frame(expand.grid(varA=c("a", "b", "c"), varB=c("d", "e", "f"), varC=c("g", "h", "i"), varD=c("old", "new")), n=1000, fail=rbinom(2700,1000, 0.01)) # add in one more column myData$pass = myData$n-myData$fail # List of grouping vars. ?I would like to pass this object around and use it as arguments in functions myGroupVars = c("varA", "varB", "varC") # create a new column that is the combination of the grouping vars (used in plotting with lattice) # Question 1: ?Is there a way to replace "varA, varB, varC" in the function below with an object? myData = transform(myData, groupVar = paste(varA, varB, varC, sep = " | ")) # Sum the data by the same groupVars and two other variables # Question 2: ?Is there a way to replace "varA + varB + varC" in the function below and do the same aggregation? myDataSum <- aggregate(cbind(pass, fail) ~ varA + varB + varC + groupVar + varD, data = myData, sum) # pivot the pass and fail quantity to one row per group, ?labelling them # Question 3: ?This one actually works. ?idvar happily accepted the vector of group vars. ?Better way? myDataSum <- reshape(myDataSum, ?idvar = myGroupVars, v.names c("pass", "fail"), timevar = "varD", direction = "wide")
Joshua Wiley
2012-Jan-01 22:39 UTC
[R] How to pass in a list of variables as an argument to a function?
Hi Randall, This will do it. There may be more elegant ways. Formula methods are just handy front ends (e.g., stats:::aggregate.formula), that end up dispatching to other methods usually. It is easy to pass a character vector to extractor functions like `[`() so with a bit more typing, you can often skip the formula altogether. I think that will be the easiest approach if you are not actually typing the formula (there are ways to create them, but bleh). Cheers, Josh ########################################### # libraries used library(reshape) # create some data similar to use case myData = data.frame(expand.grid(varA=c("a", "b", "c"), varB=c("d", "e", "f"), varC=c("g", "h", "i"), varD=c("old", "new")), n=1000, fail=rbinom(2700,1000, 0.01)) # add in one more column myData$pass = with(myData, n - fail) # List of grouping vars. I would like to pass this object around and use it as arguments in functions myGroupVars = c("varA", "varB", "varC") # create a new column that is the combination of the grouping vars (used in plotting with lattice) # Question 1: Is there a way to replace "varA, varB, varC" in the function below with an object? myData2 <- transform(myData, groupVar = do.call("paste", c(myData[, myGroupVars], sep = " | "))) myData = transform(myData, groupVar = paste(varA, varB, varC, sep = " | ")) all.equal(myData, myData2) # Sum the data by the same groupVars and two other variables # Question 2: Is there a way to replace "varA + varB + varC" in the function below and do the same aggregation? myDataSum = aggregate(cbind(pass, fail) ~ varA + varB + varC + groupVar + varD, data = myData, sum) myDataSum2 <- aggregate(x = myData2[, c("pass", "fail")], by = myData2[, c(myGroupVars, "groupVar", "varD")], FUN = sum) all.equal(myDataSum, myDataSum2) # pivot the pass and fail quantity to one row per group, labelling them # Question 3: This one actually works. idvar happily accepted the vector of group vars. Better way? myDataSum <- reshape(myDataSum, idvar = myGroupVars, v.names c("pass", "fail"), timevar = "varD", direction = "wide") ##################################### On Sun, Jan 1, 2012 at 11:58 AM, Randall Goodwin <randall.goodwin at gmail.com> wrote:> Hello, > > I have some code that currently works fine and I am endeavoring to > convert the major pieces of it into functions. > This involves taking "hard coded" names of variables that are used in > various places and figuring out how to > abstract them out into functions where the arguments (i.e. a list of > variables)?can be passed to the parent function > and used within that function for various purposes. > > Here is some code that comes close to replicating some of the cases I > am trying to solve. > > Basically, ?the same list of variables comes up many times in the > current code (where nothing is really a function). > Now that I am converting everything to a function, I'd like to specify > the list of variables once and use that list > throughout the code in other places. ?The list of variables does not > have to be of class = list. ?more generally, > it could be any class that can be converted such that it is usable in > paste(), aggregate() and reshape() as in > the example below. > > I have tried various things to make it work.. using paste() and > noquote() in combination to build a string that is identical to the > arguments that these functions accept, ?however R interprets them as a > string, ?not as individual arguments. > > Thanks in advance, > > Randall > > ################################################################# > > # libraries used > library(reshape) > > # create some data similar to use case > myData = data.frame(expand.grid(varA=c("a", "b", "c"), > varB=c("d", "e", "f"), > varC=c("g", "h", "i"), > varD=c("old", "new")), > n=1000, fail=rbinom(2700,1000, 0.01)) > > # add in one more column > myData$pass = myData$n-myData$fail > > # List of grouping vars. ?I would like to pass this object around and > use it as arguments in functions > myGroupVars = c("varA", "varB", "varC") > > # create a new column that is the combination of the grouping vars > (used in plotting with lattice) > # Question 1: ?Is there a way to replace "varA, varB, varC" in the > function below with an object? > myData = transform(myData, groupVar = paste(varA, varB, varC, sep = " | ")) > > # Sum the data by the same groupVars and two other variables > # Question 2: ?Is there a way to replace "varA + varB + varC" in the > function below and do the same aggregation? > myDataSum <- aggregate(cbind(pass, fail) ~ varA + varB + varC + > groupVar + varD, data = myData, sum) > > # pivot the pass and fail quantity to one row per group, ?labelling them > # Question 3: ?This one actually works. ?idvar happily accepted the > vector of group vars. ?Better way? > myDataSum <- reshape(myDataSum, ?idvar = myGroupVars, v.names > c("pass", "fail"), > timevar = "varD", direction = "wide") > > ______________________________________________ > 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.-- Joshua Wiley Ph.D. Student, Health Psychology Programmer Analyst II, Statistical Consulting Group University of California, Los Angeles https://joshuawiley.com/