if (condicao) {
# comandos executados se a condição for TRUE
}Aula 4 – Estruturas condicionais, laços, rotinas e funções
Objetivo da Aula
Compreender e aplicar estruturas condicionais, laços de repetição, escrita de funções e organização de rotinas em R, com foco em problemas compatíveis com a formação em Estatística e Ciência de Dados.
1. Introdução
Nas aulas anteriores, estudamos objetos, vetores, matrizes, dataframes, listas, importação e exportação de dados. Agora avançaremos para um ponto central da programação: controlar o fluxo de execução do código.
Em termos práticos, esta aula responde a perguntas como:
- como tomar decisões com base em condições lógicas;
- como repetir automaticamente um conjunto de comandos;
- como encapsular procedimentos em funções reutilizáveis;
- como organizar scripts de forma mais limpa, reprodutível e profissional.
Uma das principais diferenças entre usar o R apenas como calculadora e utilizá-lo como linguagem de programação está justamente na capacidade de escrever códigos que decidem, repetem, automatizam e generalizam tarefas.
2. Estruturas condicionais
As estruturas condicionais permitem executar comandos somente quando determinada condição lógica é satisfeita.
2.1 A estrutura if
A estrutura mais básica é:
Exemplo 1 – Verificando se um número é positivo
x <- 12
if (x > 0) {
print("x é positivo")
}[1] "x é positivo"
O bloco dentro das chaves será executado apenas se a condição x > 0 for verdadeira. Caso contrário, nada acontece.
Exemplo 2 – Ajustando uma variável caso ela seja negativa
saldo <- -35
if (saldo < 0) {
saldo <- abs(saldo)
}
saldo[1] 35
A estrutura if é útil quando queremos corrigir, filtrar, classificar ou acionar comandos a partir de uma regra lógica.
2.2 A estrutura if ... else
Quando queremos tratar também o caso em que a condição é falsa, usamos else.
if (condicao) {
# comandos se TRUE
} else {
# comandos se FALSE
}Exemplo 3 – Verificando se um número é par ou ímpar
n <- 17
if (n %% 2 == 0) {
print("n é par")
} else {
print("n é ímpar")
}[1] "n é ímpar"
O operador %% devolve o resto da divisão inteira. Assim, um número é par quando o resto da divisão por 2 é igual a zero.
Exemplo 4 – Classificação simples de desempenho
nota <- 7.3
if (nota >= 6) {
print("Aprovado")
} else {
print("Reprovado")
}[1] "Aprovado"
2.3 A estrutura if ... else if ... else
Quando há mais de duas possibilidades, podemos encadear condições.
if (condicao1) {
# bloco 1
} else if (condicao2) {
# bloco 2
} else {
# bloco 3
}Exemplo 5 – Verificando se um número é positivo, negativo ou zero
z <- -4
if (z < 0) {
print("z é negativo")
} else if (z == 0) {
print("z é zero")
} else {
print("z é positivo")
}[1] "z é negativo"
Exemplo 6 – Faixas de rendimento em um contexto de análise de desempenho
nota_r <- 8.4
if (nota_r < 5) {
categoria <- "baixo desempenho"
} else if (nota_r < 7) {
categoria <- "desempenho intermediário"
} else if (nota_r < 9) {
categoria <- "bom desempenho"
} else {
categoria <- "excelente desempenho"
}
categoria[1] "bom desempenho"
Quando as condições são avaliadas em sequência, o R interrompe o processo na primeira condição verdadeira.
2.4 A função ifelse()
A função ifelse() é útil quando queremos devolver um resultado de forma compacta.
ifelse(condicao, valor_se_true, valor_se_false)Exemplo 7 – Classificação binária
idade <- 19
ifelse(idade >= 18, "maior de idade", "menor de idade")[1] "maior de idade"
Exemplo 8 – Aplicação vetorial de ifelse()
notas <- c(4.2, 6.1, 8.7, 5.5, 9.0, 3.8)
situacao <- ifelse(notas >= 6, "aprovado", "reprovado")
situacao[1] "reprovado" "aprovado" "aprovado" "reprovado" "aprovado" "reprovado"
Uma grande vantagem do ifelse() é seu uso vetorial, isto é, ele consegue avaliar uma condição em todos os elementos de um vetor sem necessidade de escrever um laço explícito.
2.5 Cuidados importantes com condicionais
Erros comuns em estruturas condicionais:
- usar
=em vez de==para comparação; - esquecer de fechar parênteses ou chaves;
- tentar usar
ifcom uma condição que produz mais de um valor lógico; - confundir
&com&&e|com||.
Exemplo 9 – Diferença entre & e &&
x <- 5
y <- 12
x > 0 & y > 10[1] TRUE
x > 0 && y > 10[1] TRUE
No uso mais básico:
&faz comparação elemento a elemento;&&avalia apenas a primeira condição lógica de cada lado.
Em estruturas if, normalmente a condição deve resultar em um único valor lógico.
3. Laços de repetição
Laços permitem repetir um bloco de comandos várias vezes.
3.1 O laço for
A estrutura geral é:
for (contador in sequencia) {
# comandos
}Exemplo 10 – Imprimindo os números de 1 a 5
for (i in 1:5) {
print(i)
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
Exemplo 11 – Calculando uma soma acumulada
soma <- 0
for (i in 1:10) {
soma <- soma + i
}
soma[1] 55
A variável soma funciona como acumuladora. Em cada iteração, ela recebe seu valor anterior somado ao valor atual de i.
Exemplo 12 – Criando um vetor com quadrados perfeitos
quadrados <- numeric(10)
for (i in 1:10) {
quadrados[i] <- i^2
}
quadrados [1] 1 4 9 16 25 36 49 64 81 100
Sempre que possível, pré-alocar o objeto final com funções como numeric(), character() ou vector() costuma ser melhor do que ir concatenando valores com c() a cada repetição.
Exemplo 13 – Sequência não regular
valores <- c(-3, 0, 2.5, pi)
for (v in valores) {
print(v)
}[1] -3
[1] 0
[1] 2.5
[1] 3.141593
3.2 O laço while
O while executa um bloco enquanto uma condição for verdadeira.
while (condicao) {
# comandos
}Exemplo 14 – Somando múltiplos de 4 até 40
soma <- 0
i <- 4
while (i <= 40) {
soma <- soma + i
i <- i + 4
}
soma[1] 220
No while, o programador precisa garantir que a condição se torne falsa em algum momento. Caso contrário, o código pode entrar em laço infinito.
Exemplo 15 – Construindo uma sequência até ultrapassar um limite
valores <- NULL
x <- 1
while (x <= 100) {
valores <- c(valores, x)
x <- x * 2
}
valores[1] 1 2 4 8 16 32 64
Esse tipo de estrutura é útil quando o número de iterações não está definido previamente, mas depende da evolução de uma condição.
3.3 break e next
Exemplo 16 – Interrompendo um laço com break
for (i in 1:10) {
if (i > 6) {
break
}
print(i)
}[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
Exemplo 17 – Pulando uma iteração com next
for (i in 1:10) {
if (i %% 2 == 0) {
next
}
print(i)
}[1] 1
[1] 3
[1] 5
[1] 7
[1] 9
breakinterrompe completamente o laço;nextpula apenas a iteração atual e continua nas seguintes.
4. Evitando laços quando possível
O R é uma linguagem fortemente vetorial. Em muitas situações, laços podem ser substituídos por estratégias mais simples e eficientes.
Exemplo 18 – Multiplicando todos os elementos de um vetor por 2
x <- c(3, 5, 7, 9)
2 * x[1] 6 10 14 18
Exemplo 19 – Classificando valores com ifelse() sem for
notas <- c(4.5, 6.0, 7.2, 5.8, 9.1)
ifelse(notas >= 6, "A", "R")[1] "R" "A" "A" "R" "A"
Exemplo 20 – Aplicando função por linha ou coluna com apply()
A <- matrix(1:12, nrow = 3, byrow = TRUE)
A [,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
apply(A, 1, sum)[1] 10 26 42
apply(A, 2, mean)[1] 5 6 7 8
Em apply(A, 1, sum), o valor 1 indica aplicação por linha.
Em apply(A, 2, mean), o valor 2 indica aplicação por coluna.
Exemplo 21 – lapply() e sapply()
lista_obj <- list(
a = 1:5,
b = c(2, 4, 8),
c = c(10, 20)
)
lapply(lista_obj, length)$a
[1] 5
$b
[1] 3
$c
[1] 2
sapply(lista_obj, length)a b c
5 3 2
A família apply não substitui todos os laços, mas em muitas situações ela torna o código:
- mais curto;
- mais legível;
- mais idiomático em R.
5. Escrevendo funções
Funções permitem encapsular tarefas e reutilizá-las com diferentes entradas.
A estrutura básica é:
nome_funcao <- function(parametros) {
# corpo da função
return(resultado)
}5.1 Função sem parâmetro
Exemplo 22 – Mensagem de boas-vindas
boas_vindas <- function() {
print("Bem-vindos à Aula 4 de R")
}
boas_vindas()[1] "Bem-vindos à Aula 4 de R"
5.2 Função com um parâmetro
Exemplo 23 – Dobro de um número
dobra <- function(x) {
y <- 2 * x
return(y)
}
dobra(7)[1] 14
dobra(2.5)[1] 5
Exemplo 24 – Valor absoluto sem usar abs()
valor_absoluto_manual <- function(x) {
if (x >= 0) {
return(x)
} else {
return(-x)
}
}
valor_absoluto_manual(-12)[1] 12
valor_absoluto_manual(8)[1] 8
5.3 Função com mais de um parâmetro
Exemplo 25 – Equação da reta
reta <- function(x, beta0, beta1) {
y <- beta0 + beta1 * x
return(y)
}
reta(x = 4, beta0 = 2, beta1 = 1.5)[1] 8
A expressão matemática correspondente é dada por:
\[ y = \beta_0 + \beta_1 x \]
Exemplo 26 – Média de dois números
media2 <- function(a, b) {
resultado <- (a + b) / 2
return(resultado)
}
media2(8, 10)[1] 9
A expressão matemática correspondente é:
\[ \bar{x} = \frac{a+b}{2} \]
5.4 Funções retornando mais de um resultado
Quando precisamos devolver várias saídas, podemos retornar uma lista.
Exemplo 27 – Soma, média e desvio-padrão
resumo_vetor <- function(v) {
s <- sum(v)
m <- mean(v)
dp <- sd(v)
return(list(
soma = s,
media = m,
desvio_padrao = dp
))
}
x <- c(3, 7, 10, 12, 15)
resumo_vetor(x)$soma
[1] 47
$media
[1] 9.4
$desvio_padrao
[1] 4.615192
As principais expressões envolvidas são:
\[ S = \sum_{i=1}^{n} x_i \]
\[ \bar{x} = \frac{1}{n} \sum_{i=1}^{n} x_i \]
\[ s = \sqrt{\frac{1}{n-1}\sum_{i=1}^{n}(x_i-\bar{x})^2} \]
Esse tipo de função é particularmente útil em rotinas de análise, pois reúne, em um único objeto, diferentes medidas calculadas a partir da mesma entrada.
5.5 Funções com validação de entrada
Em aplicações mais profissionais, é interessante verificar se a entrada é adequada.
Exemplo 28 – Média apenas para vetores numéricos
media_segura <- function(v) {
if (!is.numeric(v)) {
stop("A entrada deve ser numérica.")
}
return(mean(v))
}
media_segura(c(2, 4, 6, 8))[1] 5
A função stop() interrompe a execução e devolve uma mensagem de erro personalizada. Isso é muito útil para tornar funções mais robustas.
6. Escrevendo rotinas e scripts
Uma rotina ou script é um conjunto organizado de comandos salvo em um arquivo com extensão .R.
Em projetos reais, dificilmente tudo será digitado diretamente no console. O mais comum é construir um script com:
- leitura dos dados;
- tratamento;
- análises;
- gráficos;
- exportação de resultados.
6.1 Exemplo de rotina simples
x <- round(runif(1000, min = -30, max = 50), 0)
media_desvio <- function(v) {
m <- mean(v)
dp <- sd(v)
return(list(media = m, desvio_padrao = dp))
}
resultado <- media_desvio(x)
resultado$media
resultado$desvio_padrao
hist(x)Exemplo 29 – Salvando uma rotina em arquivo
Suponha que você tenha criado um arquivo chamado rotina_aula4.R no diretório de trabalho.
source("rotina_aula4.R")A função source() executa um script salvo em arquivo. Isso é extremamente útil para:
- reaproveitar códigos;
- automatizar etapas;
- modularizar projetos.
6.2 Estrutura recomendada de um script analítico
Uma organização profissional mínima de um script pode seguir a ordem:
- limpeza do ambiente, quando necessário;
- definição do diretório ou projeto;
- leitura de dados;
- criação de funções auxiliares;
- processamento e análise;
- visualização dos resultados;
- exportação de objetos e tabelas.
Exemplo 30 – Mini fluxo organizado
# 1. Leitura dos dados
dados <- read.csv("base.csv", stringsAsFactors = FALSE)
# 2. Função auxiliar
top_media <- function(v) {
mean(sort(v, decreasing = TRUE)[1:5])
}
# 3. Aplicação
resultado <- top_media(dados$nota_r)
# 4. Saída
resultado7. Exemplos aplicados ao contexto de Estatística e Ciência de Dados
Nesta seção, vamos usar problemas mais próximos do perfil da disciplina.
7.1 Classificação de desempenho
nota_r <- c(5.4, 7.8, 9.1, 6.2, 4.7, 8.5)
classificacao <- ifelse(
nota_r < 6, "insuficiente",
ifelse(nota_r < 8, "adequado", "alto")
)
data.frame(nota_r, classificacao)7.2 Seleção condicional em um dataframe
dados <- data.frame(
aluno = c("Ana", "Bruno", "Carla", "Daniel", "Eva"),
nota_r = c(8.7, 5.9, 9.1, 6.4, 7.8),
projetos = c(3, 1, 5, 2, 4)
)
subset(dados, nota_r >= 7 & projetos >= 3)7.3 Função para extrair os melhores desempenhos
top_media_notas <- function(df, nome_variavel, k = 3) {
v <- df[[nome_variavel]]
v_ordenado <- sort(v, decreasing = TRUE)
media_top <- mean(v_ordenado[1:k])
return(media_top)
}
top_media_notas(dados, "nota_r", k = 3)[1] 8.533333
7.4 Construindo uma classificação com laço
notas <- c(4.5, 6.0, 8.2, 5.1, 9.0, 7.4)
classe <- character(length(notas))
for (i in 1:length(notas)) {
if (notas[i] < 6) {
classe[i] <- "R"
} else if (notas[i] < 8) {
classe[i] <- "A"
} else {
classe[i] <- "D"
}
}
data.frame(notas, classe)Apesar de esse exemplo poder ser resolvido com ifelse(), ele é didaticamente importante para mostrar como combinar laços e condicionais.
8. Erros comuns e boas práticas
- esquecer de inicializar uma variável acumuladora;
- usar
ifquando a condição retorna um vetor lógico inteiro; - concatenar repetidamente objetos grandes dentro de laços sem necessidade;
- criar funções sem nomes claros;
- escrever scripts sem comentários e sem estrutura.
- use nomes de objetos informativos;
- comente trechos importantes do código;
- teste funções com exemplos simples antes de usá-las em rotinas maiores;
- prefira soluções vetoriais quando fizer sentido;
- salve scripts com nomes claros, como
aula4_condicionais_funcoes.R.
9. Exercícios propostos
Exercício 1
Crie um script que receba um número x e:
- informe se ele é negativo, zero ou positivo;
- informe se ele é par ou ímpar;
- devolva seu valor absoluto sem usar
abs().
Exercício 2
Construa uma função chamada classifica_nota() que receba uma nota de 0 a 10 e devolva:
"insuficiente"se a nota for menor que 6;"adequado"se a nota estiver entre 6 e 8, sem incluir 8;"alto"se a nota for maior ou igual a 8.
Teste a função em pelo menos cinco valores diferentes.
Exercício 3
Use um laço for para construir um vetor contendo os 20 primeiros valores da sequência
\[ a_i = \frac{i}{i+1}, \quad i = 1, 2, \ldots, 20 \]
Depois:
- mostre o vetor;
- calcule sua média;
- identifique o maior valor.
Exercício 4
Escreva uma função que receba um vetor numérico e devolva uma lista contendo:
- o tamanho do vetor;
- a soma;
- a média;
- a mediana;
- o desvio-padrão;
- o índice do maior valor.
Exercício 5
Considere o seguinte dataframe:
dados <- data.frame(
id = 1:8,
nota_r = c(8.2, 6.4, 9.5, 5.7, 7.8, 8.9, 4.9, 6.8),
projetos = c(3, 1, 5, 0, 2, 4, 1, 2)
)Faça o que se pede:
- selecione apenas as observações com
nota_r >= 7; - crie uma nova coluna chamada
perfil, com: "forte"senota_r >= 8eprojetos >= 3;"moderado"senota_r >= 6;"fraco"caso contrário;- ordene o resultado final por
projetose depois pornota_r, ambas em ordem decrescente.
Exercício 6
Escreva uma função chamada produto_escalar_manual() que receba dois vetores numéricos de mesmo tamanho e devolva o produto escalar entre eles, sem usar %*%.
O produto escalar entre dois vetores ( ) e ( ) de dimensão (n) é dado por:
\[ \mathbf{x} \cdot \mathbf{y} = \sum_{i=1}^{n} x_i y_i \]
Exercício 7
Escreva uma função que receba os coeficientes (a), (b) e (c) e devolva as raízes reais da equação do segundo grau
\[ ax^2 + bx + c = 0 \]
A função deve:
- informar quando não existirem raízes reais;
- devolver uma única raiz quando o discriminante for zero;
- devolver duas raízes quando o discriminante for positivo.
Utilize o discriminante
\[ \Delta = b^2 - 4ac \]
e, quando ( ), as raízes
\[ x_1 = \frac{-b + \sqrt{\Delta}}{2a} \qquad \text{e} \qquad x_2 = \frac{-b - \sqrt{\Delta}}{2a} \]
Exercício 8
Crie um script com a seguinte estrutura:
- gere 500 valores aleatórios de uma normal com média 12 e desvio-padrão 3;
- escreva uma função que devolva média, variância e quartis;
- aplique essa função ao vetor gerado;
- construa um histograma;
- salve esse script com um nome apropriado.
Lembre-se de que, para uma variável aleatória normal,
\[ X \sim N(\mu, \sigma^2) \]
onde, neste exercício,
\[ \mu = 12 \qquad \text{e} \qquad \sigma = 3 \]
Os exercícios desta aula foram pensados para consolidar o raciocínio de programação em R em um nível compatível com estudantes de Estatística e Ciência de Dados. O objetivo não é apenas “fazer funcionar”, mas escrever códigos organizados, interpretáveis e reutilizáveis.
Refaça, no seu próprio script, pelo menos três exemplos desta aula e resolva os exercícios propostos sem copiar diretamente os blocos já apresentados. O objetivo é treinar a autonomia na escrita de código.