How to Use a MACro Variable in R? (Similar to %Let in Sas)

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



Leave a reply



Submit