programación - manual de r estadistica en español
¿Cuáles son las diferencias entre “=” y “<-” en R? (7)
¿Cuáles son las diferencias entre los operadores de asignación
=
y<-
en R?
Como muestra su ejemplo, =
y <-
tienen una precedencia de operadores ligeramente diferente (lo que determina el orden de evaluación cuando se mezclan en la misma expresión). De hecho ?Syntax
en R da la siguiente tabla de precedencia de operadores, de mayor a menor:
… ‘-> ->>’ rightwards assignment ‘<- <<-’ assignment (right to left) ‘=’ assignment (right to left) …
¿Pero es esta la única diferencia?
Como preguntaba sobre los operadores asignados : sí, esa es la única diferencia. Sin embargo, sería perdonado por creer lo contrario. Incluso la documentación R de ?assignOps
afirma que hay más diferencias:
El operador
<-
se puede usar en cualquier lugar, mientras que el operador=
solo se permite en el nivel superior (por ejemplo, en la expresión completa escrita en el símbolo del sistema) o como una de las subexpresiones en una lista de expresiones preparadas.
No le pongamos demasiada importancia: la documentación de R es (sutilmente) incorrecta [ http://developer.r-project.org/equalAssign.html ] . Esto es fácil de mostrar: solo tenemos que encontrar un contraejemplo del operador =
que no esté (a) en el nivel superior, ni (b) una subexpresión en una lista de expresiones preparadas (es decir, {…; …}
). - Sin más preámbulos:
x
# Error: object ''x'' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
Claramente, hemos realizado una tarea, utilizando =
, fuera de los contextos (a) y (b). Entonces, ¿por qué la documentación de una característica del lenguaje R central ha sido incorrecta durante décadas?
Es porque en la sintaxis de R el símbolo =
tiene dos significados distintos que se combinan rutinariamente:
- El primer significado es como un operador de asignación . Esto es todo lo que hemos hablado hasta ahora.
- El segundo significado no es un operador, sino un token de sintaxis que señala un argumento con nombre que pasa en una llamada de función. A diferencia del operador
=
, no realiza ninguna acción en tiempo de ejecución, simplemente cambia la forma en que se analiza una expresión.
Veamos.
En cualquier pieza de código de la forma general ...
‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
... el =
es el token que define el paso del argumento con nombre: no es el operador de asignación. Además, =
está totalmente prohibido en algunos contextos sintácticos:
if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
Cualquiera de estos generará un error "inesperado ''='' en ‹bla›".
En cualquier otro contexto, =
refiere a la llamada del operador de asignación. En particular, simplemente poner paréntesis alrededor de la subexpresión hace que cualquiera de los anteriores (a) sea válido y (b) una asignación . Por ejemplo, lo siguiente realiza una tarea:
median((x = 1 : 10))
Pero también:
if (! (nf = length(from))) return()
Ahora puede objetar que dicho código es atroz (y puede que tenga razón). Pero tomé este código de la función base::file.copy
(reemplazando <-
con =
) - es un patrón generalizado en gran parte de la base de código de Core R.
La http://developer.r-project.org/equalAssign.html , en la que probablemente se basa la documentación de la R, explica esto correctamente:
[
=
asignación está permitida] solo en dos lugares de la gramática: en el nivel superior (como un programa completo o una expresión escrita por el usuario); y cuando se aísla de la estructura lógica circundante, mediante llaves o un par extra de paréntesis.
Una confesión: mentí antes. Hay una diferencia adicional entre los operadores =
y <-
: llaman funciones distintas. Por defecto, estas funciones hacen lo mismo pero puede anular cualquiera de ellas por separado para cambiar el comportamiento. Por el contrario, <-
y ->
(asignación de izquierda a derecha), aunque sintácticamente distintas, siempre llaman a la misma función. Anular uno también anula al otro. Saber esto rara vez es práctico, pero se puede usar para algunos chanchullos divertidos .
¿Cuáles son las diferencias entre los operadores de asignación =
y <-
en R?
Sé que los operadores son ligeramente diferentes, como muestra este ejemplo
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
¿Pero es esta la única diferencia?
Esto también puede aumentar la comprensión de la diferencia entre esos dos operadores:
df <- data.frame(
a = rnorm(10),
b <- rnorm(10)
)
Para el primer elemento, R tiene valores asignados y nombre propio, mientras que el nombre del segundo elemento parece un poco extraño.
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 versión 3.3.2 (2016-10-31); macOS Sierra 10.12.1
La diferencia en los operadores de asignación es más clara cuando los usa para establecer un valor de argumento en una llamada de función. Por ejemplo:
median(x = 1:10)
x
## Error: object ''x'' not found
En este caso, x
se declara dentro del alcance de la función, por lo que no existe en el espacio de trabajo del usuario.
median(x <- 1:10)
x
## [1] 1 2 3 4 5 6 7 8 9 10
En este caso, se declara x
en el espacio de trabajo del usuario, por lo que puede usarlo una vez que se haya completado la llamada a la función.
Existe una preferencia general entre la comunidad R por usar <-
para la asignación (excepto en firmas de funciones) por compatibilidad con versiones (muy) antiguas de S-Plus. Tenga en cuenta que los espacios ayudan a aclarar situaciones como
x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3
La mayoría de los IDE R tienen métodos abreviados de teclado para hacer que <-
sea más fácil de escribir. Ctrl + = en Arquitecto, Alt + - en RStudio ( Opción + - bajo macOS), Shift + - (guión bajo) en emacs + ESS.
Si prefiere escribir =
a <-
pero desea usar el símbolo de asignación más común para el código publicado públicamente (en CRAN, por ejemplo), puede usar una de las funciones tidy_*
en el paquete formatR
para reemplazar automáticamente =
con <-
.
library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5
La respuesta a la pregunta "¿Por qué x <- y = 5
arroja un error pero no x <- y <- 5
?" es "Se trata de la magia contenida en el analizador". La sintaxis de R contiene muchos casos ambiguos que deben resolverse de una forma u otra. El analizador elige resolver los bits de la expresión en diferentes órdenes dependiendo de si se usó =
o <-
.
Para comprender lo que está sucediendo, debe saber que la asignación devuelve silenciosamente el valor asignado. Puede verlo más claramente imprimiendo explícitamente, por ejemplo, print(x <- 2 + 3)
.
En segundo lugar, es más claro si usamos la notación de prefijo para la asignación. Asi que
x <- 5
`<-`(x, 5) #same thing
y = 5
`=`(y, 5) #also the same thing
El analizador interpreta x <- y <- 5
como
`<-`(x, `<-`(y, 5))
Podríamos esperar que x <- y = 5
sería entonces
`<-`(x, `=`(y, 5))
pero en realidad se interpreta como
`=`(`<-`(x, y), 5)
Esto se debe a que =
tiene una prioridad menor que <-
, como se muestra en la página de ayuda ?Syntax
.
La guía de estilo R de Google simplifica el problema al prohibir el "=" para la asignación. No es una mala elección.
https://google.github.io/styleguide/Rguide.xml
El manual R entra en detalle en los 5 operadores de asignación.
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
Los operadores <-
y =
asignan al entorno en el que son evaluados. El operador <-
se puede usar en cualquier lugar, mientras que el operador =
solo se permite en el nivel superior (por ejemplo, en la expresión completa escrita en el símbolo del sistema) o como una de las subexpresiones en una lista de expresiones preparadas.
Según John Chambers, el operador =
solo se permite en "el nivel superior", lo que significa que no está permitido en las estructuras de control como if
, lo que hace que el siguiente error de programación sea ilegal.
> if(x = 0) 1 else x
Error: syntax error
Mientras escribe, "no permitir la nueva forma de asignación [=] en las expresiones de control evita errores de programación (como el ejemplo anterior) que son más probables con el operador igual que con otras S asignaciones".
Puedes hacer esto si está "aislado de la estructura lógica circundante, con llaves o un par de paréntesis extra", por lo que if ((x = 0)) 1 else x
funcionaría.
x = y = 5
es equivalente a x = (y = 5)
, porque los operadores de asignación "agrupan" de derecha a izquierda, lo que funciona. Significado: asigna 5 a y
, dejando el número 5; y luego asigna ese 5 a x
.
Esto no es lo mismo que (x = y) = 5
, ¡lo cual no funciona! Significado: asigne el valor de y
a x
, dejando el valor de y
; y luego asigna 5 a, umm ..., ¿qué es exactamente?
Cuando mezcla los diferentes tipos de operadores de asignación, <-
enlaza más apretado que =
. Entonces x = y <- 5
se interpreta como x = (y <- 5)
, que es el caso que tiene sentido.
Desafortunadamente, x <- y = 5
se interpreta como (x <- y) = 5
, que es el caso que no funciona.
Consulte ?Syntax
y ?assignOps
para las ?assignOps
de precedencia (enlace) y agrupación.