SAS 宏变量的 R 版本



我对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而不是==,以便fromto可以选择成为名称的向量。此解决方案中的就地修改实际上并不符合 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$SPL[["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相同的对象SPSPF等,只是第二列名为 "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)

最新更新