***
Parte do livro Introdução à análise de dados com R. Este trabalho está em andamento, o texto é bastante preliminar e sofrerá muitas alterações.
Quer fazer um curso presencialmente!? Estamos com turmas abertas em Brasília e São Paulo!
Quer fazer sugestões? Deixe um comentário abaixo ou, se você sabe utilizar o github, acesse aqui.
Não copie ou reproduza este material sem autorização.
Volte para ver atualizações!
***
Há ocasiões em queremos ou precisamos executar parte do código apenas se alguma condição for atendida. O R fornece três opções básicas para estruturar seu código dessa maneira: if(), if() else e ifelse(). Vejamos cada uma delas.
O if() sozinho
A estrutura básica do if() é a seguinte:
if (condicao) {
# comandos que
# serao rodados
# caso condicao = TRUE
}
- O início do código se dá com o comando
ifseguido de parênteses e chaves; - Dentro do parênteses temos uma condição lógica, que deverá ter como resultado ou
TRUEouFALSE; - Dentro das chaves temos o bloco de código que será executado se – e somente se – a condição do parênteses for
TRUE.
Vejamos um exemplo muito simples. Temos dois blocos de código que criam as variáveis x e y, mas eles só serão executados se as variáveis cria_x e cria_y forem TRUE, respectivamente.
# vetores de condição lógica
cria_x <- TRUE
cria_y <- FALSE
# só executa se cria_x = TRUE
if (cria_x) {
x <- 1
}
# só executa se cria_y = TRUE
if (cria_y) {
y <- 1
}
# note que x foi criado
exists("x")
## [1] TRUE
# note que y não foi criado
exists("y")
## [1] FALSE
Note que somente a variável x foi criada. Vamos agora rodar o mesmo bloco mas com TRUE e FALSE diferentes.
# remove x que foi criado
rm(x)
# vetores de condição lógica
cria_x <- FALSE
cria_y <- TRUE
# só executa se cria_x = TRUE
if (cria_x) {
x <- 1
}
# só executa se cria_y = TRUE
if (cria_y) {
y <- 1
}
# note que x não foi criado
exists("x")
## [1] FALSE
# note que y foi criado
exists("y")
## [1] TRUE
Note que agora apenas o y foi criado.
O if() com o else
Outra forma de executar códigos de maneira condicional é acrescentar ao if() o opcional else.
A estrutura básica do if() else é a seguinte:
if (condicao) {
# comandos que
# serao rodados
# caso condicao = TRUE
} else {
# comandos que
# serao rodados
# caso condicao = FALSE
}
- O início do código se dá com o comando
ifseguido de parênteses e chaves; - Dentro do parênteses temos uma condição lógica, que deverá ter como resultado ou
TRUEouFALSE; - Dentro das chaves do
if()temos um bloco de código que será executado se – e somente se – a condição do parênteses forTRUE. - Logo em seguida temos o
elseseguido de chaves; - Dentro das chaves do
elsetemos um bloco de código que será executado se – e somente se – a condição do parênteses forFALSE.
Como no caso anterior, vejamos primeiramente um exemplo bastante simples.
numero <- 1
if (numero == 1) {
cat("o numero é igual a 1")
} else {
cat("o numero não é igual a 1")
}
## o numero é igual a 1
É possível encadear diversos if() else em sequência:
numero <- 10
if (numero == 1) {
cat("o numero é igual a 1")
} else if (numero == 2) {
cat("o numero é igual a 2")
} else {
cat("o numero não é igual nem a 1 nem a 2")
}
## o numero não é igual nem a 1 nem a 2
Para fins de ilustração, vamos criar uma função que nos diga se um número é par ou ímpar. Nela vamos utilizar tanto o if() sozinho quanto o if() else.
Vale relembrar que um número (inteiro) é par se for divisível por 2 e que podemos verificar isso se o resto da divisão (operador %% no R) deste número por 2 for igual a zero.
par_ou_impar <- function(x){
# verifica se o número é um decimal comparando o tamanho da diferença de x e round(x)
# se for decimal retorna NA (pois par e ímpar não fazem sentido para decimais)
if (abs(x - round(x)) > 1e-7) {
return(NA)
}
# se o número for divisível por 2 (resto da divisão zero) retorna "par"
# caso contrário, retorna "ímpar"
if (x %% 2 == 0) {
return("par")
} else {
return("impar")
}
}
Vamos testar nossa função:
par_ou_impar(4) ## [1] "par" par_ou_impar(5) ## [1] "impar" par_ou_impar(2.1) ## [1] NA
Parece que está funcionando bem… só tem um pequeno problema. Se quisermos aplicar nossa função a um vetor de números, olhe o que ocorrerá:
x <- 1:5
par_ou_impar(x)
## Warning in if (abs(x - round(x)) > 1e-07) {: a condição tem comprimento > 1 e somente o primeiro
## elemento será usado
## Warning in if (x%%2 == 0) {: a condição tem comprimento > 1 e somente o primeiro elemento será usado
## [1] "impar"
Provavelmente não era isso o que esperávamos. O que está ocorrendo aqui?
A função ifelse()
Os comandos if() e if() else não são vetorizados. Uma alternativa para casos como esses é utilizar a função ifelse().
A função ifelse() tem a seguinte estrutura básica:
ifelse(vetor_de_condicoes, valor_se_TRUE, valor_se_FALSE)
- o primeiro argumento é um vetor (ou uma expressão que retorna um vetor) com vários
TRUEeFALSE; - o segundo argumento é o valor que será retornado quando o elemento do
vetor_de_condicoesforTRUE; - o terceiro argumento é o valor que será retornado quando o elemento do
vetor_de_condicoesforFALSE.
Primeiramente, vejamos um caso trivial, para entender melhor como funciona o ifelse():
ifelse(c(TRUE, FALSE, FALSE, TRUE), 1, -1) ## [1] 1 -1 -1 1
Note que passamos um vetor de condições com TRUE, FALSE, FALSE e TRUE. O valor para o caso TRUE é 1 e o valor para o caso FALSE é -1. Logo, o resultado é 1, -1, -1 e 1.
Façamos agora um exemplo um pouco mais elaborado. Vamos criar uma versão com ifelse da nossa função que nos diz se um número é par ou ímpar.
par_ou_impar_ifelse <- function(x){
# se x for decimal, retorna NA, se não for, retorna ele mesmo (x)
x <- ifelse(abs(x - round(x)) > 1e-7, NA, x)
# se x for divisivel por 2, retorna 'par', se não for, retorna impar
ifelse(x %% 2 == 0, "par", "impar")
}
Testemos a função com vetores. Perceba que agora funciona sem problemas!
par_ou_impar_ifelse(x) ## [1] "impar" "par" "impar" "par" "impar" par_ou_impar_ifelse(c(x, 1.1)) ## [1] "impar" "par" "impar" "par" "impar" NA
Vetorização e ifelse()
Um tema constante neste livro é fazer com que você comece a pensar em explorar a vetorização do R. Este caso não é diferente, note que poderíamos ter feito a função utilizando apenas comparações vetorizadas:
par_ou_impar_vec <- function(x){
# transforma decimais em NA
decimais <- abs(x - round(x)) > 1e-7
x[decimais] <- NA
# Cria vetor para aramazenar resultados
res <- character(length(x))
# verificar quem é divisível por dois
ind <- (x %% 2) == 0
# quem for é par
res[ind] <- "par"
# quem não for é ímpar
res[!ind] <- "impar"
# retorna resultado
return(res)
}
Na prática, o que a função ifelse() faz é mais ou menos isso o que fizemos acima – comparações e substituições de forma vetorizada. Note que, neste caso, nossa implementação ficou inclusive um pouco mais rápida do que a solução anterior com ifelse():
library(microbenchmark) microbenchmark(par_ou_impar_vec(1:1e3), par_ou_impar_ifelse(1:1e3)) ## Unit: microseconds ## expr min lq mean median uq max neval cld ## par_ou_impar_vec(1:1000) 56 58 85 59 83 1428 100 a ## par_ou_impar_ifelse(1:1000) 322 324 411 326 414 2422 100 b
Olá sou um estudante de economia de sp caso o moderador ou dono do site leia meu comentario queria conversar um pouco com você para tirar umas duvidas acompanho algum tempo o site
se poder deixar um contato ou mandar um e-mail seria grato
CurtirCurtir