我对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在运行时没有给我任何错误,但似乎没有做任何事情。任何帮助,不胜感激。
这里有一些替代方案。
1( 基本 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( 基本 R 传递名称和环境的函数 在这里,我们定义一个函数,该函数采用数据框和环境的名称,并就地修改数据框的名称。 我们使用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 函数返回副本 在这里,我们定义了一个函数,该函数获取数据框本身并返回名称已更改的副本。 该函数本身不需要处理环境,并且本质上更具功能性(即它不修改其输入(——调用者负责将结果赋回。
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::重命名 doBy 软件包中的 renameCol
与 (1b( 中的rename1b
插头兼容,因此:
library(doBy)
e <- environment()
for(nm in v) e[[nm]] <- renameCol(e[[nm]], "Price", paste0(nm, "Price"))
3( plyr::重命名 plyr 包具有rename
功能。 请注意,与 (1b( 一样,它会生成包含重命名列的数据框的副本,因此我们将其重新分配:
e <- environment()
for(nm in v) e[[nm]] <- plyr::rename(e[[nm]], list(Price = paste0(nm, "Price")))
重塑包具有类似的功能,也称为rename
,如果我们将plyr::rename
替换为 reshape::rename
,则上述功能有效。
4( gtools::d efmacro 也可以在 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的Programmer's Niche文章。
注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")))
为了满足您的需求,您将需要 get(( 和 assign(( 函数,因为您正在尝试在 names()
属性中传递一个需要数据框对象的字符串文字。此外,要将变量与字符串连接起来,您需要使用 paste((。
考虑以下使用 lapply(((一种将函数应用于列表或向量并返回列表的递归方法(;它重命名字段并将每个数据框返回到数据框列表中。然后,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)