3.11 Mais sobre funções
Funções são tão comuns (provavelmente você já usou funções no Excel), que mesmo sem termos abordado o tema com detalhes, nós conseguimos utilizar várias funções nas seções anteriores:
- a função
c()
foi utilizada para criar vetores; - a função
class()
foi utilizada para descobrir a classe de um objeto; - a família de funções
is.na()
,is.nan()
,is.infinite()
eis.null
foram utilizadas para testar se um valor éNA
,NaN
, infinito ouNULL
, respectivamente.
Diferentemente dos objetos, as funções podem receber argumentos. Argumentos são os valores que colocamos dentro dos parênteses e que as funções precisam para funcionar (calcular algum resultado). Por exemplo, a função c()
precisa saber quais são os valores que formarão o vetor que ela irá criar.
c(1, 3, 5)
## [1] 1 3 5
Nesse caso, os valores 1
, 3
e 5
são os argumentos da função c()
. Os argumentos de uma função são sempre separados por vírgulas.
Funções no R têm personalidade. Cada uma pode funcionar de um jeito diferente das demais, mesmo quando fazem tarefas parecidas. Por exemplo, vejamos a função sum()
.
sum(1, 3)
## [1] 4
Como podemos ver, essa função retorna a soma de seus argumentos. Também podemos passar um vetor como argumento, e ela retornará a soma dos elementos do vetor.
sum(c(1, 3))
## [1] 4
Já a função mean()
, que calcula a média de um conjunto de valores, exige que você passe valores na forma de um vetor:
# Só vai considerar o primeiro número na média
mean(1, 3)
## [1] 1
# Considera todos os valores dentro do vetor na média
mean(c(1, 3))
## [1] 2
Como cada coluna de um data frame é um vetor, podemos calcular a média de uma coluna fazendo:
# Podemos passar esse vetor para a função mean()
mean(mtcars$mpg)
## [1] 20.09062
Também podemos usar argumentos para modificar o comportamento de uma função. O que acontece se algum elemento do vetor for NA
?
mean(c(1, 3, NA))
## [1] NA
Como a função não sabe o valor do terceiro elemento do vetor, ela não sabe qual é a média desses 3 elementos e, então, devolve NA
. Como é muito comum termos NA
nas nossas bases de dados, é muito comum tentarmos calcular a média de uma coluna que tem NA
e recebermos NA
como resposta.
Na grande maioria dos casos, queremos saber a média de uma coluna apesar dos NA
s. Isto é, queremos retirar os NA
s e então calcular a média com os valores que conhecemos. Para isso, podemos utilizar o argumento na.rm = TRUE
da função mean()
.
mean(c(1, 3, NA), na.rm = TRUE)
## [1] 2
Esse argumento diz à função para remover os NA
s antes de calcular a média. Assim, a média calculada é: (1 + 3)/2
.
Claro que cada função tem os seus próprios argumentos e nem toda função terá o argumento na.rm=
. Para saber quais são e como usar os argumentos de uma função, basta acessar a sua documentação:
help(mean)
Os argumentos das funções também têm nomes, que podemos ou não usar na hora de usar uma função. Veja por exemplo a função seq()
.
seq(from = 4, to = 10, by = 2)
## [1] 4 6 8 10
Entre outros argumentos, ela possui os argumentos from=
, to=
e by=
. O que ela faz é criar uma sequência (vetor) de by
em by
que começa em from
e termina em to
. No exemplo, criamos uma função de 2 em 2 que começa em 4 e termina em 10.
Também poderíamos usar a mesma função sem colocar o nome dos argumentos:
seq(4, 10, 2)
## [1] 4 6 8 10
Para utilizar a função sem escrever o nome dos argumentos, você precisa colocar os valores na ordem em que os argumentos aparecem. E se você olhar a documentação da função seq()
, fazendo help(seq)
, verá que a ordem dos argumentos é justamente from=
, to=
e by=
.
Escrevendo o nome dos argumentos, não há problema em alterar a ordem dos argumentos:
seq(by = 2, to = 10, from = 4)
## [1] 4 6 8 10
Mas se especificar os argumentos, a ordem importa. Veja que o resultado será diferente.
seq(2, 10, 4)
## [1] 2 6 10
A seguir, apresentamos algumas funções nativas do R úteis para trabalhar com data frames :
head()
- Mostra as primeiras 6 linhas.tail()
- Mostra as últimas 6 linhas.dim()
- Número de linhas e de colunas.names()
- Os nomes das colunas (variáveis).str()
- Estrutura do data frame. Mostra, entre outras coisas, as classes de cada coluna.cbind()
- Acopla duas tabelas lado a lado.rbind()
- Empilha duas tabelas.
Além de usar funções já prontas, você pode criar a sua própria função. A sintaxe é a seguinte:
<- function(argumento_1, argumento_2) {
nome_da_funcao
# Código que a função irá executar
}
Repare que function
é um nome reservado no R, isto é, você não pode criar um objeto com esse nome.
Um exemplo: vamos criar uma função que soma dois números.
<- function(x, y) {
minha_soma <- x + y
soma
# resultado retornado
soma }
Essa função tem os seguintes componentes:
minha_soma
: nome da funçãox
ey
: argumentos da funçãosoma <- x + y
: operação que a função executasoma
: valor retornado pela função
Após rodarmos o código de criar a função, podemos utilizá-la como qualquer outra função do R.
minha_soma(2, 2)
## [1] 4
O objeto soma
só existe dentro da função, isto é, além de ele não ser colocado no seu environment, ele só existirá na memória (RAM) enquanto o R estiver executando a função. Depois disso, ele será apagado. O mesmo vale para os argumentos x
e y
.
O valor retornado pela função representa o resultado que receberemos ao utilizá-la. Por padrão, a função retornará sempre a última linha de código que existir dentro dela. No nosso exemplo, a função retorna o valor contido no objeto soma
, pois é isso que fazemos na última linha de código da função.
Repare que se atribuirmos o resultado a um objeto, ele não será mostrado no console:
<- minha_soma(3, 3)
resultado
# Para ver o resultado, rodamos o objeto `resultado`
resultado## [1] 6
Agora, o que acontece se a última linha da função não devolver um objeto? Veja:
<- function(x, y) {
minha_nova_soma <- x + y
soma }
A função minha_nova_soma()
apenas cria o objeto soma
, sem retorná-lo como na função minha_soma()
. Se utilizarmos essa nova função, nenhum valor é devolvido no console:
minha_nova_soma(1, 1)
No entanto, a última linha da função agora é a atribuição soma <- x + y
e esse será o “resultado retornado”. Assim, podemos visualizar o resultado da função fazendo:
<- minha_nova_soma(1, 1)
resultado
resultado## [1] 2
É como se, por trás das cortinas, o R estivesse fazendo resultado <- soma <- x + y
, mas apenas o objeto resultado
continua existindo, já que os objetos soma
, x
e y
são descartados após a função ser executada.
Claro que, na prática, é sempre bom criarmos funções que retornem na tela os seus resultados, para evitar esse passo a mais se quisermos apenas ver o resultado no console. Assim, a função minha_soma()
costuma ser preferível com relação à função minha_nova_soma()
.
Exercícios
1. Qual dos códigos abaixo devolverá um erro se for avaliado?
a.
3 * 5 + 10
b.
function <- 10
c.
mean(1, 10)
d.
(soma <- sum(1, 1))
2. Crie uma função que receba um número e retorne o quadrado deste número.
3. Crie uma função que receba 2 números e devolva a raiz quadrada da soma desses números.
4. Crie uma função que receba dois valores (numéricos) e devolva o maior deles.
5. Use a função runif()
para criar uma função que retorne um número aleatório inteiro entre 0 e 10 (0 e 10 inclusive). Caso você não conheça a função runif()
, rode help(runif)
para ler a sua documentação.
6. Rode help(sample)
para descobrir o que a função sample()
faz. Em seguida
a. use-a para escrever uma função que devolva uma linha aleatória de um data frame;
b. generalize a função para retornar um número qualquer de linhas, que poderá ser escolhido por quem for usá-la.