Каковы различия между "=" и "<-" в R?

Каковы различия между операторами присваивания = а также <- в R?

Я знаю, что операторы немного отличаются, как показывает этот пример

x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"

Но единственная ли это разница?

9 ответов

Решение

Разница в операторах присваивания более очевидна, когда вы используете их для установки значения аргумента в вызове функции. Например:

median(x = 1:10)
x   
## Error: object 'x' not found

В этом случае, x объявляется в рамках функции, поэтому он не существует в рабочей области пользователя.

median(x <- 1:10)
x    
## [1]  1  2  3  4  5  6  7  8  9 10

В этом случае, x объявляется в рабочей области пользователя, поэтому вы можете использовать его после завершения вызова функции.


Существует общее предпочтение среди сообщества R для использования <- для назначения (кроме подписей функций) для совместимости с (очень) старыми версиями S-Plus. Обратите внимание, что пробелы помогают прояснить такие ситуации, как

x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3

Большинство RE IDE имеют сочетания клавиш, чтобы сделать <- легче набрать. Ctrl + = в Architect, Alt + - в RStudio (Option + - под macOS), Shift + - (подчеркивание) в emacs+ESS.


Если вы предпочитаете писать = в <- но вы хотите использовать более общий символ присваивания для общедоступного кода (например, в CRAN), тогда вы можете использовать один из tidy_* функции в formatR пакет для автоматической замены = с <-,

library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5

Ответ на вопрос "Почему x <- y = 5 выкинуть ошибку но не x <- y <- 5?" is " Дело до магии, содержащейся в синтаксическом анализаторе ". Синтаксис R содержит множество неоднозначных случаев, которые должны быть разрешены тем или иным способом. Парсер выбирает разрешение битов выражения в разных порядках в зависимости от того, = или же <- использовался.

Чтобы понять, что происходит, вам нужно знать, что назначение молча возвращает значение, которое было назначено. Вы можете увидеть это более четко, например, при явной печати print(x <- 2 + 3),

Во-вторых, понятнее, если мы будем использовать префиксную нотацию для присваивания. Так

x <- 5
`<-`(x, 5)  #same thing

y = 5
`=`(y, 5)   #also the same thing

Парсер интерпретирует x <- y <- 5 как

`<-`(x, `<-`(y, 5))

Можно ожидать, что x <- y = 5 будет тогда

`<-`(x, `=`(y, 5))

но на самом деле это интерпретируется как

`=`(`<-`(x, y), 5)

Это потому что = имеет более низкий приоритет, чем <-, как показано на ?Syntax страница справки.

Каковы различия между операторами присваивания = а также <- в R?

Как показывает ваш пример, = а также <- имеют немного другой приоритет оператора (который определяет порядок вычисления, когда они смешаны в одном выражении). По факту, ?Syntax в R дает следующую таблицу приоритетов операторов, от наивысшего к низшему:

…
‘-> ->>’           rightwards assignment
‘<- <<-’           assignment (right to left)
‘=’                assignment (right to left)
…

Но единственная ли это разница?

Поскольку вы спрашивали об операторах присваивания: да, это единственное отличие. Тем не менее, вы были бы прощены за веру в обратное. Даже документация R ?assignOps утверждает, что есть больше различий:

Оператор <- может использоваться где угодно, тогда как оператор = допускается только на верхнем уровне (например, в полном выражении, набранном в командной строке) или в качестве одного из подвыражений в ограниченном списке выражений.

Давайте не будем заострять внимание на этом: документация на R (слегка) неверна [ 1 ]. Это легко показать: нам просто нужно найти контрпример = оператор, который не является (а) на верхнем уровне и (б) подвыражением в ограниченном списке выражений (т.е. {…; …}). - Без дальнейших церемоний:

x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1

Очевидно, мы выполнили задание, используя = вне контекста (а) и (б). Итак, почему документация о ядре языка R была неправильной в течение десятилетий?

Это потому, что в синтаксисе R символ = имеет два разных значения, которые обычно смешиваются:

  1. Первое значение как оператор присваивания. Это все, о чем мы говорили до сих пор.
  2. Второе значение - это не оператор, а синтаксический маркер, который сигнализирует именованный аргумент, передаваемый в вызове функции. в отличие от = Оператор не выполняет никаких действий во время выполнения, он просто изменяет способ анализа выражения.

Посмотрим.

В любой части кода общего вида...

‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)

... то = это токен, который определяет именованную передачу аргумента: это не оператор присваивания. Более того, = полностью запрещено в некоторых синтаксических контекстах:

if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …

Любой из них вызовет ошибку "неожиданно" = "в‹ bla ›".

В любом другом контексте, = относится к вызову оператора присваивания. В частности, простое размещение скобок вокруг подвыражения делает любое из вышеуказанного (а) действительным и (б) присваиванием. Например, следующее выполняет назначение:

median((x = 1 : 10))

Но также:

if (! (nf = length(from))) return()

Теперь вы можете возразить, что такой код ужасен (и вы можете быть правы). Но я взял этот код из base::file.copy функция (замена <- с = ) - это широко распространенная модель в основной базе кода R.

Оригинальное объяснение Джона Чемберса, на котором, вероятно, основана документация R, действительно объясняет это правильно:

[ = присваивание] допускается только в двух местах грамматики: на верхнем уровне (в виде законченной программы или пользовательского выражения); и когда он изолирован от окружающей логической структуры, скобками или дополнительной парой скобок.


Признание: я солгал раньше. Существует еще одно различие между = а также <- операторы: они вызывают разные функции. По умолчанию эти функции делают то же самое, но вы можете переопределить любую из них отдельно, чтобы изменить поведение. В отличие от <- а также -> (присвоение слева направо), хотя синтаксически иное, всегда вызывает одну и ту же функцию. Переопределение одного переопределяет другое. Знание этого редко бывает практичным, но его можно использовать для забавных махинаций.

Руководство по стилю Google R упрощает проблему, запрещая "=" для назначения. Неплохой выбор.

https://google.github.io/styleguide/Rguide.xml

Руководство R подробно описывает все 5 операторов присваивания.

http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html

x = y = 5 эквивалентно x = (y = 5), потому что операторы присваивания "группа" справа налево, который работает. Значение: присвоить 5 y, оставив номер 5; а затем назначьте это 5 x,

Это не то же самое, что (x = y) = 5, который не работает! Значение: назначить значение y в x, оставляя значение y; а затем назначить 5, хм... что именно?

Когда вы смешиваете различные виды операторов присваивания, <- крепче, чем =, Так x = y <- 5 интерпретируется как x = (y <- 5), который имеет место, что имеет смысл.

К несчастью, x <- y = 5 интерпретируется как (x <- y) = 5, который не работает!

Увидеть ?Syntax а также ?assignOps для приоритета (связывания) и правил группировки.

По словам Джона Чемберса, оператор = разрешено только на "верхнем уровне", что означает, что это не разрешено в управляющих структурах, таких как if, что делает следующую ошибку программирования недопустимой.

> if(x = 0) 1 else x
Error: syntax error

Как он пишет, "Запрещение новой формы присваивания [=] в управляющих выражениях позволяет избежать ошибок программирования (таких как приведенный выше пример), которые более вероятны при использовании оператора равенства, чем при других присваиваниях S".

Вы можете сделать это, если она "изолирована от окружающей логической структуры скобками или дополнительной парой скобок", поэтому if ((x = 0)) 1 else x должно сработать.

Смотрите http://developer.r-project.org/equalAssign.html

Операторы <- а также = назначить в среду, в которой они оцениваются. Оператор <- может использоваться где угодно, тогда как оператор = допускается только на верхнем уровне (например, в полном выражении, набранном в командной строке) или в качестве одного из подвыражений в ограниченном списке выражений.

Это также может добавить к пониманию разницы между этими двумя операторами:

df <- data.frame(
      a = rnorm(10),
      b <- rnorm(10)
)

Для первого элемента R присвоены значения и собственное имя, тогда как имя второго элемента выглядит несколько странно.

str(df)
# 'data.frame': 10 obs. of  2 variables:
#  $ a             : num  0.6393 1.125 -1.2514 0.0729 -1.3292 ...
#  $ b....rnorm.10.: num  0.2485 0.0391 -1.6532 -0.3366 1.1951 ...

Версия R 3.3.2 (2016-10-31); macOS Sierra 10.12.1

Я не уверен, цитировалась ли здесь книга Патрика Бернса R inferno, где в 8.2.26 = не является синонимом <- Патрик заявляет: «Вы явно не хотите использовать '<-', когда вы хотите установить аргумент функция. ". Книга доступна по адресу https://www.burns-stat.com/documents/books/the-r-inferno/.

Существуют некоторые различия между и в прошлой версии R или даже в языке-предшественнике R (языке S). Но в настоящее время, похоже, используется=только как и любой другой современный язык (python, java) не вызовет никаких проблем. Вы можете добиться большей функциональности, используя при передаче значения некоторым дополнениям, а также одновременно создавая глобальную переменную, но она может иметь странное/нежелательное поведение, как в

      df <- data.frame(
      a = rnorm(10),
      b <- rnorm(10)
)
      str(df)
# 'data.frame': 10 obs. of  2 variables:
#  $ a             : num  0.6393 1.125 -1.2514 0.0729 -1.3292 ...
#  $ b....rnorm.10.: num  0.2485 0.0391 -1.6532 -0.3366 1.1951 ...

Настоятельно рекомендуется! Попробуйте прочитать эту статью, которая является лучшей статьей, которая пытается объяснить разницу между этими двумя: Проверьте https://colinfay.me/r-assignment/

Кроме того, подумайте о<-как функция, которая невидимо возвращает значение.

      a <- 2
(a <- 2)
#> [1] 2

См.: https://adv-r.hadley.nz/functions.html .

Другие вопросы по тегам