How do I use a macro variable in R? (Similar to %LET in SAS)
how about this:
reg<-lm(formula(paste(depvar ,'~ var1 + var2')), data=mydata)
R Version of SAS macro variable?
Here are some alternatives.
1) Base R Set e
to be the environment of the data frames. Here we assume they are in the current environment. With this in place e[[nm]]
refers to the data frame whose name is the character string held in variable nm
so the following works modifying the names in place:
e <- environment()
for(nm in v) {
is.price <- names(e[[nm]]) == "Price"
names(e[[nm]])[ is.price ] <- paste0(nm, "Price")
}
1a) Base R Function passing name and environment Here we define a function which takes the name of the data frame and the environment and modifies the names of the data frame in place. We use match
instead of ==
so that from
and to
can optionally be vectors of names. The in place modification in this solution is not really in the spirit of R's functional nature but we show it as an alternative:
rename1a <- function(DFname, from, to, envir = parent.frame()) {
ix <- match(from, names(envir[[DFname]]))
names(envir[[DFname]])[ ix ] <- to
}
for(nm in v) rename1a(nm, "Price", paste0(nm, "Price"))
1b) Base R Function returning copy Here we define a function which takes the data frame itself and returns a copy with the name changed. The function itself does not need to deal with environments and is more funtional in nature (i.e. it does not modify its inputs) -- the caller is responsible for assigning the result back.
rename1b <- function(DF, from, to) {
names(DF)[match(from, names(DF))] <- to
DF
}
e <- environment()
for(nm in v) e[[nm]] <- rename1b(e[[nm]], "Price", paste0(nm, "Price"))
2) doBy::renameCol renameCol
in the doBy package is plug compatible with rename1b
in (1b) so:
library(doBy)
e <- environment()
for(nm in v) e[[nm]] <- renameCol(e[[nm]], "Price", paste0(nm, "Price"))
3) plyr::rename The plyr package has a rename
function. Note that like (1b) it produces a copy of the data frame with the renamed columns so we assign it back:
e <- environment()
for(nm in v) e[[nm]] <- plyr::rename(e[[nm]], list(Price = paste0(nm, "Price")))
The reshape package has a similar function also called rename
and the above works if we replace plyr::rename
with reshape::rename
.
4) gtools::defmacro It would also be possible to use defmacro
in gtools to create a macro which alters the names in place. Although not typical of processing in R this does allow one to pass the data frame itself rather than separate name and environment as in (1a).
library(gtools)
rename4 <- defmacro(DF, from, to, expr = { names(DF)[ match(from, names(DF)) ] <- to })
e <- environment()
for(nm in v) rename4(e[[nm]], "Price", paste0(nm, "Price"))
Also see Thomas Lumley's Programmer's Niche article in R News 2001/3.
Note 1: You may wish to examine why you want to make these name changes in first place. There is also the question of whether the data frames should be freely defined in the global environment or combined into a list given that we want to deal with them en masse. The first Map
creates a named list L
such that, for example, L$SP
or L[["SP"]]
refers to the SP
component in L
. The second Map
outputs a new named list whose components have the new column names:
L <- Map(get, v) # create named list of input data frames
Map(rename1b, L, "Price", paste0(names(L), "Price"))
Note 2: Here we create some input to test with using the builtin data frame BOD
. This creates the objects SP
, SPF
, etc. that are the same as data frame BOD
except that the second column is named "Price"
:
# create SP, SPF, ... to test, each with a Price column
v <- c("SP","SPF","SPP","NQ","RTY","NYA")
for(nm in v) assign(nm, setNames(BOD, c("Time", "Price")))
R SAS macro like expression
I am not familiar with rmcorr but your problem stems from how your function takes input paramets. Look carefully at your code:
rmcorr(participant = Subject, measure1 = var2, measure2 = var1 , dataset = Results2)
takes measure1
and measure
as bare names input (so, a language element, not a string literal like "var1"
(in quotes).
While you pass string literals to the function with Allrmcorr("VAS","Hyd")
, rmcorr wants bare names that it evaluets in them frame of dataset
. All this is probably a bit complicated an off-putting if you are new to R. I recommend reading "Advanced R" by Hadley Wickham if you want to dive deeper into the topic (especially the chapters on functions and lazy evaluation).
A simple solution to your problem - which is similar to how macro variables work - is constructing your expression as a string and then evaluating it:
Allrmcorr <- function(var1, var2, dat){
ds <- dat
eval(parse(text = (sprintf(
"rmcorr(participant = Subject, measure1 = %s, measure2 = %s, dataset = ds)", var1, var2
))))
}
Allrmcorr("VAS", "Hyd", mydata)
This has severe disadvantages when it comes to performance and debuggability of your code; however, I was not able to find a better solution to your problem since the internal implementation of rcmorr
is somewhat weird.
How to make the equivalent of a SAS macro with do loop in R studio?
Here is a Base R solution to the problem. The OP wants to replicate the process of a SAS macro that subsets a list of SAS data sets, raw.have2000 - raw.have2018, keeps two columns, sets a variable year
equal to the year listed in the data set name, and joins these into a single data set.
# create some data
var1 <- 0:5
var2 <- 6:11
var3 <- 12:17
raw.have2000 <- data.frame(var1,var2,var3)
raw.have2001 <- data.frame(var1,var2,var3)
raw.have2002 <- data.frame(var1,var2,var3)
years <- 2000:2002
dataList <- lapply(years,function(x){
# create name of data set as a character object
dsname <- paste0("raw.have",x)
# use dsname with get() to extract data and subset first 2 variables
ds <- subset(get(dsname),var1 !=0,select=c(var1,var2))
ds$year <- x
# print to have data frame returned in
# output list
ds
})
# combine data frames
appended <- do.call(rbind,dataList)
...and the output, noting that the rows where var1 = 0
have been eliminated, var3
has been dropped, and the year
variable has been added:
> appended
var1 var2 year
2 1 7 2000
3 2 8 2000
4 3 9 2000
5 4 10 2000
6 5 11 2000
21 1 7 2001
31 2 8 2001
41 3 9 2001
51 4 10 2001
61 5 11 2001
22 1 7 2002
32 2 8 2002
42 3 9 2002
52 4 10 2002
62 5 11 2002
>
Explanation
One of the major differences between SAS and R is that experienced SAS programmers use the SAS macro language to automate repetitive tasks. The macro language generates SAS code that is processed by the SAS system.
R does not have a macro language / code generator. However, one can use the get()
function to access R objects whose names can be generated by combining various pieces of information into character objects.
R macros to enable user defined input similar to %let in SAS
You can accomplish this task using the paste0
function.
metric <- "MSP"
infile <- paste0("C:/Projects/Consumption curves/UKPOV/excel files/",metric,"_product_CC_2009_salespercap.csv")
Category_sales <- read.csv(infile)
or wrapped in a function
readCSV <- function(var) {
metric <- var
infile <- paste0("C:/Projects/Consumption curves/UKPOV/excel files/",metric,"_product_CC_2009_salespercap.csv")
return(infile)
}
Category_sales <- read.csv(readCSV('MSP'))
You can apply the same logic to all the bits that need to be replaced in your string.
Regarding to variable names you can do:
eval(parse(....))
will work
data1 <- data.frame(column1 = 1:10, column2 = letters[1:10])
txt <- "data1$column2"
> eval(parse(text = txt))
[1] a b c d e f g h i j
Levels: a b c d e f g h i j
For your particular case you can replace txt
with the same paste0
logic to build your variable names.
Full explanation in this SO Q/A
Hope it helps
How to pass an %LET argument into a sas script from R?
You can use the -SET option on the SAS command line to pass arguments into SAS. Then use the %SYSGET macro to retrieve those values in your program. For further discussion and an example, see the article "How to pass parameters to a SAS program."
Related Topics
Keeping Zero Count Combinations When Aggregating with Data.Table
Increase the API Limit in Ggmap's Geocode Function (In R)
How to Use Plyr to Number Rows
Initialize an Empty Tibble with Column Names and 0 Rows
Fixing Set.Seed for an Entire Session
R: Text Progress Bar in for Loop
Changing Title in Multiplot Ggplot2 Using Grid.Arrange
Ggplot2:Adding Two Errorbars to Each Point in Scatterplot
Calling a Function from a Namespace
Rank Variable by Group (Dplyr)
How to Set Seed for Random Simulations with Foreach and Domc Packages
Shiny Saving Url State Subpages and Tabs
Get Filename and Path of 'Source'D File
What's My User Agent When I Parse Website with Rvest Package in R