= 1:5
x <- 1:5
y
all.equal(x, y)
[1] TRUE
rm(x, y)
=
ou <-
?Vinicius Oike
July 11, 2023
Há dois operadores para definir um objeto no R: =
e <-
. A maior parte dos usuários parece preferir o último apesar dele parecer um tanto inconveniente. Em teclados antigos, havia uma tecla específica com o símbolo <-
, mas em teclados ABNT modernos ele exige três teclas para ser escrito.
Para contornar este incômodo é comum criar um atalho no teclado para esse símbolo; o RStudio, por exemplo, tem um atalho usando a teclas Alt
e -
em conjunto. Mas ainda assim fica a questão: por que não utilizar o =
? A resposta curta é que o símbolo <-
é a melhor e mais consistente forma de definir objetos R. Na prática, contudo, há poucas diferenças entre as expressões e elas dificilmente vão fazer alguma diferença. Podemos começar com um exemplo bastante simples para entender estas diferenças.
O código abaixo cria duas variáveis, x
e y
, cujos valores são a sequência \(1, 2, 3, 4, 5\). Até aí tudo igual. A função all.equal
certifica que os objetos são iguais e a função rm
“deleta” os objetos. Esta última vai ser conveniente para manter os exemplos organizados.
Agora considere o código abaixo. A função median
está sendo aplicada em x <- 1:5
. O que acontece desta vez? O resultado é que é criada uma variável x
com valor 1 2 3 4 5
e também é impresso a mediana deste vetor, i.e., 3
.
Poderíamos fazer o mesmo usando =
, certo? Errado. Aí está uma das primeiras diferenças entre estes operadores. O código abaixo calcula a mediana do vetor, mas não cria um objeto chamado x
com valor 1 2 3 4 5
. Por quê? O problema é que o operador =
tem duas finalidades distintas. Ele serve tanto para definir novos objetos, como em x = 2
, como também para definir o valor dos argumentos de uma função, como em rnorm(n = 10, mean = 5, sd = 1)
. Coincidentemente, o nome do primeiro argumento da função median
é x. Logo, o código abaixo é interpretado como: tire a mediana do vetor 1 2 3 4 5
. O mesmo acontece com outras funções (ex: mean
, var
, etc.)
[1] 3
Error in eval(expr, envir, enclos): object 'x' not found
Warning in rm(x): object 'x' not found
Outro exemplo em que há divergência entre os operadores é com o comando lm
. Usando <-
podemos escrever, numa única linha, um comando que define um objeto lm
(resultado de uma regressão) ao mesmo tempo em que pedimos ao R para imprimir os resultados desta regressão. O código abaixo faz justamente isto.
# Imprime os resultados da regressão e salva as info num objeto chamado 'fit'
summary(fit <- lm(mpg ~ wt, data = mtcars))
Call:
lm(formula = mpg ~ wt, data = mtcars)
Residuals:
Min 1Q Median 3Q Max
-4.5432 -2.3647 -0.1252 1.4096 6.8727
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 37.2851 1.8776 19.858 < 2e-16 ***
wt -5.3445 0.5591 -9.559 1.29e-10 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 3.046 on 30 degrees of freedom
Multiple R-squared: 0.7528, Adjusted R-squared: 0.7446
F-statistic: 91.38 on 1 and 30 DF, p-value: 1.294e-10
[1] "lm"
Note que isto não é possível com o operador =
. Isto acontece, novamente, porque o =
é interpretado de maneira diferente quando aparece dentro de uma função. É necessário quebrar o código em duas linhas.
Error in summary.lm(fit = lm(mpg ~ wt, data = mtcars)): argument "object" is missing, with no default
Call:
lm(formula = mpg ~ wt, data = mtcars)
Residuals:
Min 1Q Median 3Q Max
-4.5432 -2.3647 -0.1252 1.4096 6.8727
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 37.2851 1.8776 19.858 < 2e-16 ***
wt -5.3445 0.5591 -9.559 1.29e-10 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 3.046 on 30 degrees of freedom
Multiple R-squared: 0.7528, Adjusted R-squared: 0.7446
F-statistic: 91.38 on 1 and 30 DF, p-value: 1.294e-10
Há também algumas pequenas divergências pontuais. Os primeiros dois argumentos da função lm
são formula
e data
. Considere o código abaixo. Sem executar o código qual deve ser o resultado?
Estamos aplicando a função lm
em dois argumentos. O primeiro deles se chama formula
e é definido como mpg ~ wt
, o segundo é chamado data
e é definido como os valores no data.frame mtcars
. Ou seja, o resultado deve ser o mesmo do exemplo acima com median(x <- 1:5)
. A função é aplicada sobre os argumentos e os objetos formula
e data
são criados.
Call:
lm(formula = formula <- mpg ~ wt, data = data <- mtcars)
Coefficients:
(Intercept) wt
37.285 -5.344
mpg ~ wt
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Note que usei os nomes dos argumentos apenas para exemplificar o caso. Pode-se colocar um nome diferente, pois não estamos “chamando” o argumento e sim especificando qual valor/objeto a função deve utilizar.
Call:
lm(formula = a <- "mpg ~ wt", data = b <- mtcars)
Coefficients:
(Intercept) wt
37.285 -5.344
[1] "mpg ~ wt"
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
O mesmo não é possível com =
, por causa da duplicidade apontada acima.
Error in terms.formula(formula, data = data): argument is not a valid model
Há ainda mais alguns exemplos estranhos, resultados da ordem que o R processa os comandos. O segundo código abaixo, por exemplo, não funciona. Isto acontece porque o <-
tem “prioridade” e é lido primeiro.
É difícil encontrar desvatagens em usar o <-
(além da dificuldade de escrevê-lo num teclado normal). Mas há pelo menos um caso em que ele pode levar a problemas. O código abaixo mostra como este operador pode ser sensível a espaços em branco. No caso, define-se o valor de x
como -2
. O primeiro teste verifica se o valor de x
é menor que \(-1\). Logo, espera-se que o código imprima "ótimo"
pois -2
é menor que -1
. Já o segundo teste faz quase o mesmo. A única diferença é um espaço em branco, mas agora ao invés de um teste, a linha de código define o valor de x como 1
e imprime "ótimo"
, pois o valor do teste (por padrão) é TRUE
.
Assim como muitos dos exemplos acima, é difícil imaginar que isto possa ser um problema real. Eventualmente, podemos apagar espaços em branco usando o ‘localizar e substituir’ e isto talvez leve a um erro como o abaixo.
Eu citei apenas dois operadores: =
e <-
; mas na verdade há ainda outros: <<-
, ->
e ->>
(veja help("assignOps")
). Os operadores com “flecha dupla” são comumente utilizadas dentro de funções para usos específicos. Algumas pessoas acham que o operador ->
é mais intuitivo quando usado com “pipes”. Pessoalmente, acho este tipo de código abominável.
AirPassengers |>
log() |>
window(start = c(1955, 1), end = c(1958, 12)) -> sub_air_passengers
sub_air_passengers
Jan Feb Mar Apr May Jun Jul Aug
1955 5.488938 5.451038 5.587249 5.594711 5.598422 5.752573 5.897154 5.849325
1956 5.648974 5.624018 5.758902 5.746203 5.762051 5.924256 6.023448 6.003887
1957 5.752573 5.707110 5.874931 5.852202 5.872118 6.045005 6.142037 6.146329
1958 5.828946 5.762051 5.891644 5.852202 5.894403 6.075346 6.196444 6.224558
Sep Oct Nov Dec
1955 5.743003 5.613128 5.468060 5.627621
1956 5.872118 5.723585 5.602119 5.723585
1957 6.001415 5.849325 5.720312 5.817111
1958 6.001415 5.883322 5.736572 5.820083
Além dos operadores base, o popular pacote magrittr
também possui um novo tipo de operador. Muitos conhecem o %>%
que ajuda a formar “pipes” e carregar objetos progressivamente em funções distintas. Menos conhecido, mas igualmente poderoso, o %<>%
faz algo parecido.
Note que o código acima é equivalente ao abaixo. A vantagem do operador %<>%
é de evitar a repetição do x <- x ...
o que pode ser conveniente quando o nome do objeto é longo. Da mesma forma, também pode ser aplicado para transformar elementos em uma lista ou colunas num data.frame
.
Não recomendo o uso nem do ->
e nem do %<>%
.
No geral, o operador <-
é a forma mais “segura” de se definir objetos. De fato, atualmente, este operador é considerado o mais apropriado. O livro Advanced R, do influente autor Hadley Wickham, por exemplo, recomenda que se use o operador <-
exclusivamente para definir objetos.
A inconveniência de escrevê-lo num teclado moderno é contornada, como comentado acima, por atalhos como o Alt
+ -
no RStudio. Em editores de texto como o VSCode, Sublime Text ou Notepad++ também é possível criar atalhos personalizados para o <-
. Pessoalmente, eu já me acostumei a digitar <-
manualmente e não vejo grande problema nisso. Acho que o =
tem seu valor por ser mais intutivo, especialmente para usuários que já tem algum conhecimento de programação, mas acabo usando mais o <-
. Por fim, o <-
fica bem bonito quando se usa uma fonte com ligaturas como o Fira Code.
É importante frisar que o <-
continua sendo o operador de predileção da comunidade dos usuários de R e novas funções/pacotes devem ser escritas com este sinal. Por sorte há opções bastante simples que trocam os =
para <-
corretamente como o formatR
apresentado abaixo. Veja também o addin do pacote styler
. Ou seja, é possível escrever seu código usando =
e trocá-los por <-
de maneira automática se for necessário.
x <- rnorm(n = 10, mean = 2)
O ponto central deste post, na verdade, é mostrar como os operadores <-
e =
são muito similares na prática e que a escolha entre um ou outro acaba caindo numa questão subjetiva. Há quem acredite ser mais cômodo usar o =
não só porque ele é mais fácil de escrever, mas também porque ele é mais próximo de universal. Várias linguagens de programação comuns para a/o economista (Matlab, Python, Stata, etc.) usam o sinal de igualdade para definir objetos e parece estranho ter que usar o <-
somente para o R.
Em livros de econometria ambos os operadores são utilizados. Os livros Introduction to Econometrics with R, Applied Econometrics with R, Arbia. Spatial Econometrics, entre outros, usam o <-
. Já os livros Tsay. Financial Time Series e Shumway & Stoffer. Time Series Analysis usam =
.
No fim, use o operador que melhor