Seminário sobre p-valores e significância estatística, hoje às 14:30, no Departamento de Estatística na UnB


Hoje, às 2:30pm, no prédio do CIC/EST, sala Multiuso, farei uma apresentação sobre o uso de p-valores e significância estatística em trabalhos aplicados (com foco na Economia).

Com o recente pronunciamento da American Statistical Association (ASA), o tema voltou a ficar na moda, acho que o debate será bem interessante. Estão todos convidados para a discussão!

Programação no R: if(), if() else e ifelse()


***

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 if seguido de parênteses e chaves;
  • Dentro do parênteses temos uma condição lógica, que deverá ter como resultado ou TRUE ou FALSE;
  • 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 if seguido de parênteses e chaves;
  • Dentro do parênteses temos uma condição lógica, que deverá ter como resultado ou TRUE ou FALSE;
  • Dentro das chaves do if() temos um bloco de código que será executado se – e somente se – a condição do parênteses for TRUE.
  • Logo em seguida temos o else seguido de chaves;
  • Dentro das chaves do else temos um bloco de código que será executado se – e somente se – a condição do parênteses for FALSE.

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 TRUE e FALSE;
  • o segundo argumento é o valor que será retornado quando o elemento do vetor_de_condicoes for TRUE;
  • o terceiro argumento é o valor que será retornado quando o elemento do vetor_de_condicoes for FALSE.

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