web-dev-qa-db-fra.com

La mise à jour de la trame de données via la fonction ne fonctionne pas

J'ai rencontré un petit problème avec R…

Dans le bloc de données suivant

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

Je souhaite modifier les valeurs de v2 dans les lignes où v1 vaut 1.

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

fonctionne très bien.

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

Cependant, je dois le faire dans une fonction.

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

L'appel de la fonction semble fonctionner.

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

Cependant, quand je regarde maintenant le test:

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

ça n'a pas marché. Existe-t-il une commande qui indique à R de vraiment mettre à jour la trame de données dans la fonction? Merci beaucoup pour toute aide!

33
donodarazao

test dans votre fonction est un copie de l'objet de votre environnement global (je suppose que c'est là qu'il est défini). L'affectation se produit dans l'environnement actuel, sauf indication contraire, vous devez donc indiquer à R que vous souhaitez affecter la copie locale de test au test dans le .GlobalEnv.

Et c'est une bonne forme de passer tous les objets nécessaires comme arguments à la fonction.

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

Personnellement, je ferais return(test) et ferais l'affectation en dehors de la fonction, mais je ne sais pas si vous pouvez le faire dans votre situation réelle.

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
46
Joshua Ulrich

Changer le <- en << - dans votre fonction, fait le astuce aussi, voir le R-manual . Citation de cette page:

Les opérateurs << - et - >> ne sont normalement utilisés que dans les fonctions et provoquent une recherche dans les environnements parents pour une définition existante de la variable affectée. Si une telle variable est trouvée (et que sa liaison n'est pas verrouillée), sa valeur est redéfinie, sinon l'affectation a lieu dans l'environnement global.

Votre code doit alors être:

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)
24
AnitaD

Il est recommandé de ne pas modifier les variables globales dans les fonctions, car cela peut avoir des effets indésirables effets secondaires . Pour éviter cela dans R, toute modification apportée aux objets à l'intérieur d'une fonction ne modifie en fait que les copies locales du environment de cette fonction.

Si vous voulez vraiment changer de test, vous devez affecter la valeur de retour de la fonction à tester (il serait préférable d'écrire la fonction avec une valeur de retour plus explicite,

 test <- test.fun(1)

Ou choisissez l'environnement global à affecter à l'intérieur de test.fun,

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

Je pense que cela se produit en raison des différents environments qui sont évalués. Votre fonction copie test de l'environnement global dans un environnement local temporaire (qui est créé lors de l'appel de fonction) puis test est uniquement évalué (c'est-à-dire modifié) dans cet environnement local.

Vous pouvez résoudre ce problème en utilisant la super-affectation <<-, mais cela n'est PAS recommandé et entraînera d'horribles problèmes imprévus (votre ordinateur attrape un virus, votre petite amie commence à vous tromper, ...).

Généralement, la solution donnée par Joshua Ulrich est la voie à suivre pour ce genre de problèmes. Vous passez l'objet d'origine et le retournez. Lors d'un appel de fonction, vous affectez le résultat à votre objet d'origine.

2
Henrik

Vous pouvez écrire une fonction de remplacement. Il s'agit d'une fonction avec un nom qui se termine par '<-' et l'enveloppe essentiellement dans un:

foo = bar (foo)

emballage. Donc dans votre cas:

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

Notez que vous devez citer le nom de la fonction lors de la création ou R se confond.

2
Spacedman

* J'ai créé une fonction appelée read__csv Je veux accéder à ces mêmes données à une autre fonction 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)
0
Mr S Coder