R版本的SAS宏变量?
R Version of SAS macro variable?
我对SAS很熟悉。我是 R 的初学者,我想弄清楚宏变量的 R 等价物是什么。具体来说,我有 6 个数据集,它们都有一个共同的变量名称 Price。我想创建一个循环,将每个数据集中的价格更改为 DatasetNamePrice。这在 SAS 中使用宏变量进行文本替换很简单。到目前为止,我已经用每个数据集的名称创建了向量。
v=c("SP","SPF","SPP","NQ","RTY","NYA")
我通常使用这段代码重命名变量:
names(SP)[names(SP)=="Price"]="SPPrice"
我目前的尝试是:
for(i in 1:6)
{
names(v[[i]])[names(v[[i]])=="Price"]="v[[i]]Price"
}
R 在运行时没有给我任何错误,但似乎没有做任何事情。感谢任何帮助。
根据您的需要,您需要 get() and assign() functions since you are attempting to pass a string literal in the names()
attribute which expects a data frame object. Also, to concatenate variables with strings you need to use paste()。
考虑以下使用 lapply()(将函数应用于列表或向量和 returns 列表的递归方法);它将字段和 returns 每个数据帧重命名为数据帧列表。然后,for
循环使用 assign()
:
从这个创建的列表中重新写入原始数据帧
v=c("SP","SPF","SPP","NQ","RTY","NYA")
dfList <- lapply(v, function(x) {
df <- get(x)
names(df)[grep("Price", names(df))] <- paste0(x, "Price")
return(df)
})
for (i in 1:length(v)) {
assign(v[[i]], as.data.frame(dfList[[i]]))
}
rm(dfList)
这里有一些替代方案。
1) Base R 设置e
为数据帧的环境。这里我们假设他们在当前环境中。有了这个 e[[nm]]
指的是名称为变量 nm
中保存的字符串的数据框,因此以下工作就地修改名称:
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 这里我们定义了一个函数,它接受数据框的名称和环境并修改数据框的名称.我们使用 match
而不是 ==
以便 from
和 to
可以选择性地作为名称向量。此解决方案中的就地修改并不真正符合 R 的功能性质的精神,但我们将其作为替代方案展示:
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) 返回副本的基本 R 函数 这里我们定义了一个函数,它接受数据框本身和 returns 一个名称已更改的副本。该函数本身不需要处理环境,并且本质上更具功能性(即它不修改其输入)——调用者负责将结果分配回去。
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"))
doBy 包中的 2) doBy::renameCol renameCol
与 (1b) 中的 rename1b
插件兼容,因此:
library(doBy)
e <- environment()
for(nm in v) e[[nm]] <- renameCol(e[[nm]], "Price", paste0(nm, "Price"))
3) plyr::rename plyr 包有一个rename
函数。请注意,与 (1b) 一样,它会生成包含重命名列的数据框副本,因此我们将其分配回去:
e <- environment()
for(nm in v) e[[nm]] <- plyr::rename(e[[nm]], list(Price = paste0(nm, "Price")))
reshape 包有一个类似的功能,也称为 rename
,如果我们将 plyr::rename
替换为 reshape::rename
,则上述功能有效。
4) gtools::defmacro 也可以在 gtools 中使用 defmacro
创建一个宏来改变名称。虽然这不是 R 中的典型处理,但这确实允许传递数据框本身,而不是像 (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"))
另请参阅 R News 2001/3 中 Thomas Lumley 的程序员专栏文章。
注 1:您可能希望首先检查为什么要进行这些名称更改。还有一个问题是,数据框是应该在全局环境中自由定义,还是应该合并到一个列表中,因为我们想要处理它们。第一个 Map
创建一个命名列表 L
,例如,L$SP
或 L[["SP"]]
引用 L
中的 SP
组件。第二个 Map
输出一个新的命名列表,其组件具有新的列名:
L <- Map(get, v) # create named list of input data frames
Map(rename1b, L, "Price", paste0(names(L), "Price"))
注 2: 这里我们创建一些输入以使用内置数据框 BOD
进行测试。这将创建与数据框 BOD
相同的对象 SP
、SPF
等,除了第二列名为 "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")))
我对SAS很熟悉。我是 R 的初学者,我想弄清楚宏变量的 R 等价物是什么。具体来说,我有 6 个数据集,它们都有一个共同的变量名称 Price。我想创建一个循环,将每个数据集中的价格更改为 DatasetNamePrice。这在 SAS 中使用宏变量进行文本替换很简单。到目前为止,我已经用每个数据集的名称创建了向量。
v=c("SP","SPF","SPP","NQ","RTY","NYA")
我通常使用这段代码重命名变量:
names(SP)[names(SP)=="Price"]="SPPrice"
我目前的尝试是:
for(i in 1:6)
{
names(v[[i]])[names(v[[i]])=="Price"]="v[[i]]Price"
}
R 在运行时没有给我任何错误,但似乎没有做任何事情。感谢任何帮助。
根据您的需要,您需要 get() and assign() functions since you are attempting to pass a string literal in the names()
attribute which expects a data frame object. Also, to concatenate variables with strings you need to use paste()。
考虑以下使用 lapply()(将函数应用于列表或向量和 returns 列表的递归方法);它将字段和 returns 每个数据帧重命名为数据帧列表。然后,for
循环使用 assign()
:
v=c("SP","SPF","SPP","NQ","RTY","NYA")
dfList <- lapply(v, function(x) {
df <- get(x)
names(df)[grep("Price", names(df))] <- paste0(x, "Price")
return(df)
})
for (i in 1:length(v)) {
assign(v[[i]], as.data.frame(dfList[[i]]))
}
rm(dfList)
这里有一些替代方案。
1) Base R 设置e
为数据帧的环境。这里我们假设他们在当前环境中。有了这个 e[[nm]]
指的是名称为变量 nm
中保存的字符串的数据框,因此以下工作就地修改名称:
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 这里我们定义了一个函数,它接受数据框的名称和环境并修改数据框的名称.我们使用 match
而不是 ==
以便 from
和 to
可以选择性地作为名称向量。此解决方案中的就地修改并不真正符合 R 的功能性质的精神,但我们将其作为替代方案展示:
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) 返回副本的基本 R 函数 这里我们定义了一个函数,它接受数据框本身和 returns 一个名称已更改的副本。该函数本身不需要处理环境,并且本质上更具功能性(即它不修改其输入)——调用者负责将结果分配回去。
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"))
doBy 包中的 2) doBy::renameCol renameCol
与 (1b) 中的 rename1b
插件兼容,因此:
library(doBy)
e <- environment()
for(nm in v) e[[nm]] <- renameCol(e[[nm]], "Price", paste0(nm, "Price"))
3) plyr::rename plyr 包有一个rename
函数。请注意,与 (1b) 一样,它会生成包含重命名列的数据框副本,因此我们将其分配回去:
e <- environment()
for(nm in v) e[[nm]] <- plyr::rename(e[[nm]], list(Price = paste0(nm, "Price")))
reshape 包有一个类似的功能,也称为 rename
,如果我们将 plyr::rename
替换为 reshape::rename
,则上述功能有效。
4) gtools::defmacro 也可以在 gtools 中使用 defmacro
创建一个宏来改变名称。虽然这不是 R 中的典型处理,但这确实允许传递数据框本身,而不是像 (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"))
另请参阅 R News 2001/3 中 Thomas Lumley 的程序员专栏文章。
注 1:您可能希望首先检查为什么要进行这些名称更改。还有一个问题是,数据框是应该在全局环境中自由定义,还是应该合并到一个列表中,因为我们想要处理它们。第一个 Map
创建一个命名列表 L
,例如,L$SP
或 L[["SP"]]
引用 L
中的 SP
组件。第二个 Map
输出一个新的命名列表,其组件具有新的列名:
L <- Map(get, v) # create named list of input data frames
Map(rename1b, L, "Price", paste0(names(L), "Price"))
注 2: 这里我们创建一些输入以使用内置数据框 BOD
进行测试。这将创建与数据框 BOD
相同的对象 SP
、SPF
等,除了第二列名为 "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")))