As funções são uma maneira de atribuir uma determinada atividade ao R, tornando as operações mais eficientes e com melhor execução. As funções também são uma maneira de automatizar uma série de atividades que outrora seriam feitas uma a uma pelo usuário.
A estrutura básica de uma função da linguagem R é:
nome_da_função <- function(parâmetro_1, parâmetro_2, ..., parâmetro_N){
Especificação da função
}
A função é composta por um conjunto de parâmetros que serão inputados na parte de especificação da função conforme o usuário indicar. Após criar a função, o seu uso será condcionado aos valores dos parâmetros indicados pelo usuário.
nome_da_função(parâmetro_1 = valor_parâmetro_1, parâmetro_2 = valor_parâmetro_2, ..., parâmetro_N = valor_parâmetro_N)
Para demonstrar, suponha que queiramos criar uma função que adicione um ao parâmetro x.
funcao1 <- function(x){
x + 1
}
Note que o comando indica que só existe um parâmetro na função, ao qual chamamos de x. Para usar a função, devemos atribuir o valor desejado a x.
funcao1(x=5)
As notações if e else são maneiras que o usuário dispõe para indicar alguma condição nas funções. Basicamente, estas notações são indicadas para informar que o R deve realizar uma determinada tarefa caso uma dada condição ocorra (if) ou realizar outra tarefa definida caso a condição não ocorra (else).
Estas notações possuem a seguinte estrutura:
if(condição){
tarefa} else{
outra_tarefa}
Por exemplo:
if(2%%2 == 0){
print("2 é um número par")
} else{
print("2 é um número ímpar")
}
[1] "2 é um número par"
Obriga o R a responder "2 é um número par" caso o resto da devisão de dois por dois seja igual a zero e "2 é um número ímpar" em caso contrário.
É importante que o uso da notação if não torna obrigatório o uso da notação else. No entanto, a recíproca não é verdadeira.
if(2%%2 == 0){
print("2 é um número par")
}
[1] "2 é um número par"
else{
print("2 é um número ímpar")
}
Error in parse(text = x, srcfile = src): <text>:1:1: 'else' inesperado 1: else ^ Traceback:
O usuário pode trabalhar com uma estrutura aninhada de condições, utilizando as notações if, else if e else.
if (condição_1) {
Tarefa_1
} else if (condição_2) {
Tarefa_2
} else if (condição_3) {
Tarefa_3
...
} else if (condição_N) {
} else {
Tarefa_N
}
if(2 > 5){
print("2 é maior que 5")
} else if(2 ==5){
print("2 é igual a 5")
}else{
print("2 é menor que 5")
}
[1] "2 é menor que 5"
raiz <- function(x){
if(x < 0){
print("Este número não possui uma raíz quadrada no conjunto dos reais!")
}else{
return(x^0.5)
}
}
raiz(x=4)
Algumas ferramentas da linguagem R podem melhorar a qualidade das funções, por exemplo:
warning() Retorna um aviso mas não interrompe o fluxo da função.
stop() Interrompe a função e imprime um aviso.
break() Interrompe a função sem fornecer um aviso.
next() Obriga o R a pular para o próximo passo da função.
return() Indica qual objeto a função deverá retornar.
O loop do tipo for é aplicável quando queremos que uma determinada função seja aplicada a todos os elementos de um determinado conjunto. O loop for é formado por um índice criado pelo próprio usuário para representar os elementos de um determinado conjunto e uma função, ou seja:
for(índice, in conjunto){função}
for(i in 1:5){print(i)}
[1] 1 [1] 2 [1] 3 [1] 4 [1] 5
Obs: Na presença de conjuntos muito grandes, o loop for se torna ineficiente.
df <- data.frame(v1 = c(1,2,3, "..."), v2 = c(1:4), stringsAsFactors = FALSE)
df
v1 | v2 |
---|---|
<chr> | <int> |
1 | 1 |
2 | 2 |
3 | 3 |
... | 4 |
for(i in 1:4){
if(df$v1[i] == "..."){
df$v1[i] <- "0"
}
}
df
v1 | v2 |
---|---|
<chr> | <int> |
1 | 1 |
2 | 2 |
3 | 3 |
0 | 4 |
# Checando quais números são múltiplos de 3 entre 1 e 30
for(i in 1:30){
if(i%%3==0){
print(i)
}
}
[1] 3 [1] 6 [1] 9 [1] 12 [1] 15 [1] 18 [1] 21 [1] 24 [1] 27 [1] 30
Em alguns casos precisaremos usar um loop dentro de outro loop. Por exemplo, imagine que você possui um data frame com as coordenadas geográficas de cinco municípios e quer criar uma matriz de distâncias entre esses municípios. Podemos resolver este problema usando o conceito de distância euclidiana:
\begin{equation} \sqrt((Lat_i - Lat_j)^2 + (Long_i - Long_J)^2) \end{equation}Suponha que as informações sejam dadas por:
df <- data.frame(lat = c(-48.43, -47.78, -47.48, -47.49, -47.53), long = c(-5.09, -5.17, -5.53, -7.33, -4.45), id = 1:5)
df <- data.frame(lat = c(-48.43, -47.78, -47.48, -47.49, -47.53),
long = c(-5.09, -5.17, -5.53, -7.33, -4.45), id = 1:5)
# Primeiro vamos criar uma matriz vazia de tamanho 5x5
distancia <- matrix(nrow = nrow(df), ncol = nrow(df))
# Em seguida vamos usar um loop for para preencher as i linhas e j colunas da matriz com as medidas de distância
# euclidiana entre os municípios
for(i in 1:5){
for(j in 1:5){
distancia[i, j]<- sqrt((df$lat[i] - df$lat[j])^2 + (df$long[i]-df$long[j])^2)
}
}
# Agora vamos pedir para que o R imprima a matriz de distâncias
print(distancia)
[,1] [,2] [,3] [,4] [,5] [1,] 0.0000000 0.6549046 1.046948 2.429239 1.104355 [2,] 0.6549046 0.0000000 0.468615 2.179381 0.762168 [3,] 1.0469479 0.4686150 0.000000 1.800028 1.081157 [4,] 2.4292386 2.1793806 1.800028 0.000000 2.880278 [5,] 1.1043550 0.7621680 1.081157 2.880278 0.000000
Quem é o vizinho mais próximo de cada município?
Os loops do tipo while são utilizados quando desejamos aplicar uma determinada condição a cada elemento de ums sequência contínua sempre quando o elemento desta sequência aparecer.
while(condição){
função
}
n <- 1
while(n<=5){
print(n)
n <- n+ 1
}
[1] 1 [1] 2 [1] 3 [1] 4 [1] 5
O loop while é uma versão do loop for, e, a depender da ocasião, ambos podem resolver o mesmo problema:
for(i in 1:5){
print(i)
}
[1] 1 [1] 2 [1] 3 [1] 4 [1] 5
# Loops regressivos
n <- 10
while(n>=0){
print(n)
n <- n- 1
Sys.sleep(1)
}
# Usando o while em scripts que operem com horas
time = lubridate::now()
while(time < "2020-10-19 07:52:00 -00"){
print(lubridate::now())
time = time + 1
}
# Loops infinitos
while(TRUE){
print(lubridate::now())
}
As funções apply são um conjunto de ferramentas que facilitam a aplicação de tarefas em determinados objetos. Nesta aula, abordaremos as funções apply, lapply, sapply, tapply, vapply e mapply.
A função apply aplica uma função a um vetor, array ou matriz a partir de uma margem especificada.
*apply(X, MARGIN, fFUN)
Emque X é o vetor, array ou matriz em que o apply será aplicado, MARGIN recebe valor 1 para linhas e 2 para colunas e FUN é a função que será aplicada.
df <- data.frame(x1 = c(1:10), x2 = c(11:20))
apply(X = df, MARGIN = 2, FUN = sum)
Possui as mesmas aplicações da função apply, porém, é aplicavel também às listas.
lapply(X, FUN)
lapply(X = df, FUN = sum)
Possui a mesma aplicabilidade da função lapply. No entanto, esta função retorna ao usuário os resultados em uma matriz ou vetor.
sapply(X,FUN)
df1 <- sapply(X = df,FUN = sum)
df1
Aplica uma função a um subconjunto de um vetor que é construído a partir de um outro vetor.
tapply(X, INDEX, FUN)
Em que INDEX é o índice de agregação da função.
df$x2 <- rbinom(10, 1, .4)
df
x1 | x2 |
---|---|
<int> | <int> |
1 | 0 |
2 | 1 |
3 | 1 |
4 | 0 |
5 | 0 |
6 | 1 |
7 | 1 |
8 | 0 |
9 | 0 |
10 | 0 |
tapply(X = df$x1, INDEX = df$x2, FUN = sum)
Possui uma funcionalidade similar à função sapply, no entanto, seu output permite um maior controle por parte do usuário, facilitando tanto a exposição quanto a compreenção dos resultados, uma vez que, com o vapply o usuário pode indicar um tipo de valor de retorno.
vapply(X, FUN, FUN.VALUE)
Em que o parâmetro FUN.VALUE diz respeito ao tipo de valor esperado para os possíveis outputs.
# Por exemplo:
lista <- list(c(1:5), c(1:10))
# Se quisermos obter a média e o desvio padrão dos dois vetores, podemos fazer
sapply(X = lista, FUN = function(x){return(c(mean(x), sd(x)))})
3.000000 | 5.50000 |
1.581139 | 3.02765 |
# No entanto, podemos pré determinar ao R que o output será exposto em uma matriz 2 x 2
vapply(X = lista, FUN = function(x){return(c(mean(x), sd(x)))}, FUN.VALUE = matrix(2,2))
A função mapply é uma versão multiplicativa do sapply. Com a função mapply o usuário pode aplicar uma determinada função a cada elemento de um objeto de maneira consecutiva.
mapply(x, FUN, times, MoreArgs)
Em que o parâmetro MoreArgs indica um conjunto de elementos que não estão contidos no objeto X mas que o usuário também deseja aplicar a função e o parâmetro times indica a ordem de aplicação da função.
Exemplo Suponha que queiramos que cada número da sequência 1, 2, 3, 4 seja repetido 4, 3, 2, 1 vezes, sucessivamente.
mapply(x = 1:4, FUN = rep, times = 4:1)
set.seed(123)
df <- data.frame(grupo = rbinom(100, 1, .45), renda = runif(100, 150, 1500))
O intervalo de confiança para a diferença de médias entre as rendas dos dois grupos quando esses possuem desvios padrões diferentes é dado pela seguinte expressão:
\begin{equation} \mathrm{IC}\left(\mu_{1}-\mu_{0} ; \gamma\right)=\left(\bar{y}_{1}-\bar{y}_{0}\right) \pm t_{\gamma} \sqrt{S_{0} / n_{1}+S_{1} / n_{0}} \end{equation}Em que $\bar{y}_{1}$ é a renda média do grupo 1, $\bar{y}_{0}$ é a renda média do grupo 0, $t_{\gamma}$ é o valor da tabela t de student para $n-1$ graus de liberdade, $S_{0}$ é a raiz quadrada da variância amostral da variável de interesse para o grupo 0, $S_{1}$ é a raiz quadrada da variância amostral da variável de interesse para o grupo 1 e $n$ é o número de observações.
Construa uma função para o cálculo do intervalo de confiança para a diferença de média da renda dos dois grupos.
titanic <- data.frame(Titanic)
a. Use uma função apply apropriada para obter a soma de homens e mulheres no navio.
b. Use uma função apply apropriada para obter uma tabela com o número de sobreviventes por sexo.
c. Use uma função apply apropriada para obter uma tabela com o número de passageiros por sexo e idade.
Nota: Suponha que só existem 3 ativos na bolsa (WINFUT, WDOFUT e OZ1D).
Desafio
Use os conhecimentos adquiridos até agora para criar um jogo da forca semelhante ao que foi demonstrado na aula.