Подтвердить что ты не робот

Оператор "[<-" в RStudio и R

Случайно я столкнулся с странным поведением оператора "[<-". Он ведет себя по-разному в зависимости от порядка вызовов и использует ли RStudio или просто обычный RGui. Я расскажу вам пример.

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

Насколько я знаю, первое совпадение не должно меняться x (или, может быть, я ошибаюсь?), а второй должен делать. И фактически результат вышеописанных операций

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

Однако, когда мы выполняем эти операции в другом порядке, результаты разные, а x изменилось! Сознательно:

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

Но это происходит только тогда, когда я использую простой R! В RStudio поведение в обоих вариантах одинаково. Я проверил его на двух машинах (один с Fedora с Win7), и ситуация выглядит точно так же. Я знаю, что "функциональная" версия ("[<-"(x..)), вероятно, никогда не используется, но мне очень любопытно, почему это происходит. Может ли кто-нибудь объяснить это?

==========================

EDIT: Хорошо, поэтому из комментариев я понял, что причина в том, что x <- 1:10 имеет тип "integer" и после замены x[5] <- 123 он "double". Но все еще остается вопрос, почему поведение в RStudio отличается? Я перезапускаю сеанс R и ничего не меняю.

4b9b3361

Ответ 1

поведение Rstudio

Rstudio-объект-браузер изменяет объекты, которые он анализирует, таким образом, чтобы принудительное копирование было изменено. В частности, в обозревателе объектов используется по меньшей мере одна функция R, вызов которой внутренне принудительно оценивает объект, в процессе сброса значения поля объекта с именем от 1 до 2. Из Руководство по R-Internals:

Когда объект должен быть изменен, проконсультируется имя с именем. Значение 2 означает, что объект должен быть дублирован перед изменением. [...] Значение 1 используется для ситуаций [...], где в принципе две копии a существуют в течение всего времени вычисления [...], но уже нет, и поэтому некоторые примитивные функции могут быть оптимизированы чтобы избежать копирования в этом случае.

Чтобы увидеть, что браузер объектов изменяет поле с именем ([NAM()] в следующем блоке кода), сравните результаты выполнения следующих строк. В первом случае обе "линии" запускаются вместе, так что Rstudio не успевает "коснуться" X до того, как будет запрошена его структура. Во втором случае каждая строка вставляется отдельно, поэтому X изменяется до того, как будет проверено.

## 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,... 

Если для поля named установлено значение 2, [<-(X, ...) не будет изменять исходный объект. Вставка следующего в Rstudio сразу изменяет X, в то время как вставка его в строку-строку не выполняется:

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

Еще одно следствие всего этого заключается в том, что браузер объектов Rstudio фактически делает некоторые операции медленнее, чем в противном случае. Снова сравните те же две команды, которые сначала вставляются вместе, а затем по одному:

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

Измененное поведение [< - in R

Поведение [<- w.r.t. изменение вектора X зависит от типов хранения X и элемента, назначаемого ему. Это объясняет поведение R, но не Rstudio.

В R, когда [<- либо добавляется к вектору X, либо выполняет переназначение, требующее модификации типа X, копируется X, а возвращаемое значение не перезаписывает пре- существующая переменная X. (Для этого вам нужно сделать что-то вроде X <- "[<-(X, 2, 100).

Итак, ни одно из следующих изменений 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

Однако, если это возможно, R действительно позволяет функции [<- изменять X напрямую по ссылке (т.е. без создания копии). "Возможное" здесь включает случаи, когда подзадачи не требуют изменения типа X.

Итак, все следующие изменения 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