Funções e argumentos

As funções no R são definidas como:

nome(argumento1, argumento2, ...)

Exemplo: função runif() (para gerar valores aleatórios de uma distribuição uniforme):

runif(n, min = 0, max = 1)
runif(10, 1, 100)
 [1] 31.468845 26.509578 55.679921  6.581932 47.386379 48.893303 81.427859
 [8] 37.661733 55.109301 17.855943

Argumentos que já possuem um valor especificado (como max e min) podem ser omitidos:

runif(10)

Se os argumentos forem nomeados, a ordem deles dentro da função não tem mais importância:

runif(min = 1, max = 100, n = 10)

Argumentos nomeados e não nomeados podem ser utilizados, desde que os não nomeados estejam na posição correta:

runif(10, max = 100, min = 1)

Outros tipos de argumentos

Exemplo: função sample():

sample(x, size, replace = FALSE, prob = NULL)
  • x e size devem ser obrigatoriamente especificados
  • replace é lógico: TRUE (T) ou FALSE (F)
  • prob é um argumento vazio ou ausente (“opcional”)

Exemplo: função plot():

plot(x, y, ...)
  • ...” permite especificar argumentos de outras funções (por exemplo par())

Mecanismos de ajuda

Argumentos e detalhes do funcionamento das funções:

?runif

ou

help(runif)

A documentação contém os campos:

  • Description: breve descrição
  • Usage: função e todos seus argumentos
  • Arguments: lista descrevendo cada argumento
  • Details: descrição detalhada
  • Value: o que a função retorna
  • References: bibliografia relacionada
  • See Also: funções relacionadas
  • Examples: exemplos práticos

Procura por funções que contenham palavra:

help.search("palavra")

Ajuda através do navegador (também contém manuais, …):

help.start()

Busca por palavra nos arquivos da lista de discussão do R:

RSiteSearch("palavra")

Criando uma função

A ideia original do R é transformar usuários em programadores

Criar funções para realizar trabalhos específicos é um dos grandes poderes do R

Por exemplo, podemos criar a famosa função

ola.mundo <- function(){
    writeLines("Olá mundo")
}

E chama-la através de

ola.mundo()
Olá mundo

A função acima não permite alterar o resultado de saída. Podemos fazer isso incluindo um argumento

ola.mundo <- function(texto){
    writeLines(texto)
}

E fazer por exemplo

ola.mundo("Funções são legais")
Funções são legais

(Veremos detalhes de funções mais adiante)

Exercícios 1

  1. Usando a função runif() gere \(30\) números aleatórios entre:
    • 0 e 1
    • -5 e 5
    • 10 e 500 alternando a posição dos argumentos da função.
  2. Veja o help da função (?) "+"
  3. Crie uma função para fazer a soma de dois números: x e y

Objetos

Programação orientada a objetos

O que é um objeto?

  • Um símbolo ou uma variável capaz de armazenar qualquer valor ou estrutura de dados

Por quê objetos?

  • Uma maneira simples de acessar os dados armazenados na memória (o R não permite acesso direto à memória)

Programação:

  • Objetos   ⇒   Classes   ⇒   Métodos

“Tudo no R é um objeto.”

“Todo objeto no R tem uma classe”

  • Classe: é a definição de um objeto. Descreve a forma do objeto e como ele será manipulado pelas diferentes funções
  • Método: são funções genéricas que executam suas tarefas de acordo com cada classe. As funções genéricas mais importantes são:
    • summary()
    • plot()

Veja o resultado de

methods(summary)
methods(plot)

A variável x recebe o valor \(2\) (tornando-se um objeto dentro do R):

x <- 2

O símbolo <- é chamado de operador de atribuição. Ele serve para atribuir valores a objetos, e é formado pelos símbolos < e -, obrigatoriamente sem espaços.

Para ver o conteúdo do objeto:

x
[1] 2

Observação: O símbolo = pode ser usado no lugar de <- mas não é recomendado.

Quando você faz

x <- 2

está fazendo uma declaração, ou seja, declarando que a variável x irá agora se tornar um objeto que armazena o número 2. As declarações podem ser feitas uma em cada linha

x <- 2
y <- 4

ou separadas por ;

x <- 2; y <- 4

Operações matemáticas em objetos:

x + x
[1] 4

Objetos podem armazenar diferentes estruturas de dados:

y <- runif(10)
y
 [1] 0.6249965 0.8821655 0.2803538 0.3984879 0.7625511 0.6690217 0.2046122
 [8] 0.3575249 0.3594751 0.6902905

Note que cada objeto só pode armazenar uma estrutura (um número ou uma sequência de valores) de cada vez! (Aqui, o valor \(4\) que estava armazenado em y foi sobrescrito pelos valores acima.)

Nomes de objetos

  • Podem ser formados por letras, números, “_”, e “.
  • Não podem começar com número e/ou ponto
  • Não podem conter espaços
  • Evite usar acentos
  • Evite usar nomes de funções como:

c q t C D F I T diff df data var pt

  • O R é case-sensitive, portanto:

dados \(\neq\) Dados \(\neq\) DADOS

Gerenciando a área de trabalho

Liste os objetos criados com a função ls():

ls()

Para remover apenas um objeto:

rm(x)

Para remover outros objetos:

rm(x, y)

Para remover todos os objetos:

rm(list = ls())

Cuidado! O comando acima apaga todos os objetos na sua área de trabalho sem perguntar. Depois só é possível recuperar os objetos ao rodar os script novamente.

Exercícios 2

  1. Armazene o resultado da equação \(32 + 16^2 - 25^3\) no objeto x
  2. Divida x por \(345\) e armazene em y
  3. Crie um objeto (com o nome que você quiser) para armazenar \(30\) valores aleatórios de uma distribuição uniforme entre \(10\) e \(50\)
  4. Remova o objeto y
  5. Remova os demais objetos de uma única vez
  6. Procure a função utilizada para gerar numeros aleatórios de uma distribuição de Poisson, e gere \(100\) valores para a VA \(X \sim \text{Poisson}(5)\).

Classes de objetos

O R possui 5 classes básicas de objetos, também chamados de objetos “atômicos”:

  • character
  • numeric
  • integer
  • complex
  • logical

Um vetor só pode conter elementos de uma mesma classe

(A única excessão é a lista).

Vetor

Características:

  • Coleção ordenada de valores
  • Estrutura unidimensional

Usando a função c() para criar vetores:

num <- c(10, 5, 2, 4, 8, 9)
num
[1] 10  5  2  4  8  9
class(num)
[1] "numeric"

Por que numeric e não integer?

x <- c(10L, 5L, 2L, 4L, 8L, 9L)
x
[1] 10  5  2  4  8  9
class(x)
[1] "integer"

Para forçar a representação de um número para inteiro é necessário usar o sufixo L.

Note que a diferença entre numeric e integer também possui impacto computacional, pois o armazenamento de números inteiros ocupa menos espaço na memória. Dessa forma, esperamos que o vetor x acima ocupe menos espaço na memória do que o vetor num, embora sejam aparentemente idênticos. Veja:

object.size(num)
[1] 88 bytes
object.size(x)
[1] 72 bytes

A diferença pode parecer pequena, mas pode ter um grande impacto computacional quando os vetores são formados por milhares ou milhões de números.

Representação numérica dentro do R

Os números que aparecem na tela do console do R são apenas representações simplificadas do número real armazenado na memória. Por exemplo,

x <- runif(10)
x
 [1] 0.2875775 0.7883051 0.4089769 0.8830174 0.9404673 0.0455565 0.5281055
 [8] 0.8924190 0.5514350 0.4566147

O objeto x contém números como 0.2875775, 0.7883051, etc, que possuem 7 casas decimais, que é o padrão do R. O número de casas decimais é controlado pelo argumento digits da função options. Para visualizar essa opção, use

getOption("digits")
[1] 7

Note que esse valor de 7 é o número de dígitos significativos, e pode variar conforme a sequência de números. Por exemplo,

y <- runif(10)
y
 [1] 0.069360916 0.817775199 0.942621732 0.269381876 0.169348123
 [6] 0.033895622 0.178785004 0.641665366 0.022877743 0.008324827

possui valores com 9 casas decimais. Isto é apenas a representação do número que aparece na tela. Internamente, cada número é armazenado com uma precisão de 22 casas decimais! Você pode ver o número com toda sua precisão usando a função print() e especificando o número de casas decimais com o argumento digits (de 1 a 22)

print(x, digits = 1)
 [1] 0.29 0.79 0.41 0.88 0.94 0.05 0.53 0.89 0.55 0.46
print(x, digits = 7) # padrão
 [1] 0.2875775 0.7883051 0.4089769 0.8830174 0.9404673 0.0455565 0.5281055
 [8] 0.8924190 0.5514350 0.4566147
print(x, digits = 22)
 [1] 0.28757752012461423873901 0.78830513544380664825439
 [3] 0.40897692181169986724854 0.88301740400493144989014
 [5] 0.94046728429384529590607 0.04555649938993155956268
 [7] 0.52810548804700374603271 0.89241904439404606819153
 [9] 0.55143501446582376956940 0.45661473530344665050507

Também é possível alterar a representação na tela para o formato científico, usando a função format()

format(x, scientific = TRUE)
 [1] "2.875775e-01" "7.883051e-01" "4.089769e-01" "8.830174e-01"
 [5] "9.404673e-01" "4.555650e-02" "5.281055e-01" "8.924190e-01"
 [9] "5.514350e-01" "4.566147e-01"

Nessa representação, o valor 2.875775e-01 = \(2.875775 \times 10^{-01}\) = 0.2875775.

Sequências de números

Usando a função seq()

seq(1, 10)
 [1]  1  2  3  4  5  6  7  8  9 10

Ou 1:10 gera o mesmo resultado. Para a sequência variar em \(2\)

seq(from = 1, to = 10, by = 2)
[1] 1 3 5 7 9

Para obter \(15\) valores entre \(1\) e \(10\)

seq(from = 1, to = 10, length.out = 15)
 [1]  1.000000  1.642857  2.285714  2.928571  3.571429  4.214286  4.857143
 [8]  5.500000  6.142857  6.785714  7.428571  8.071429  8.714286  9.357143
[15] 10.000000

Usando a função rep()

rep(1, 10)
 [1] 1 1 1 1 1 1 1 1 1 1

Para gerar um sequência várias vezes

rep(c(1, 2, 3), 5)
 [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3

Para repetir um número da sequência várias vezes

rep(c(1, 2, 3), each = 5)
 [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3

Operações matemáticas em vetores

Operações podem ser feitas entre um vetor e um número:

num * 2
[1] 20 10  4  8 16 18

E também entre vetores de mesmo comprimento ou com comprimentos múltiplos:

num * num
[1] 100  25   4  16  64  81
num + c(2, 4, 1)
[1] 12  9  3  6 12 10

A Regra da Reciclagem

Agora tente:

num + c(2, 4, 1, 3)

Exercícios 3

  1. Crie um objeto com os valores 54, 0, 17, 94, 12.5, 2, 0.9, 15.
  2. Some o objeto acima com os valores 5, 6.

Atributos de objetos

Os objetos possuem atributos, que servem para descrever o formato do objeto:

  • names, dimnames
  • length
  • dim
  • class

Classe:

class(num)
[1] "numeric"

Comprimento:

length(num)
[1] 6

Outras classes de vetores

Vetores também podem ter outras classes:

  • Vetor de caracteres:
caracter <- c("brava", "joaquina", "armação")
caracter
[1] "brava"    "joaquina" "armação" 
  • Vetor lógico:
logico <- caracter == "armação"
logico
[1] FALSE FALSE  TRUE

ou

logico <- num > 4
logico
[1]  TRUE  TRUE FALSE FALSE  TRUE  TRUE

No exemplo anterior, a condição num > 4 é uma expressão condicional, e o símbolo > um operador lógico. Os operadores lógicos utilizados no R são:

Símbolo Significado
< menor
<= menor igual
> maior
>= maior igual
== igual
!= diferente
& e
| ou

Fator

Características:

  • Coleção de categorias ou níveis (levels)
  • Estrutura unidimensional

Utilizando as funções factor() e c():

fator <- factor(c("alta","baixa","baixa","media",
                  "alta","media","baixa","media","media"))
fator
[1] alta  baixa baixa media alta  media baixa media media
Levels: alta baixa media
class(fator)
[1] "factor"

Caso haja uma hierarquia, os níveis dos fatores podem ser ordenados:

fator <- factor(c("alta","baixa","baixa","media",
                  "alta","media","baixa","media","media"),
                levels = c("alta","media","baixa"))
fator
[1] alta  baixa baixa media alta  media baixa media media
Levels: alta media baixa

Exercícios 4

  1. Construa um único objeto com as letras: A, B, e C, repetidas cada uma 15, 12, e 8 vezes, respectivamente.
  2. Mostre na tela, em forma de verdadeiro ou falso, onde estão as letras B nesse objeto.
  3. Veja a página de ajuda da função sum() e descubra como fazer para contar o número de letras B neste vetor (usando sum()).
  4. Crie um objeto com 100 valores aleatórios de uma distribuição uniforme \(U(0,1)\). Conte quantas vezes aparecem valores maiores ou iguais a 0,5.

Misturando classes de objetos

Algumas vezes isso acontece por acidente, mas também pode acontecer de propósito.

O que acontece aqui?

w <- c(5L, "a")
x <- c(1.7, "a")
y <- c(TRUE, 2)
z <- c("a", T)

Lembre-se da regra:

Um vetor só pode conter elementos de uma mesma classe

Quando objetos de diferentes classes são misturados, ocorre a coerção, para que cada elemento possua a mesma classe.

Nos exemplos acima, nós vemos o efeito da coerção implícita, quando o R tenta representar todos os objetos de uma única forma.

Nós podemos forçar um objeto a mudar de classe, através da coerção explícita, realizada pelas funções as.*:

x <- 0:6
class(x)
[1] "integer"
as.numeric(x)
[1] 0 1 2 3 4 5 6
as.logical(x)
[1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
as.character(x)
[1] "0" "1" "2" "3" "4" "5" "6"
as.factor(x)
[1] 0 1 2 3 4 5 6
Levels: 0 1 2 3 4 5 6

De ?logical:

 Logical vectors are coerced to integer vectors in contexts where a
 numerical value is required, with ‘TRUE’ being mapped to ‘1L’,
 ‘FALSE’ to ‘0L’ and ‘NA’ to ‘NA_integer_’.
(x <- c(FALSE, TRUE))
[1] FALSE  TRUE
class(x)
[1] "logical"
as.numeric(x)
[1] 0 1

Algumas vezes não é possível fazer a coerção, então:

x <- c("a", "b", "c")
as.numeric(x)
Warning: NAs introduced by coercion
[1] NA NA NA
as.logical(x)
[1] NA NA NA

Valores perdidos e especiais

Valores perdidos devem ser definidos como NA (not available):

perd <- c(3, 5, NA, 2)
perd
[1]  3  5 NA  2
class(perd)
[1] "numeric"

Podemos testar a presença de NAs com a função is.na():

is.na(perd)
[1] FALSE FALSE  TRUE FALSE

Ou:

any(is.na(perd))
[1] TRUE

Outros valores especiais são:

  • NaN (not a number) - exemplo: 0/0
  • -Inf e Inf - exemplo: 1/0

A função is.na() também testa a presença de NaNs:

perd <- c(-1,0,1)/0
perd
[1] -Inf  NaN  Inf
is.na(perd)
[1] FALSE  TRUE FALSE

A função is.infinite() testa se há valores infinitos

is.infinite(perd)
[1]  TRUE FALSE  TRUE

Exercícios 5

  1. Calcule as 50 primeiras potências de 2, ou seja, \(2, 2^2, 2^3, \ldots, 2^{50}\).
    1. Calcule o quadrados dos números inteiros de 1 a 50, ou seja, \(1^2, 2^2, 3^2, \ldots, 50^2\).
    2. Quais pares são iguais, ou seja, quais números inteiros dos dois exercícios anteriores satisfazem a condição \(2^n = n^2\)?
    3. Quantos pares existem?
  2. Calcule o seno, coseno e a tangente para os números variando de \(0\) a \(2\pi\), com distância de \(0.1\) entre eles. (Use as funções sin(), cos(), tan()).
    1. Calcule a tangente usando a relação \(\tan(x) = \sin(x)/\cos(x)\).
    2. Calcule a diferença das tangentes calculadas pela função do R e pela razão acima.
    3. Quais valores são exatamente iguais?
    4. Qual a diferença máxima (em módulo) entre eles? Qual é a causa dessa diferença?

Matriz

Características:

  • Podem conter apenas um tipo de informação (números, caracteres)
  • Estrutura bidimensional

Utilizando a função matrix():

matriz <- matrix(1:12, nrow = 3, ncol = 4)
matriz
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
class(matriz)
[1] "matrix"

Alterando a ordem de preenchimento da matriz (por linhas):

matriz <- matrix(1:12, nrow = 3, ncol = 4, byrow = TRUE)
matriz
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12

Para verificar a dimensão da matriz:

dim(matriz)
[1] 3 4

Adicionando colunas com cbind()

cbind(matriz, rep(99, 3))
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    2    3    4   99
[2,]    5    6    7    8   99
[3,]    9   10   11   12   99

Adicionando linhas com rbind()

rbind(matriz, rep(99, 4))
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
[4,]   99   99   99   99

Matrizes também podem ser criadas a partir de vetores adicionando um atributo de dimensão

m <- 1:10
m
 [1]  1  2  3  4  5  6  7  8  9 10
class(m)
[1] "integer"
dim(m)
NULL
dim(m) <- c(2, 5)
m
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8   10
class(m)
[1] "matrix"

Operações matemáticas em matrizes

Matriz multiplicada por um escalar

matriz * 2
     [,1] [,2] [,3] [,4]
[1,]    2    4    6    8
[2,]   10   12   14   16
[3,]   18   20   22   24

Multiplicação de matrizes (observe as dimensões!)

matriz2 <- matrix(1, nrow = 4, ncol = 3)
matriz %*% matriz2
     [,1] [,2] [,3]
[1,]   10   10   10
[2,]   26   26   26
[3,]   42   42   42

Lista

Características:

  • Pode combinar uma coleção de objetos de diferentes classes (é um tipo especial de vetor)
  • Estrutura “unidimensional”: apenas o número de elementos é contado

Utilizando a função list():

lista <- list(a = 1:10, b = c("T1", "T2", "T3", "T4"), TRUE, 2 + 2)
lista
$a
 [1]  1  2  3  4  5  6  7  8  9 10

$b
[1] "T1" "T2" "T3" "T4"

[[3]]
[1] TRUE

[[4]]
[1] 4
class(lista)
[1] "list"
dim(lista)
NULL
length(lista)
[1] 4

Formando uma lista com objetos criados anteriormente:

lista <- list(fator = fator, matriz = matriz)
lista
$fator
[1] alta  baixa baixa media alta  media baixa media media
Levels: alta media baixa

$matriz
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
length(lista)
[1] 2

Data frame

Características:

  • Uma lista de vetores e/ou fatores, de mesmo comprimento
  • Pode conter diferentes tipos de dados (numérico, fator, …)
  • Estrutura bidimensional

Utilizando a função data.frame():

da <- data.frame(ano = 2000:2004,
                 prod = c(32, 54, 25, 48, 29))
da
   ano prod
1 2000   32
2 2001   54
3 2002   25
4 2003   48
5 2004   29
class(da)
[1] "data.frame"
dim(da)
[1] 5 2

Data frames podem ser formados com objetos criados anteriormente, desde que tenham o mesmo comprimento!

length(num)
[1] 6
length(fator)
[1] 9
da <- data.frame(numerico = c(num, NA, NA, NA),
                        fator = fator)
da
  numerico fator
1       10  alta
2        5 baixa
3        2 baixa
4        4 media
5        8  alta
6        9 media
7       NA baixa
8       NA media
9       NA media
class(da)
[1] "data.frame"
dim(da)
[1] 9 2
## Estrutura dos dados
str(da)
'data.frame':   9 obs. of  2 variables:
 $ numerico: num  10 5 2 4 8 9 NA NA NA
 $ fator   : Factor w/ 3 levels "alta","media",..: 1 3 3 2 1 2 3 2 2

A função str() é uma das que você precisa saber!

Para converter um data frame para uma matriz

as.matrix(da)
      numerico fator  
 [1,] "10"     "alta" 
 [2,] " 5"     "baixa"
 [3,] " 2"     "baixa"
 [4,] " 4"     "media"
 [5,] " 8"     "alta" 
 [6,] " 9"     "media"
 [7,] NA       "baixa"
 [8,] NA       "media"
 [9,] NA       "media"
data.matrix(da)
      numerico fator
 [1,]       10     1
 [2,]        5     3
 [3,]        2     3
 [4,]        4     2
 [5,]        8     1
 [6,]        9     2
 [7,]       NA     3
 [8,]       NA     2
 [9,]       NA     2

Geralmente é o resultado de data.matrix() o que você está procurando.

Note que os níveis de um fator são armazenados internamente como números: \(1^\circ\) nível = 1, \(2^\circ\) nível = 2, \(\ldots\)

fator
[1] alta  baixa baixa media alta  media baixa media media
Levels: alta media baixa
str(fator)
 Factor w/ 3 levels "alta","media",..: 1 3 3 2 1 2 3 2 2
as.numeric(fator)
[1] 1 3 3 2 1 2 3 2 2

Nomes (atributo)

Objetos do R podem ter nomes, que facilitam a auto-descrição

x <- 1:3
names(x)
NULL
names(x) <- c("Curitiba", "Paraná", "Brasil")
x
Curitiba   Paraná   Brasil 
       1        2        3 
names(x)
[1] "Curitiba" "Paraná"   "Brasil"  

Listas também podem ter nomes

x <- list(Curitiba = 1, Paraná = 2, Brasil = 3)
x
$Curitiba
[1] 1

$Paraná
[1] 2

$Brasil
[1] 3
names(x)
[1] "Curitiba" "Paraná"   "Brasil"  

Associando nomes às linhas e colunas de uma matriz:

rownames(matriz) <- c("A","B","C")
colnames(matriz) <- c("T1","T2","T3","T4")
matriz
  T1 T2 T3 T4
A  1  2  3  4
B  5  6  7  8
C  9 10 11 12

Para data frames existe uma função especial para os nomes de linhas, row.names(). Data frames também não possuem nomes de colunas, apenas nomes, já que é um caso particular de lista. Então para verificar/alterar nomes de colunas de um data frame também use names().

names(da)
[1] "numerico" "fator"   
row.names(da)
[1] "1" "2" "3" "4" "5" "6" "7" "8" "9"

Um resumo das funções para alterar/acessar nomes de linhas e colunas em matrizes e data frames.

Classe Nomes de colunas Nomes de linhas
data.frame names() row.names()
matrix colnames() rownames()

Exercícios 6

  1. Crie um objeto para armazenar a seguinte matriz \[\left[ \begin{array}{ccc} 2 & 8 & 4 \\ 0 & 4 & 1 \\ 9 & 7 & 5 \end{array} \right]\]
  2. Atribua nomes para as linhas e colunas dessa matriz.
  3. Crie uma lista (não nomeada) com dois componentes: (1) um vetor com as letras A, B, e C, repetidas 2, 5, e 4 vezes respectivamente; e (2) a matriz do exemplo anterior.
  4. Atribua nomes para estes dois componentes da lista.
  5. Inclua mais um componente nesta lista, com o nome de fator, e que seja um vetor da classe fator, idêntico ao objeto caracter criado acima (que possui apenas os nomes brava, joaquina, armação).
  6. Você contou 42 caranguejos na Joaquina, 34 no Campeche, 59 na Armação, e 18 na Praia Mole. Crie um data frame para armazenar estas informações (número de caranguejos observados e local).

A resolução de todos os exercícios desta página está disponível neste script.


Licença Creative Commons 4.0

Este conteúdo está disponível por meio da Licença Creative Commons 4.0