代码之家  ›  专栏  ›  技术社区  ›  donodarazao

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

  •  26
  • donodarazao  · 技术社区  · 14 年前

    我在使用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真正更新函数中的数据帧? 非常感谢您的帮助!

    5 回复  |  直到 10 年前
        1
  •  45
  •   Joshua Ulrich    14 年前

    test 你的职能是 复制 来自全局环境的对象(我假设这就是定义对象的地方)。除非另有规定,否则分配将在当前环境中进行,因此需要告诉R您要分配的本地副本 测试 测试 .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
    

    我个人会的 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
    
        2
  •  23
  •   AnitaD    10 年前

    改变 <- <<- 在你的功能中,也有技巧, 见 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
  •  8
  •   James    14 年前

    最好不要改变函数中的全局变量,因为这可能是不可取的。 side effects . 为了避免在R中出现这种情况,对函数内对象的任何更改实际上只更改该函数的本地副本。 environment .

    如果您真的想更改测试,就必须将函数的返回值赋给测试(最好用更明确的返回值编写函数,

     test <- test.fun(1)
    

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

    test.fun <- function (x) {             
        test[test$v1==x,"v2"] <- 10             
        print(test)
        assign("test",test,.GlobalEnv)           
    } 
    
        4
  •  2
  •   Henrik    14 年前

    我认为这是因为 environments 进行评估。您的功能副本 test 从全局环境到临时本地环境(在函数调用上创建),然后 测试 仅在此本地环境中进行评估(即更改)。

    你可以通过使用超级任务来克服这个问题。 <<- , 但这是不推荐的,并将导致可怕的不可预见的问题(你的电脑感染了病毒,你的女朋友开始欺骗你,…)。

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

        5
  •  2
  •   Spacedman    14 年前

    您可以编写一个替换函数。这是一个以“<-”结尾的函数,基本上用一个:

    Fo=棒(FO)

    包装器。所以在你的例子中:

    > "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会混淆。