Atualizar frame de dados via function não funciona

Eu me deparei com um pequeno problema usando R…

No seguinte quadro de dados

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

Eu quero alterar os valores de v2 nas linhas em que v1 é 1.

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

funciona muito bem.

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

No entanto, preciso fazer isso em uma function.

 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) } 

Chamar a function parece funcionar.

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

No entanto, quando eu olho agora para o teste:

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

não funcionou. Existe um comando que diz ao R para realmente atualizar o quadro de dados na function? Muito obrigado por qualquer ajuda!

test em sua function é uma cópia do object do seu ambiente global (estou assumindo que é onde está definido). A atribuição acontece no ambiente atual, a menos que seja especificado de outra forma, portanto, é necessário informar ao R que você deseja atribuir a cópia local do test ao test no .GlobalEnv .

E é uma boa forma de passar todos os objects necessários como argumentos para a function.

 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 

Pessoalmente, gostaria de return(test) e fazer a atribuição fora da function, mas não tenho certeza se você pode fazer isso em sua situação real.

 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 

Mudando o <- para << - na sua function, faz o truque também, veja o manual R. Citar a partir dessa página:

Os operadores << - e - >> são normalmente usados ​​apenas em funções e fazem com que uma pesquisa seja feita através de ambientes pai para uma definição existente da variável que está sendo atribuída. Se essa variável for encontrada (e sua binding não estiver bloqueada), seu valor será redefinido, caso contrário, a atribuição ocorrerá no ambiente global.

Seu código deve então ser:

 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) 

É uma boa prática não alterar variables ​​globais em funções, porque isso pode ter efeitos colaterais indesejáveis. Para evitar isso em R, quaisquer alterações em objects dentro de uma function, na verdade, apenas alteram as cópias que são locais para o environment dessa function.

Se você realmente quer mudar o teste, você tem que atribuir o valor de retorno da function para testar (seria melhor escrever a function com um valor de retorno mais explícito,

  test <- test.fun(1) 

Ou escolha o ambiente global para atribuir a test.fun ,

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

Eu acho que isso acontece por causa dos diferentes environments que são avaliados. Sua function copia o test do ambiente global em um ambiente local temporário (que é criado na chamada de function) e, em seguida, o test é avaliado apenas (ou seja, alterado) neste ambiente local.

Você poderia superar esse problema usando o super-assignment <<- , mas isso não é recomendado e levará a problemas imprevistos terríveis (seu computador pega um vírus, sua namorada começa a trair você, ...).

Geralmente a solução dada por Joshua Ulrich é o caminho a percorrer neste tipo de problemas. Você passa o object original e o devolve. Na chamada de function, você atribui o resultado ao seu object original.

Você poderia escrever uma function de substituição. Esta é uma function com um nome que termina em ‘<-' e essencialmente o envolve em:

foo = bar (foo)

embrulho. Então, no seu caso:

 > "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 

Note que você tem que citar o nome da function na criação ou R fica confuso.