关于可能重复的编辑:
proposed link有助于了解问题的来源(我已将其作为第1条评论发布)。
但是我的问题是如何解决在函数中调用setnames的具体问题,而不仅仅是了解正在发生的事情,而不是直接在那里解决。使用copy
可能是一种选择,可能还有其他选择。
到目前为止,这个问题有2条赞成没有评论,请说出来如果我可以改进它。
data.tables::setnames
通过引用修改值,在下面的情况下,它似乎会导致意外行为(至少对我来说意外)。
我找到了一种处理它的丑陋方式,但可能有更好的系统方法,所以我希望你的建议。
奇怪的行为
df1 <- data.frame(a=1,b="x")
f1 <- function(df2){
setnames(df2,"b","c")
df2
}
f1(df1)
# a c
# 1 1 x
df1
# a c
# 1 1 x
df1已被修改
如果我复制该怎么办?
df1 <- data.frame(a=1,b="x")
f1 <- function(df2){
df3 <- df2
setnames(df3,"b","c")
df3
}
f1(df1)
# a c
# 1 1 x
df1
# a c
# 1 1 x
没了
如果我制作副本并“假装改变”但不要
df1 <- data.frame(a=1,b="x")
f1 <- function(df2){
df3 <- subset(df2) # note: it doesn't work with `identity`, EDIT: we can also use `data.table::copy`
setnames(df3,"b","c")
df3
}
f1(df1)
# a c
# 1 1 x
df1
# a b
# 1 1 x
它有效
我该怎么做?这是一个错误吗?
编辑:我发现data.table有一个copy
函数比我使用subset
答案 0 :(得分:2)
我认为这是预期的行为,因为df2
指向与df1
相同的对象。您可以通过以下方式看到:
library(pryr)
library(data.table)
df1 <- data.frame(a=1,b="x")
address(df1)
#[1] "0000000002892318" (will be different for others)
f_address<-function(df2) print(address(df2))
f_address(df1)
#[1] "0000000002892318"
由于setnames
会按引用更改输入,因此在更改df2
时,它会更改df1
和df2
指向的对象。
要更改此设置,您可以创建自己的功能,明确复制df1
然后修改它:
setnames_copy <- function(x, old, new){
y <- copy(x)
setnames(y, old, new)
}
f2 <- function(df2){
setnames_copy(df2, "b", "c")
}
df3 <- f2(df1)
df3
# a c
#1 1 x
df1
# a b
#1 1 x
如您所见,df1
未经修改。
答案 1 :(得分:0)
受@ mike-h解决方案的启发,这里的功能类似于设置名称,除非您在定义输入的环境之外使用setnames创建副本。 / p>
library(pryr)
setnames2 <- function(`$$`,old,new,verbose = FALSE){
var_name <- as.character(substitute(`$$`))
calling_env_objects <- sapply(ls(envir=parent.frame(n=2)),. %>% get(envir=parent.frame(n=2)) %>% address)
copied_object <- calling_env_objects[calling_env_objects == address(`$$`)]
if(length(copied_object) ==0){ # if the address isn't used in the calling environment's calling environment
if(verbose){cat("use regular setnames\n")}
setnames(`$$`,old,new)
} else if (length(copied_object) ==1){ # if the address is already in use in the calling environment's calling environment
if(verbose){cat("create copy then use setnames on it and assign to relevant environment\n")}
y <- copy(`$$`);setnames(y, old, new);assign(var_name,y,envir=parent.frame())
} else {print("you shouldn't go around naming objects `$$`...")}
}
df1 <- data.frame(a=1,b="x")
f3 <- function(df2){
setnames2(df2,"b","c",verbose=TRUE)
print(df2)
}
f3(df1)
# create copy then use setnames on it and assign to relevant environment
# a c
# 1 1 x
df1
# a b
# 1 1 x
f4 <- function(df2){
df2 <- copy(df2)
setnames2(df2,"b","c",verbose=TRUE)
print(df2)
}
f4(df1)
# use regular setnames
# a c
# 1 1 x
df1
# a b
# 1 1 x