42 votes

Opérateur "[<-" dans RStudio et R

Par hasard, j'ai rencontré un comportement étrange de "[<-" opérateur. Il se comporte différemment selon l'ordre des appels et selon que j'utilise RStudio ou un simple RGui. Je vais me faire comprendre avec un exemple.

x <- 1:10
"[<-"(x, 1, 111)
x[5] <- 123

Pour autant que je sache, la première affectation ne devrait pas changer. x (ou peut-être ai-je tort ?), alors que la seconde devrait suffire. Et en fait, le résultat des opérations ci-dessus est

x
[1]  1  2  3  4  123  6  7  8  9 10

Cependant, lorsque nous effectuons ces opérations dans un ordre différent, les résultats sont différents et x a changé ! Méchamment :

x <- 1:10
x[5] <- 123
"[<-"(x, 1, 111)
x
[1] 111   2   3   4   123   6   7   8   9  10

Mais cela ne se produit que lorsque j'utilise R ordinaire ! Dans RStudio, le comportement est le même dans les deux options. Je l'ai vérifié sur deux machines (l'une avec Fedora, l'autre avec Win7) et la situation est exactement la même. Je sais que la version "fonctionnelle" ( "[<-"(x..) ) n'est probablement jamais utilisé mais je suis très curieux de savoir pourquoi cela se produit. Quelqu'un peut-il l'expliquer ?

\==========================

EDIT : Ok, donc d'après les commentaires j'ai compris que la raison était que x <- 1:10 a le type "integer" et après avoir remplacé x[5] <- 123 c'est "double". Mais la question demeure : pourquoi le comportement est-il différent dans RStudio ? Je redémarre la session R et cela ne change rien.

36voto

Josh O'Brien Points 68397

Le comportement de Rstudio

Le navigateur d'objets de Rstudio modifie les objets qu'il examine d'une manière qui force la copie lors de la modification. Plus précisément, le navigateur d'objets utilise au moins une fonction R dont l'appel interne force l'évaluation de l'objet, ce qui réinitialise la valeur de l'attribut nommé de 1 à 2. Dans le champ Manuel R-Internals :

Lorsqu'un objet est sur le point d'être modifié, le champ nommé est consulté. Une valeur de 2 signifie que l'objet doit être dupliqué avant d'être modifié. [Une valeur de 1 est utilisée pour les situations [...] où, en principe, deux copies d'un objet existent pour la durée du calcul [...] mais pas pour plus longtemps, et donc certaines fonctions primitives peuvent être optimisées pour éviter une copie dans ce cas.

Pour voir que le navigateur d'objets modifie le nommé champ ( [NAM()] dans le bloc de code suivant), comparez les résultats de l'exécution des lignes suivantes. Dans la première, les deux "lignes" sont exécutées en même temps, de sorte que Rstudio n'a pas le temps de "toucher" le code. X avant que sa structure ne soit interrogée. Dans la seconde, chaque ligne est collée séparément, donc X est modifié avant d'être examiné.

## Pasted in together
x <- 1:10; .Internal(inspect(x))
# @46b47b8 13 INTSXP g0c4 [NAM(1)] (len=10, tl=0) 1,2,3,4,5,...

## Pasted in with some delay between lines
x <- 1:10
.Internal(inspect(x))
# @42111b8 13 INTSXP g0c4 [NAM(2)] (len=10, tl=0) 1,2,3,4,5,... 

Une fois que le nommé est réglé sur 2, [<-(X, ...) ne modifiera pas l'objet original. En collant les éléments suivants dans Rstudio en une seule fois, on modifie X alors que le coller ligne par ligne ne le fait pas :

x <- 1:10
"[<-"(x, 1, 111)

Une autre conséquence de tout cela est que le navigateur d'objets de Rstudio rend en fait certaines opérations plus lentes qu'elles ne le seraient autrement. Comparez à nouveau les deux mêmes commandes, d'abord collées ensemble, puis l'une après l'autre :

## Pasted in together
x <- 1:5e7
system.time(x[1] <- 9L)
#    user  system elapsed 
#       0       0       0 

## Pasted in one at a time
x <- 1:5e7
system.time(x[1] <- 9L)
#    user  system elapsed 
#    0.11    0.04    0.16 

Comportement variable de [<- en R

Le comportement de [<- par rapport à la modification d'un vecteur X dépend des types de stockage de X et de l'élément qui y est affecté. Ceci explique R mais pas celui de Rstudio.

En R, lorsque [<- soit ajouter à un vecteur X ou effectue une sous-affectation qui exige que X Le type de l'utilisateur est modifié, X est copiée et la valeur qui est retournée n'écrase pas la variable préexistante X . (Pour cela, vous devez faire quelque chose comme X <- "[<-(X, 2, 100) .

Ainsi, aucun des éléments suivants ne modifie X

X <- 1:2         ## Note: typeof(X) --> "integer"

## Subassignment that requires that X be coerced to "numeric" type
"[<-"(X, 2, 100) ## Note: typeof(100) --> "numeric"
X 
# [1]   1   2

## Appending to X
"[<-"(X, 3, 100L)
X
# [1]   1   2

Dans la mesure du possible, cependant, R permet à l'utilisateur d'avoir accès à l'information. [<- pour modifier la fonction X directement par référence (c'est-à-dire sans faire de copie). "Possible" inclut ici les cas où une sous-cession n'exige pas que X Le type de l'utilisateur est modifié.

Ainsi, tous les éléments suivants modifient X

X <- c(0i, 0i, 0i, 0i)
"[<-"(X, 1, TRUE)
"[<-"(X, 2, 20L)
"[<-"(X, 3, 3.14)
"[<-"(X, 4, 5+5i)
X
# [1]  1.00+0i 20.00+0i  3.14+0i  5.00+5i

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X