【问题标题】:Update data frame via function doesn't work通过函数更新数据框不起作用
【发布时间】:2011-04-27 13:24:13
【问题描述】:

我在使用 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 function dataframe


    【解决方案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你要将test的本地副本分配给.GlobalEnv中的test

    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
    

    不过,以这种方式使用 assign&lt;&lt;- 相当少见,许多有经验的 R 程序员会建议不要这样做。

    【讨论】:

      【解决方案2】:

      在您的函数中将 更改为 也可以解决问题, 见R-manual。从该页面引用:

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

      你的代码应该是:

      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)
      

      【讨论】:

        【解决方案3】:

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

        如果真要改test,就得把函数的返回值赋值给test(函数最好写一个返回值更明确的,

         test <- test.fun(1)
        

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

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

        【讨论】:

          【解决方案4】:

          我认为这是因为评估的 environments 不同。您的函数将 test 从全局环境复制到临时本地环境(在函数调用时创建),然后 test 仅在此本地环境中评估(即更改)。

          你可以通过使用超级赋值&lt;&lt;-来解决这个问题,但不推荐这样做,这会导致可怕的不可预见的问题(你的电脑感染了病毒,你的女朋友开始欺骗你,.. .).

          一般来说,Joshua Ulrich 给出的解决方案是解决这类问题的方法。您传递原始对象并返回它。在函数调用时,您将结果分配给原始对象。

          【讨论】:

            【解决方案5】:

            你可以写一个替换函数。这是一个名称以 '

            foo = bar(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 会感到困惑。

            【讨论】:

              【解决方案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)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-03-09
                • 1970-01-01
                • 2013-11-07
                相关资源
                最近更新 更多