通过函数更新数据框不起作用

Update data frame via function doesn't work

提问人:donodarazao 提问时间:10/19/2010 更新时间:1/15/2020 访问量:47614

问:

我在使用 R 时遇到了一个小问题......

在以下数据框中

test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 

我想在 v1 为 1 的行中更改 v2 的值。

test[test$v1==1,"v2"] <- 10

工作得很好。

test
  v1 v2
1  1 10
2  1 10
3  1 10
4  2  0
5  2  0
6  2  0

但是,我需要在函数中执行此操作。

test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0)

test.fun <- function (x) {
    test[test$v1==x,"v2"] <- 10
    print(test)
}

调用该函数似乎有效。

test.fun(1)
  v1 v2
1  1 10
2  1 10
3  1 10
4  2  0
5  2  0
6  2  0

但是,当我现在查看测试时:

test
  v1 v2
1  1  0
2  1  0
3  1  0
4  2  0
5  2  0
6  2  0

它没有用。 是否有命令告诉 R 真正更新函数中的数据帧? 非常感谢您的帮助!

R 函数 数据帧

评论


答:

68赞 Joshua Ulrich 10/19/2010 #1

test在您的函数中是来自全局环境的对象的副本(我假设这是定义它的地方)。除非另有说明,否则赋值将在当前环境中进行,因此函数内部发生的任何更改仅适用于函数内部的副本,而不适用于全局环境中的对象。

将所有必要的对象作为参数传递给函数是一种很好的形式。

就我个人而言,我会在您的职能结束时进行职能之外的分配,但我不确定您是否可以在实际情况下这样做。return(test)

test.fun <- function (x, test) {
    test[test$v1==x,"v2"] <- 10
    return(test)
}
test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0)
(test <- test.fun(1, test))
#  v1 v2
#1  1 10
#2  1 10
#3  1 10
#4  2  0
#5  2  0
#6  2  0

如果绝对有必要直接修改函数外部的对象,则需要告诉 R 要将 的本地副本分配给 .testtest.GlobalEnv

test.fun <- function (x, test) {
    test[test$v1==x,"v2"] <- 10
    assign('test',test,envir=.GlobalEnv)
    #test <<- test  # This also works, but the above is more explicit.
}
(test.fun(1, test))
#  v1 v2
#1  1 10
#2  1 10
#3  1 10
#4  2  0
#5  2  0
#6  2  0

不过,以这种方式使用 or 是相当罕见的,许多有经验的 R 程序员会建议不要使用它。assign<<-

11赞 James 10/19/2010 #2

最好不要更改函数中的全局变量,因为这可能会产生不良的副作用。为了避免这种情况,在 R 中,对函数内部对象的任何更改实际上只更改该函数的 .environment

如果真的想更改 test,就必须赋值函数的返回值来测试(最好用更显式的返回值编写函数,

 test <- test.fun(1)

或者选择要在 中分配的全局环境 ,test.fun

test.fun <- function (x) {             
    test[test$v1==x,"v2"] <- 10             
    print(test)
    assign("test",test,.GlobalEnv)           
} 
3赞 Henrik 10/19/2010 #3

我认为发生这种情况是因为评估的不同。函数从全局环境复制到临时本地环境(在函数调用中创建),然后仅在此本地环境中进行评估(即更改)。environmentstesttest

您可以通过使用超级分配来克服此问题,但不建议这样做,并且会导致可怕的不可预见的问题(您的计算机感染了病毒,您的女朋友开始欺骗您,...)。<<-

一般来说,约书亚·乌尔里希(Joshua Ulrich)给出的解决方案是解决此类问题的方法。传递原始对象并返回它。在函数调用时,将结果分配给原始对象。

3赞 Spacedman 10/19/2010 #4

你可以编写一个替换函数。这是一个名称以“<-”结尾的函数,实质上是将其包装在:

foo = 条形图(foo)

包装纸。因此,就您而言:

> "setV2<-" = function (x,value,m){x[x$v1==m,"v2"]=value;return(x)}
> test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 
> setV2(test,1)=10
> test
  v1 v2
1  1 10
2  1 10
3  1 10
4  2  0
5  2  0
6  2  0
> setV2(test,2)=99
> test
  v1 v2
1  1 10
2  1 10
3  1 10
4  2 99
5  2 99
6  2 99

请注意,您必须在创建时引用函数名称,否则 R 会感到困惑。

29赞 AnitaD 3/6/2015 #5

将函数中的<更改为<<-也可以解决问题, 请参阅 R 手册。从该页面引用:

运算符 <<- 和 ->> 通常仅在函数中使用,并导致通过父环境搜索所分配变量的现有定义。如果找到这样的变量(并且其绑定未锁定),则重新定义其值,否则在全局环境中进行赋值。

然后,您的代码应为:

test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 

test.fun <- function (x) {
  test[test$v1==x,"v2"] <<- 10
  print(test)
}

test.fun(1)
0赞 Mr Coder 1/15/2020 #6

* 我创建了一个名为 read__csv 的函数,我想将相同的数据访问到其他 r 函数*

read__csv <- function(files_csv) {
  print(files_csv)
  # set R workign directory as current R file path
  setwd(system("pwd", intern = T) )
  print( getwd() )
  data<-read.csv(files_csv,header = TRUE,na.strings=0)
  print(data)
  assign("data", data, envir = .GlobalEnv)
 #create data varible to r global envrioment 
}

#R Funtion calling
read__csv("csv.csv")

print(data)