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")))
paste0(v, "Price")
? It gives[1] "SPPrice" "SPFPrice" "SPPPrice" "NQPrice" "RTYPrice" "NYAPrice"
. So you cangrep/match/whatever
names first. – user3710546