1.7 Dicas de erros comuns de sintaxe da linguagem R
Abrir e esquecer de fechar parênteses, colchetes e aspas é um dos erros mais comuns no início da caminhada rumo ao aprendizado de qualquer linguagem de programação, e é necessário muita paciência1 por parte do usuário para aprender a lidar com a frustração dos sucessivos erros que aparecem no caminho. Mesmo usuários mais experientes têm que aprender a lidar com os erros, que são comuns, o que levou o programador Patrick Burns a publicar um curioso livro sob o título The R Inferno (Burns 2012). Uma ferramenta útil para evitar tais problemas é o uso de uma IDE como o RStudio. Há opções na configuração que autorizam o software a checar seu código e informá-lo de possíveis erros, além de proverem ao usuário uma ferramenta de limpeza do código. Sugerimos fortemente a instalação de uma IDE para usar o R. Segue então uma brevíssima lista de erros super comuns que iniciantes enfrentam no aprendizado da linguagem R.
1.7.1 Parênteses
Lembre-se sempre de, ao abrir um parêntese, fechá-lo.
Caso contrário, a ação não se completará e seu console ficará travado com um sinal de +
aguardando que seu código seja completo.
Neste caso, ficar completo significa fechar o parêntese.
Tente executar o código abaixo e verifique que o sinal de +
ficará estagnado na tela de seu console.
Para sair desta tela, clique no console e depois tecle Esc
.
Você verá que o sinal de >
voltará a aparecer no console.
<- c(1, 2, 3 erro
Agora, execute o comando abaixo. Ele será executado perfeitamente.
<- c(1, 2, 3) erro
1.7.2 Vírgulas
Ao concatenar elementos ou ao adicionar valores em argumentos de funções, é necessário lembrar sempre de colocar as vírgulas em seus devidos lugares. Caso contrário … mais um erro! Tentem executar o código abaixo:
<- c(1, 5, 6 7, 8) numeros
## Error: <text>:1:22: unexpected numeric constant
## 1: numeros <- c(1, 5, 6 7
## ^
O R dará o aviso Error: unexpected numeric constant in "numeros <- c(1,5,6 7"
e encerrá a operação.
Executem agora o comando abaixo.
Será executado sem problemas.
<- c(1, 5, 6, 7, 8) numeros
1.7.3 Aspas
Textos são especificados dentro de aspas duplas ""
ou aspas simples ''
; tanto faz qual você usa, o importante é sempre que abrir aspas, fechar as aspas com o mesmo tipo.
Se seu texto tem acentos, use aspas duplas para delimitá-lo.
Aspas simples podem entrar num texto definido por aspas duplas, e vice-versa.
Rode isso no seu console:
<- "um texto com 'aspas simples'"
objum objum
## [1] "um texto com 'aspas simples'"
<- 'um texto com "aspas simples"'
obj2 obj2
## [1] "um texto com \"aspas simples\""
# note que foi adicionada uma barra invertida, porque \" na sintaxe do Rsignifica aspas para confundir com as aspas que você usa para indicar textos.
1.7.4 Números
Números são sempre especificados sem aspas; se você colocar qualquer número entre aspas, ele será interpretado como texto:
<- 18
obj1 + 1 # essa fórmula irá funcionar porque obj1 é um número obj1
## [1] 19
<- "18" obj2
Isso não vai funcionar porque obj2
não é um número.
+ 1 obj2
## Error in obj2 + 1: non-numeric argument to binary operator
Caso você insista em rodar, receberá a seguinte mensagem: Error in obj2 + 1 : non-numeric argument to binary operator
.
1.7.5 Nomes de objetos
Nomes de objetos não podem ter espaço em branco e aspas são ignoradas:
1 = "meutexto" #nao vai funcionar obj
## Error: <text>:1:5: unexpected numeric constant
## 1: obj 1
## ^
<- "meutexto" # vai funcionar
obj1 obj1
## [1] "meutexto"
"obj1" <- "meu texto" # vai criar objeto obj1, ignorando as aspas
obj1
## [1] "meu texto"
"1" = "meu texto" #nao vai funcionar obj
## Error: <text>:1:4: unexpected string constant
## 1: obj"1"
## ^
1.7.6 Atribuição de objetos
A atribuição de valores aos objetos pode ser feita com dois operadores equivalentes, =
ou <-
(este pode ser utilizado no sentido inverso também ->
):
<- "meu texto"
obj1
# ou pode escrever assim
<- "meu texto" # atribui
obj1
# ou assim
"meu texto" -> obj1 # atribui
obj1
## [1] "meu texto"
1.7.7 Busque entender as partes
Se você tiver dificuldade no entendimento de um script do R que está tentando rodar, separe os termos das linhas e expressões para entender o que cada parte está fazendo.
Também pode alterar os valores dos argumentos para entender o funcionamento de uma função, ou simplesmente digitar a função sem os parênteses para ver o script que ela contem.
Por exemplo, vejamos a expressão abaixo, que faz uso de um conjunto de dados chamado iris
, que vem disponível com o R.
<- paste(levels(iris$Species), tapply(iris$Sepal.Length, INDEX = iris$Species, mean, na.rm = TRUE), sep = " sépala média = ")
obj1 obj1
## [1] "setosa sépala média = 5.006" "versicolor sépala média = 5.936"
## [3] "virginica sépala média = 6.588"
À primeira vista, a expressão parece complicada.
Vamos separar as partes e entender pedaço por pedaço.
Primeiro, vamos tentar entender quem é iris
.
Vamos checar a estrutura de iris
:
str(iris) #veja a estrutura
## 'data.frame': 150 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
Agora, vamos obter um sumário estatístico de iris
:
summary(iris) #veja o que é iris
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species | |
---|---|---|---|---|---|
Min. :4.300 | Min. :2.000 | Min. :1.000 | Min. :0.100 | setosa :50 | |
1st Qu.:5.100 | 1st Qu.:2.800 | 1st Qu.:1.600 | 1st Qu.:0.300 | versicolor:50 | |
Median :5.800 | Median :3.000 | Median :4.350 | Median :1.300 | virginica :50 | |
Mean :5.843 | Mean :3.057 | Mean :3.758 | Mean :1.199 | NA | |
3rd Qu.:6.400 | 3rd Qu.:3.300 | 3rd Qu.:5.100 | 3rd Qu.:1.800 | NA | |
Max. :7.900 | Max. :4.400 | Max. :6.900 | Max. :2.500 | NA |
Note que iris$Species
contem 50 valores para três nomes e portanto eles estao sendo intepretados como categoria, isto é, é um fator.
Vamos ver os níveis desse fator com a expressão abaixo, contida na função executada anteriormente e que desejamos destrinchar:
levels(iris$Species) #categorias especies do objeto factor iris$Species
## [1] "setosa" "versicolor" "virginica"
Partamos para o segundo elemento dessa função, que é a expressão colocada abaixo:
#o segundo elemento é o resultado de:
tapply(iris$Sepal.Length, INDEX = iris$Species, mean, na.rm = TRUE)
## setosa versicolor virginica
## 5.006 5.936 6.588
Essa expressão basicamente calcula a média dos 50 comprimentos de sépala para cada espécie.
Por fim, temos o último elemento da expressão que é o argumento sep
pertencente à função paste()
.
Este argumento é responsável por informar à função paste()
qual separador nós vamos utilizar para separar os elementos contidos antes do argumento sep
, isto é, separar o resultado de levels(iris$Species)
da expressão tapply(iris$Sepal.Length,INDEX=iris$Species,mean,na.rm=TRUE)
.
Nesse caso, vamos separar esses dois elementos com o texto sépala média =
.
paste(, sep ='sépala média = ')
Vamos agora ver o resultado da função que executamos lá em cima.
#veja o resultado
obj1
## [1] "setosa sépala média = 5.006" "versicolor sépala média = 5.936"
## [3] "virginica sépala média = 6.588"
Lembre-se sempre de checar também o código de qualquer função, para poder entender como ela funciona.
Vejamos os casos das funções paste()
e tapply()
, utilizadas neste exercício.
Para checar o código de uma função, geralmente basta executa o nome da função sem parênteses.
Vejamos:
tapply
## function (X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
## {
## FUN <- if (!is.null(FUN))
## match.fun(FUN)
## if (inherits(INDEX, "formula")) {
## if (is.data.frame(X))
## INDEX <- .formula2varlist(INDEX, X)
## else stop("'X' must be a data frame when 'INDEX' is a formula")
## }
## if (!is.list(INDEX))
## INDEX <- list(INDEX)
## INDEX <- lapply(INDEX, as.factor)
## nI <- length(INDEX)
## if (!nI)
## stop("'INDEX' is of length zero")
## if (!is.object(X) && !all(lengths(INDEX) == length(X)))
## stop("arguments must have same length")
## namelist <- lapply(INDEX, levels)
## extent <- lengths(namelist, use.names = FALSE)
## cumextent <- cumprod(extent)
## if (cumextent[nI] > .Machine$integer.max)
## stop("total number of levels >= 2^31")
## storage.mode(cumextent) <- "integer"
## ngroup <- cumextent[nI]
## group <- as.integer(INDEX[[1L]])
## if (nI > 1L)
## for (i in 2L:nI) group <- group + cumextent[i - 1L] *
## (as.integer(INDEX[[i]]) - 1L)
## if (is.null(FUN))
## return(group)
## levels(group) <- as.character(seq_len(ngroup))
## class(group) <- "factor"
## ans <- split(X, group)
## names(ans) <- NULL
## index <- as.logical(lengths(ans))
## ans <- lapply(X = ans[index], FUN = FUN, ...)
## ansmat <- array(if (simplify && all(lengths(ans) == 1L)) {
## ans <- unlist(ans, recursive = FALSE, use.names = FALSE)
## if (!is.null(ans) && is.na(default) && is.atomic(ans))
## vector(typeof(ans))
## else default
## }
## else vector("list", prod(extent)), dim = extent, dimnames = namelist)
## if (length(ans)) {
## ansmat[index] <- ans
## }
## ansmat
## }
## <bytecode: 0x5587b70e7670>
## <environment: namespace:base>
paste
## function (..., sep = " ", collapse = NULL, recycle0 = FALSE)
## .Internal(paste(list(...), sep, collapse, recycle0))
## <bytecode: 0x5587a4ef5730>
## <environment: namespace:base>
Referências
Lembrem-se sempre de que vocês não são os únicos a ter de lidar com a frustração durante o aprendizado de uma linguagem de programação. É importante estarem conscientes dessa verdade. Vejam esta postagem: https://www.codingame.com/blog/dealing-with-programming-frustration-the-right-way/↩︎