Estatística Computacional Com R
Estatística Computacional Com R
Estatística Computacional Com R
2018-07-24
Última atualização: 2023-02-01
2
Sumário
I R básico 9
1 Computação científica e interação com o R 11
1.1 Interagindo com o computador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2 Editores de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2.1 Editores para R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3 R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3.1 Configuração inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.2 O R como uma calculadora . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.3 Para onde vão os resultados? . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.4 O editor de scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.3.5 Operadores aritméticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.3.6 Ordens de execução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.3.7 “Salvando” resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.3.8 Finalizando o programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.3.9 Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2 Objetos e classes 17
2.1 Funções e argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1.1 Outros tipos de argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2 Mecanismos de ajuda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3 Criando uma função . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4 Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4.1 Nomes de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.4.2 Gerenciando a área de trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.5 Tipos e classes de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.5.1 Vetores numéricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.5.2 Outros tipos de vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.3 Misturando classes de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5.4 Valores perdidos e especiais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.6 Outras classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.6.1 Fator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.6.2 Matriz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.6.3 Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.6.4 Lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.6.5 Data frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.7 Atributos de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3
4 SUMÁRIO
II Estatística 81
6 Análise exploratória de dados 83
6.1 O conjunto de dados milsa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
6.2 Análise univariada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
6.2.1 Variável Qualitativa Nominal . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
6.2.2 Variável Qualitativa Ordinal . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
6.2.3 Variável quantitativa discreta . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
6.2.4 Variável quantitativa contínua . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6.3 Análise Bivariada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.3.1 Qualitativa vs qualitativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.3.2 Qualitativa vs quantitativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.3.3 Quantitativa vs Quantitativa . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
C Scripts 173
6 SUMÁRIO
Prefácio
Esta apostila foi delineada para servir como material de apoio à disciplina CE083- Estatística
Computacional I. Tal disciplina é ministrada no segundo semestre do curso de bacharelado em
Estatística da UFPR. O principal objetivo do curso é introduzir os aspectos básico do software
estatístico R. O curso é dividido em duas etapas: a primeira etapa é destinada a aspectos básicos da
linguagem R e sua operacionalização. Esta etapa complempla os Capítulos 1 a 5. A segunda etapa
objetiva exemplificar o uso do software R através de técnicas de estatística básica. Nesta etapa
revisamos as principais técnicas para resumo e apresentação de dados através de gráficos e tabelas,
bem como, sua implementação computacional através do software R. Os principais aspectos ligados
à distribuições de probabilidades são discutidos no Capítulo 7, incluindo tópicos em integração
numérica. Por fim, no Capítulo 8 apresentamos um conjunto de técnicas para a construção de
intervalos de confiança e testes de hipóteses e exemplificamos as as principais técnicas através de
sua implementação em R. Alguns tópicos adicionais como documentos dinâmicos e programação
orientada a objetos são apresentados no Apêndice.
Informação de sessão
Abaixo seguem as informações do ambiente em que o documento foi gerado pela última vez.
Wednesday, 01 February, 2023, 21:05
----------------------------------------
R version 4.2.2 (2022-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.1 LTS
locale:
[1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
[4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
[7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
7
8 SUMÁRIO
R básico
9
Capítulo 1
11
12 CAPÍTULO 1. COMPUTAÇÃO CIENTÍFICA E INTERAÇÃO COM O R
• Identação automática;
• Complementação de parênteses;
• Destaque de sintaxe (syntax highlighting);
• Numeração de linhas;
• Auto completar comandos.
Linux:
• Vim-R-plugin.
• Gedit-R-plugin.
Todas as plataformas:
1.3 R
“The statistical software should help, by supporting each step from user to programmer, with as
few intrusive barriers as possible.”
— John M. Chambers
Tudo no R é um objeto. . .
Pequeno histórico:
• 1980: Linguagem S: desenvolvida por R. Becker, J. Chambers e A. Wilks (AT&T Bell Labora-
tories);
• 1980: Versão comercial: S-Plus (Insightful Corporation);
• 1996: Versão livre: R desenvolvido por R. Ihaka e R. Gentleman (Universidade de Auckland);
• 1997: R Development Core Team;
• Hoje: desenvolvedores principais (core team) e muitos outros colaboradores em todo o mundo;
• Estatísticos, matemáticos, programadores e profissionais de formação e atuação em outras
áreas.
1.3. R 13
• 2) Pelo menu do RStudio em Session > Set Working Directory > Choose Directory...
Confira o diretório que está trabalhando com a função
getwd()
• Note que o resultado é apenas mostrado na tela, nada é salvo na memória (por enquanto).
14 CAPÍTULO 1. COMPUTAÇÃO CIENTÍFICA E INTERAÇÃO COM O R
Operador Significado
+ adição
- subtração
* multiplicação
/ divisão
ˆ ou ** potência
sqrt() raíz quadrada
exp() exponencial
log(); log2(); log10() logaritmos
factorial() fatorial
Exercícios
1. Calcule a seguinte equação: 32 + 162 − 253
2. Divida o resultado por 345
1.3. R 15
− 2 24 − 1
3. Qual o resultado da expressão e 4! ?
4. E do logaritmo desta expressão?
Do exercício anterior
> x <- 32 + 16ˆ2 - 25ˆ3
> x
[1] -15337
> x/345
[1] -44.45507
> (y <- (exp(-2) * 2ˆ4 - 1)/factorial(4))
[1] 0.04855686
> log(y)
[1] -3.02502
Quando criamos uma variável (x, y), ela fica armazenada temporariamente na memória RAM.
• O workspace consiste de tudo que foi criado durante uma sessão do R, e fica armazenado na
memória RAM.
Para efetivamente salvar essas variáveis, podemos armazenar esse workspace do R em disco, em
um arquivo chamado .Rdata
16 CAPÍTULO 1. COMPUTAÇÃO CIENTÍFICA E INTERAÇÃO COM O R
No RStudio:
• File > Save As...
• Na janela que abrir, digite o nome do arquivo (por exemplo script_aula1) e salve.
• Automaticamente o script será salvo com a extensão .R (nesse caso script_aula1.R) no
diretório de trabalho que você configurou no início.
Alternativamente, você pode também salvar toda sua área de trabalho, clicando em Workspace >
Save As Default Workspace. Este processo irá gerar dois arquivos:
• .Rdata: contém todos os objetos criados durante uma sessão. Não é necessário (e nem
recomendado) dar um nome antes do ponto. Dessa forma, a próxima vez que o programa
for iniciado neste diretório, a área de trabalho será carregada automaticamente.
• .Rhistory: um arquivo texto que contém todos os comandos que foram digitados no console.
1.3.9 Encoding
Caracteres especiais (cedilha, acentos, dentre outros) podem gerar problemas de visualização entre
diferentes sistemas operacionais que utilizam diferentes codificações (encodings). Não iremos tratar
disto neste momento, mas se voce visualizar estes caracteres de maneira “estranha” é porque irá
precisar conciliar os “encodings”.
Referências
• Leek, J. The Elements of Data Analytic Style. Leanpub, 2015.
• Murrell, P. Introduction to data technologies. Boca Raton: Chapman & Hall/CRC, 2009.
• Peng, RD. R programming for data science. Leanpub, 2015.
Capítulo 2
Objetos e classes
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)
17
18 CAPÍTULO 2. OBJETOS E CLASSES
args(sample)
function (x, size, replace = FALSE, prob = NULL)
NULL
ou
help(runif)
Procura por funções que contenham palavra em qualquer parte de sua documentação:
help.search("palavra")
search()
Note que o primeiro elemento, .GlobalEnv, será sempre carregado pois ele é o ambiente que irá
armazenar (e deixar disponível) os objetos criados pelo usuário. Para carregar um pacote instalado,
usamos a função library(), por exemplo
library(lattice)
search()
Se o diretório padrão de instalação de um pacote for de acesso restrito (root por exemplo), o R irá
perguntar se você gostaria de instalar o pacote em uma biblioteca pessoal, e sugerirá um diretório
que possui as permissões necessárias. Você pode se antecipar e já definir e criar um diretório na
sua pasta pessoal, e instalar os pacotes sempre nesse local. Por exemplo, defina ~/R/library como
sua biblioteca pessoal. Para instalar os pacotes sempre nesse diretório faça:
install.packages("mvtnorm", lib = "~/R/library")
Para verificar as bibliotecas disponíveis e se existem pacotes para serem atualizados, use
packageStatus()
E chama-la através de
ola.mundo()
Olá mundo
A função acima não permite alterar o resultado da saída. Podemos fazer isso incluindo um
argumento
ola.mundo <- function(texto){
writeLines(texto)
}
Exercícios
1. Usando a função runif() gere 30 números aleatórios entre:
• 0e1
• -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
4. Crie uma função para simular a jogada de um dado.
5. Crie uma função para simular a jogada de dois dados.
2.4 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. Duas
das funções genéricas mais importantes são:
– summary().
– plot().
Veja o resultado de
methods(summary)
methods(plot)
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
2.4. OBJETOS 21
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
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).
• O R é case-sensitive, portanto:
Cuidado! O comando acima apaga todos os objetos na sua área de trabalho sem perguntar. Depois
só é possível recuperar os objetos ao rodar o script novamente.
22 CAPÍTULO 2. OBJETOS E CLASSES
Exercícios
1. Armazene o resultado da equação 32 + 162 − 253 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 ∼ Poisson(5).
Note que a diferença entre numeric e integer também possui impacto computacional, pois o arma-
zenamento 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:
24 CAPÍTULO 2. OBJETOS E CLASSES
object.size(num)
96 bytes
object.size(x)
80 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.
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 0.033895622
[7] 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 64 bits. Como consequência, cada
número possui uma acurácia de até 16 dígitos significativos. Isso pode introduzir algum tipo de
erro, por exemplo:
sqrt(2)ˆ2 - 2
[1] 4.440892e-16
print(sqrt(2)ˆ2, digits = 22)
[1] 2.000000000000000444089
não é exatamente zero, pois a raíz quadrada de 2 não pode ser armazenada com toda precisão
com “apenas” 16 dígitos significativos. Esse tipo de erro é chamado de erro de ponto flutuante,
e as operações nessas condições são chamadas de aritmética de ponto flutuante. Para mais
informações sobre esse assunto veja What Every Computer Scientist Should Know About Floating-
Point Arithmetic e Why doesn’t R think these numbers are equal?.
No R os números podem ser representados com até 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
2.5. TIPOS E CLASSES DE OBJETOS 25
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" "9.404673e-01"
[6] "4.555650e-02" "5.281055e-01" "8.924190e-01" "5.514350e-01" "4.566147e-01"
Agora tente:
num + c(2, 4, 1, 3)
• Vetor lógico:
logico <- caracter == "armação"
logico
[1] FALSE FALSE TRUE
typeof(logico)
[1] "logical"
class(logico)
[1] "logical"
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:
Lembre-se da regra:
Um vetor só pode conter elementos do mesmo tipo!
Quando objetos de diferentes tipos 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
typeof(x)
[1] "integer"
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
as.logical(x)
[1] NA NA NA
Ou:
any(is.na(perd))
[1] TRUE
Exercícios
1. Crie um objeto com os valores 54, 0, 17, 94, 12.5, 2, 0.9, 15.
a. Some o objeto acima com os valores 5, 6, e depois com os valores 5, 6, 7.
2. Construa um único objeto com as letras: A, B, e C, repetidas cada uma 15, 12, e 8 vezes,
respectivamente.
a. Mostre na tela, em forma de verdadeiro ou falso, onde estão as letras B nesse objeto.
b. 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()).
3. 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.
4. Calcule as 50 primeiras potências de 2, ou seja, 2, 22 , 23 , . . . , 250 .
a. Calcule o quadrado dos números inteiros de 1 a 50, ou seja, 12 , 22 , 32 , . . . , 502 .
b. Quais pares são iguais, ou seja, quais números inteiros dos dois exercícios anteriores
satisfazem a condição 2n = n2 ?
c. Quantos pares existem?
5. Calcule o seno, coseno e a tangente para os números variando de 0 a 2π, com distância de 0.1
entre eles. (Use as funções sin(), cos(), tan()).
2.6. OUTRAS CLASSES 29
2.6.1 Fator
Os fatores são parecidos com caracteres no R, mas são armazenados e tratados de maneira diferente.
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"
typeof(fator)
[1] "integer"
Note que o objeto é da classe factor, mas seu tipo básico é integer! Isso significa que cada
categoria única é identificada internamente por um número, e isso faz com que os fatores possuam
uma ordenação, de acordo com as categorias únicas. Por isso existe a identificação dos Levels
(níveis) de um fator.
Veja o que acontece quando “remover a classe” desse objeto
unclass(fator)
[1] 1 2 2 3 1 3 2 3 3
attr(,"levels")
[1] "alta" "baixa" "media"
Fatores podem ser convertidos para caracteres, e também para números inteiros
as.character(fator)
[1] "alta" "baixa" "baixa" "media" "alta" "media" "baixa" "media" "media"
as.integer(fator)
[1] 1 2 2 3 1 3 2 3 3
Caso haja uma hierarquia, os níveis dos fatores podem ser ordenados explicitamente através do
argumento levels:
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
30 CAPÍTULO 2. OBJETOS E CLASSES
typeof(fator)
[1] "integer"
class(fator)
[1] "factor"
Além disso, os níveis dos fatores podem também ser explicitamente ordenados
fator <- factor(c("alta","baixa","baixa","media",
"alta","media","baixa","media","media"),
levels = c("baixa", "media", "alta"),
ordered = TRUE)
fator
[1] alta baixa baixa media alta media baixa media media
Levels: baixa < media < alta
typeof(fator)
[1] "integer"
class(fator)
[1] "ordered" "factor"
Veja que um objeto pode ter mais de uma classe. Isso geralmente só será útil em casos especificos.
As seguintes funções são úteis para verificar os níveis e o número de níveis de um fator:
levels(fator)
[1] "baixa" "media" "alta"
nlevels(fator)
[1] 3
2.6.2 Matriz
Matrizes são vetores que podem ser dispostos em duas dimensões.
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" "array"
typeof(matriz)
[1] "integer"
dim(matriz)
[1] 3 4
Matrizes também podem ser criadas a partir de vetores adicionando um atributo de dimensão,
por exemplo,
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" "array"
typeof(m)
[1] "integer"
2.6.3 Array
Um array é a forma mais geral de uma matriz, pois pode ter n dimensões.
Características:
• Estrutura n-dimensional.
• Assim como as matrizes, podem conter apenas um tipo de informação (números, caracteres).
Para criar um array, usamos a função array(), passando como primeiro argumento um vetor
atômico, e especificamos a dimensão com o argumento dim. Por exemplo, para criar um objeto
com 3 dimensões 2 × 2 × 3, fazemos
ar <- array(1:12, dim = c(2, 2, 3))
ar
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 3
[,1] [,2]
[1,] 9 11
[2,] 10 12
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
, , 2
[,1] [,2]
[1,] 7 10
[2,] 8 11
[3,] 9 12
2.6.4 Lista
Como já vimos, uma lista não é uma “classe” propriamente dita, mas sim um tipo de estrutura de
dados básico, ao lado dos vetores atômicos. E, assim como os vetores atômicos, listas são estruturas
unidimensionais. A grande diferença é que listas agrupam objetos de diferentes tipos, inclusive
outras listas.
Características:
2.6. OUTRAS CLASSES 33
• Pode combinar uma coleção de objetos de diferentes tipos ou classes (é um tipo básico de
vetor, assim como os vetores atômicos).
• Estrutura “unidimensional”: apenas o número de elementos na lista é contado.
Por exemplo, podemos criar uma lista com uma sequência de números, um caracter e outra lista.
lista <- list(1:30, "R", list(TRUE, FALSE))
lista
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
[26] 26 27 28 29 30
[[2]]
[1] "R"
[[3]]
[[3]][[1]]
[1] TRUE
[[3]][[2]]
[1] FALSE
class(lista)
[1] "list"
typeof(lista)
[1] "list"
Para melhor visualizar a estrutura dessa lista (ou de qualquer outro objeto) podemos usar a função
str()
str(lista)
List of 3
$ : int [1:30] 1 2 3 4 5 6 7 8 9 10 ...
$ : chr "R"
$ :List of 2
..$ : logi TRUE
..$ : logi FALSE
Listas podem armazenar objetos de diferentes classes e dimensões, por exemplo, usando objetos
criados anteriormente
lista <- list(fator, matriz)
lista
[[1]]
[1] alta baixa baixa media alta media baixa media media
Levels: baixa < media < alta
[[2]]
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
length(lista)
34 CAPÍTULO 2. OBJETOS E CLASSES
[1] 2
Em versões anteriores a função data.frame() convertia caracteres para fator automaticamente mas
o padrão mudou. Use o argumento stringsAsFactors para controlar este comportamento.
da <- data.frame(nome = c("João", "José", "Maria"),
sexo = c("M", "M", "F"),
idade = c(32, 34, 30))
da
nome sexo idade
1 João M 32
2 José M 34
3 Maria F 30
str(da)
'data.frame': 3 obs. of 3 variables:
$ nome : chr "João" "José" "Maria"
$ sexo : chr "M" "M" "F"
$ idade: num 32 34 30
Data frames podem ser formados com objetos criados anteriormente, desde que tenham o mesmo
comprimento:
length(num)
[1] 6
length(fator)
[1] 9
db <- data.frame(numerico = c(num, NA, NA, NA),
fator = fator)
db
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
str(db)
'data.frame': 9 obs. of 2 variables:
$ numerico: num 10 5 2 4 8 9 NA NA NA
$ fator : Ord.factor w/ 3 levels "baixa"<"media"<..: 3 1 1 2 3 2 1 2 2
Algumas vezes pode ser necessário converter um data frame para uma matriz. Existem duas
opções:
as.matrix(db)
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"
36 CAPÍTULO 2. OBJETOS E CLASSES
[9,] NA "media"
data.matrix(db)
numerico fator
[1,] 10 3
[2,] 5 1
[3,] 2 1
[4,] 4 2
[5,] 8 3
[6,] 9 2
[7,] NA 1
[8,] NA 2
[9,] NA 2
Mostra que o objeto x não possui nenhum atributo. Mas podemos definir nomes, por exemplo,
para cada componente desse vetor
names(x)
NULL
names(x) <- c("um", "dois", "tres", "quatro", "cinco", "seis")
names(x)
[1] "um" "dois" "tres" "quatro" "cinco" "seis"
attributes(x)
$names
[1] "um" "dois" "tres" "quatro" "cinco" "seis"
Nesse caso específico, o R irá mostrar os nomes acima dos componentes, mas isso não altera como
as operaçõs serão realizadas.
2.7. ATRIBUTOS DE OBJETOS 37
x
um dois tres quatro cinco seis
1 2 3 4 5 6
x + 2
um dois tres quatro cinco seis
3 4 5 6 7 8
Os nomes então podem ser definidos através da função auxiliar names(), sendo assim, também
podemos remover esse atributo declarando ele como nulo.
names(x) <- NULL
attributes(x)
NULL
x
[1] 1 2 3 4 5 6
Outros atributos também podem ser definidos de maneira similar. Veja os exemplos abaixo:
length(x)
[1] 6
## Altera o comprimento (preenche com NA)
length(x) <- 10
x
[1] 1 2 3 4 5 6 NA NA NA NA
## Altera a dimensão
length(x) <- 6
dim(x)
NULL
dim(x) <- c(3, 2)
x
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
attributes(x)
$dim
[1] 3 2
## Remove dimensão
dim(x) <- NULL
x
[1] 1 2 3 4 5 6
Assim como vimos em data frames, 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"
matriz
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
attributes(matriz)
$dim
[1] 3 4
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
attributes(matriz)
$dim
[1] 3 4
$dimnames
$dimnames[[1]]
[1] "A" "B" "C"
$dimnames[[2]]
[1] "T1" "T2" "T3" "T4"
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().
da
nome sexo idade
1 João M 32
2 José M 34
3 Maria F 30
attributes(da)
$names
[1] "nome" "sexo" "idade"
$class
[1] "data.frame"
$row.names
[1] 1 2 3
names(da)
[1] "nome" "sexo" "idade"
row.names(da)
[1] "1" "2" "3"
Um resumo das funções para alterar/acessar nomes de linhas e colunas em matrizes e data frames.
Exercícios
1. Crie um objeto para armazenar a seguinte matriz
2 8 4
0 4 1
9 7 5
Referências
Para mais detalhes e exemplos dos assuntos abordados aqui, veja Grolemund (2014). Uma
abordagem mais avançada e detalhada sobre programação orientada a objetos no R pode ser
consultada em Wickham (2015).
Grolemund, Garrett. 2014. Hands-On Programming with R - Write Your Own Functions and Simulations.
O’Reily Media. http://shop.oreilly.com/product/0636920028574.do.
Wickham, Hadley. 2015. Advanced R. CRC Press.
40 CAPÍTULO 2. OBJETOS E CLASSES
Capítulo 3
3.1 Indexação
Existem 6 maneiras diferentes de indexar valores no R. Podemos indexar usando:
• Inteiros positivos.
• Inteiros negativos.
• Zero.
• Espaço em branco.
• Nomes.
• Valores lógicos.
Existem três tipos de operadores que podem ser usados para indexar (e selecionar) sub-conjuntos
(subsets) de objetos no R:
• O operador [ ] sempre retorna um objeto da mesma classe que o original. Pode ser usado
para selecionar múltiplos elementos de um objeto.
• O operador[[ ]] é usado para extrair elementos de uma lista ou data frame. Pode ser usado
para extrair um único elemento, e a classe do objeto retornado não precisa necessariamente
ser uma lista ou data frame.
• O operador $ é usado para extrair elementos nomeados de uma lista ou data frame. É similar
ao operador [[ ]].
Ou:
41
42 CAPÍTULO 3. INDEXAÇÃO E SELEÇÃO CONDICIONAL
Também é possível selecionar uma sequência de elementos (com qualquer uma das funções de
gerar sequências que já vimos antes):
## Seleciona os elementos de 1 a 5
cont[1:5]
[1] 8 4 NA 9 6
## Seleciona os elementos nas posições ímpar
cont[seq(1, 8, by = 2)]
[1] 8 NA 6 7
Mas note que para selecionar todos menos aqueles de uma sequência, precisamos colocá-la entre
parênteses
cont[-1:5]
Error in cont[-1:5]: only 0's may be mixed with negative subscripts
cont[-(1:5)]
[1] 1 7 9
Para selecionar todos os elementos que sejam NA, ou todos menos os NAs, precisamos usar a função
is.na()
## Para selecionar os NAs
cont[is.na(cont)]
[1] NA
## Para selecionar todos menos os NAs
cont[!is.na(cont)]
[1] 8 4 9 6 1 7 9
Note que se utilizarmos o operador de atribuição <- em conjunto com uma indexação, estaremos
substituindo os valores selecionados pelos valores do lado direito do operador de atribuição.
Podemos também utilizar mais duas formas de indexação no R: espaços em branco e zero:
3.1. INDEXAÇÃO 43
cont[0]
numeric(0)
cont[]
[1] 8 4 NA 9 6 1 7 9
Note que o índice zero não existe no R, mas ao utilizá-lo é retornado um vetor “vazio”, ou um
vetor de comprimento zero. Essa forma de indexação é raramente utilizada no R.
Ao deixar um espaço em branco, estamos simplesmente informando que queremos todos os valores
daquele vetor. Essa forma de indexação será particularmente útil para objetos que possuem duas
ou mais dimensões, como matrizes e data frames.
Exercícios
1. Crie um vetor com os valores: 88, 5, 12, 13.
2. Selecione o elemento na posição 3.
3. Selecione o valor 88.
4. Selecione os valores 13 e 5.
5. Selecione todos os valores, menos o 88 e o 13.
6. Insira o valor 168 entre os valores 12 e 13, criando um novo objeto.
mat[, 1]
[1] 1 2 3
Note que o resultado destas extrações trazem os valores internos das matrizes, mas com a dimensão
reduzida (nestes casos para uma dimensão). Se o objetivo for, por exemplo, extrair uma parte da
matriz, mas mantendo as duas dimensões, então precisamos usar o argumento drop da “função” [
(sim, também é uma função; veja "?["). Veja as diferenças:
mat[3, 2]
[1] 6
mat[3, 2, drop = FALSE]
[,1]
[1,] 6
mat[1, ]
[1] 1 4 7
mat[1, , drop = FALSE]
[,1] [,2] [,3]
[1,] 1 4 7
E note que aqui a dimensão já é 2 pois naturalmente o resultado precisa ser representado em duas
dimensões.
[[2]]
A B C
X 1 4 7
Y 2 5 8
Z 3 6 9
[[3]]
[1] 5 4 3 2 1 0
Geralmente o que queremos é acessar os elementos que estão contidos nos componentes da lista, e
para isso precisamos usar [[ no lugar de [:
lis[[1]]
[1] 3 8 7 4
class(lis[[1]])
[1] "numeric"
Isso é importante, por exemplo, se quisessemos aplicar uma função qualquer a um componente da
lista. No primeiro caso isso não é possível pois o conteúdo continua dentro de uma lista, enquanto
que no segundo caso os valores retornados são os próprios números:
mean(lis[1])
Warning in mean.default(lis[1]): argument is not numeric or logical: returning
NA
[1] NA
mean(lis[[1]])
[1] 5.5
Note que o segundo elemento da lista é uma matriz, portanto a indexação da matriz dentro da lista
46 CAPÍTULO 3. INDEXAÇÃO E SELEÇÃO CONDICIONAL
Se a lista tiver componentes nomeados, eles podem ser acessados com o operador $:
lis <- list(vetor1 = c(3, 8, 7, 4), mat = mat, vetor2 = 5:0)
## Ou
## names(lis) <- c("vetor1", "mat", "vetor2")
lis
$vetor1
[1] 3 8 7 4
$mat
A B C
X 1 4 7
Y 2 5 8
Z 3 6 9
$vetor2
[1] 5 4 3 2 1 0
## Acesando o segundo componente
lis$mat
A B C
X 1 4 7
Y 2 5 8
Z 3 6 9
## Linha 2 e coluna 3
lis$mat[2, 3]
[1] 8
## Terceiro elemento do primeiro componente
lis$vetor1[3]
[1] 7
Ou então
lis[["mat"]]
A B C
X 1 4 7
Y 2 5 8
Z 3 6 9
lis[["vetor1"]][3]
[1] 7
Para acessar o segundo elemento da primeira coluna (segue a mesma lógica da indexação de
matrizes pois também possui duas dimensões):
da[2, 1]
[1] 3
Note que o argumento drop= também é válido se quiser manter a dimensão do objeto
da[, "B"]
[1] 2 NA 5 8
da[, "B", drop = FALSE]
B
1 2
2 NA
3 5
4 8
Como o data frame é um caso particular de uma lista (onde todos os componentes tem o mesmo
comprimento), as colunas de um data frame também podem ser acessadas com $:
da$A
[1] 4 3 2 1
Assim como nas listas, podemos indexar um data frame usando apenas um índice, que nesse caso
retorna a coluna (componente) do data frame:
da[1]
A
1 4
2 3
3 2
4 1
48 CAPÍTULO 3. INDEXAÇÃO E SELEÇÃO CONDICIONAL
class(da[1])
[1] "data.frame"
Note que dessa forma a classe é mantida. Também podemos indexar os data frames usando [[ da
mesma forma como em listas
da[[1]]
[1] 4 3 2 1
da[["A"]]
[1] 4 3 2 1
da[["A"]][2:3]
[1] 3 2
Para lidar com NAs em data frames, podemos também usar a função is.na()
da[is.na(da), ] # nao retorna o resultado esperado
A B
NA NA NA
## Deve ser feito por coluna
da[is.na(da$A), ]
[1] A B
<0 rows> (or 0-length row.names)
da[is.na(da$B), ]
A B
2 3 NA
## De maneira geral
is.na(da)
A B
[1,] FALSE FALSE
[2,] FALSE TRUE
[3,] FALSE FALSE
[4,] FALSE FALSE
is.na(da$A)
[1] FALSE FALSE FALSE FALSE
is.na(da$B)
[1] FALSE TRUE FALSE FALSE
Para remover as linhas que possuem NA, note que será necessário remover todas as colunas daquela
linha, pois data frames não podem ter colunas de comprimentos diferentes
da[!is.na(da$B), ]
A B
1 4 2
3 2 5
4 1 8
Para evitar fazer muitas indexações de um mesmo data frame, por exemplo, podemos utilizar a
função with()
with(da, A)
[1] 4 3 2 1
é o mesmo que
da$A
[1] 4 3 2 1
Também é útil para acessar elementos específicos dentro de data frames. Por exemplo, o terceiro
elemento da coluna B
with(da, B[3])
[1] 5
Exercícios
1. Crie a seguinte matriz
4 16 2
10 5 11
.
9 9 5
2 0 NA
Para entender como funciona a seleção condicional, observe apenas o resultado da condição dentro
do colchetes:
## Usando & (e)
dados > 15 & dados <= 35
[1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
## Usando | (ou)
dados > 15 | dados <= 35
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Os valores selecionados serão aqueles em que a condição for TRUE, no primeiro caso apenas o
quarto elemento do vetor dados.
A seleção condicional também é muito útil para selecionar elementos de um vetor, baseado em
uma condição de outro vetor.
Considere o seguinte vetor de caracteres
cara <- letters[1:length(dados)]
Considere que de alguma forma, os objetos dados e cara possuem alguma relação. Sendo assim,
podemos selecionar elementos de dados, baseados em alguma condição de cara
## Elemento de dados onde cara é igual a "c"
dados[cara == "c"]
[1] 42
mas nesse caso só temos o primeiro elemento. Um operador muito útil nestes casos é o %in%
3.2. SELEÇÃO CONDICIONAL 51
Veja a diferença
cara == c("a", "c")
[1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
cara %in% c("a", "c")
[1] TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
Exercícios
1. Crie um vetor (x) com os valores 3, 8, 10, 4, 9, 7, 1, 9, 2, 4.
2. Selecione os elementos maiores ou iguais a 5.
52 CAPÍTULO 3. INDEXAÇÃO E SELEÇÃO CONDICIONAL
Observe as linhas onde a captura seja maior que 20, selecionando apenas a coluna captura:
dados[dados$captura > 20, "captura"]
[1] 26 25 32 NA
A função subset() serve para os mesmos propósitos, e facilita todo o processo de seleção condicio-
nal:
dados[dados$porto == "SC", ]
ano captura porto
3 2003 25 SC
4 2004 32 SC
subset(dados, porto == "SC")
3.2. SELEÇÃO CONDICIONAL 53
A grande vantagem é que a função subset() já lida com os NAs (se isso for o que você precisa).
Exercícios
1. 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).
2. Com o data frame criado no exercício anterior, mostre qual a praia onde foram coletadas
menos de 30 caranguejos (usando seleção condicional!).
3. Crie uma nova coluna (região) neste data frame indicando que Joaquina e Praia Mole estão
localizadas no leste da ilha (leste) e Campeche e Armação estão no sul (sul).
4. Selecione as praias de região leste que possuem menos de 20 caranguejos contados.
5. Você está interessado em saber em qual das duas praias do sul, o número de caranguejos
contados foi maior do que 40. Usando a seleção condicional, mostre essa informação na tela.
6. Qual região possui praias com mais de 50 caranguejos contados?
54 CAPÍTULO 3. INDEXAÇÃO E SELEÇÃO CONDICIONAL
Capítulo 4
A entrada de dados no R pode ser realizada de diferentes formas. O formato mais adequado vai
depender do tamanho do conjunto de dados, e se os dados já existem em outro formato para serem
importados ou se serão digitados diretamente no R.
A seguir são descritas as formas de entrada de dados com indicação de quando cada uma das
formas deve ser usada. Os três primeiros casos são adequados para entrada de dados diretamente
no R, os seguintes descrevem como importar dados já disponíveis eletronicamente de um arquivo
texto, em outro sistema ou no próprio R.
Posteriormente também será mostrado como fazer para exportar bases de dados geradas e/ou
alteradas dentro do R.
55
56 CAPÍTULO 4. ENTRADA E SAÍDA DE DADOS NO R
y <- scan()
1: 11
2: 24
3: 35
4: 29
5: 39
6: 47
7:
Read 6 items
y
[1] 11 24 35 29 39 47
Os dados também podem ser digitados em sequência, desde que separados por um espaço,
y <- scan()
1: 11 24
3: 35 29
5: 39 47
7:
Read 6 items
y
[1] 11 24 35 29 39 47
Este formato é mais ágil que o anterior (com c(), por exemplo) e é conveniente para digitar vetores
longos. Esta função pode também ser usada para ler dados de um arquivo ou conexão, aceitando
inclusive endereços de URLs (endereços da web) o que iremos mencionar em detalhes mais adiante.
Por padrão, a função scan() aceita apenas valores numéricos como entrada (lembre-se que vetores
só podem ter elementos da mesma classe). Para alterar a classe de objeto de entrada, precisamos
especificar o argumento what de scan(). Por exemplo, para entrar com um vetor de caracteres,
fazemos
x <- scan(what = "character")
1: a
2: b
3: c
4:
Read 3 items
x
[1] "a" "b" "c"
Outras classe possíveis para o argumento what são: logical, integer, numeric, complex, character,
raw e list.
Exercícios
1. Usando a função scan() crie objetos para armazenar os seguintes valores:
a. 19, 13, 19, 23, 18, 20, 25, 14, 20, 18, 22, 18, 23, 14, 19
b. joaquina, armação, praia brava, praia mole, morro das pedras
c. TRUE, TRUE, FALSE, FALSE, TRUE
4.1. ENTRADA DE DADOS 57
Esta função é particularmente útil para ler entradas na forma de texto (strings). Por exemplo, para
ler uma linha a ser digitada na tela do R, siga o comando abaixo e digite o texto indicado. Ao
terminar pressione a tecla Enter e o texto será armazenado no objeto texto.
texto <- readLines(n = 1)
Um possível uso é dentro que funções que solicitem que o usuário responda e/ou entre com
informações na medida que são solicitadas. Experimente definir e rodar a função a seguir.
fn.ex <- function() {
cat("Digite o nome do time de futebol de sua preferência (em letras minúsculas)\n")
time <- readLines(n = 1)
if (time == "atletico-pr")
cat("BOA ESCOLHA!!!\n")
else cat("Ihh, tá mal de escolha...\n")
return(invisible())
}
fn.ex()
Nesse exemplo, readLines() foi utilizada para efetuar a leitura via teclado, mas a função permite
ainda entrada de dados por conexões com outros dispositivos de input. Por exemplo, pode ser
utilizada para ler texto de um arquivo. Consulte a documentação da função para maiores detalhes
e exemplos.
A forma mais fácil de fazer isto é usar dados em formato texto (arquivo do tipo ASCII). Por
exemplo, se seus dados estão disponíveis em uma planilha eletrônica como LibreOffice Calc, MS
Excel ou similar, você pode escolher a opção Salvar como. . . e gravar os dados em um arquivo em
formato texto. Os dois principais formatos de texto são:
• txt: arquivo de texto puro, onde as colunas são separadas geralmente por uma tabulação
(Tab) ou espaço (Spc)
• csv: arquivo de texto, onde as colunas são geralmente separadas por vírgula (comma separated
value), ou ponto-e-vírgula.
No R usa-se scan() mencionada anteriormente, ou então a função mais flexível read.table() para
ler os dados de um arquivo texto e armazenar no formato de um data frame.
Argumentos:
• "crabs.csv": nome do arquivo. (Considerando que o arquivo crabs.csv está dentro do
diretório dados).
• header = TRUE: significa que a primeira linha do arquivo deve ser interpretada como os
nomes das colunas.
• sep = ";": o separador de colunas (também pode ser ",", "\t" para tabulação e para
espaços).
• dec = ",": o separador de decimais (também pode ser ".").
As funções read.csv() e read.csv2() são chamadas de wrappers (envelopes) que tornam o uso
da função read.table() um pouco mais direta, alterando alguns argumentos. Por exemplo, o
comando acima poderia ser substituído por
dados <- read.csv2("dados/crabs.csv")
O objeto criado com as funções read.*() sempre serão da classe data.frame, e quando houverem
colunas com caracteres, estas colunas sempre serão da classe factor. Você pode alterar esse padrão
usando o argumento stringAsFactors = FALSE
dados2 <- read.csv2("dados/crabs.csv", stringsAsFactors = FALSE)
Para conferir a estrutura dos dados importados, usamos a função str() que serve para demonstrar
a estrutura de um objeto, como o nome das colunas e suas classes:
str(dados)
'data.frame': 156 obs. of 7 variables:
$ especie: chr "azul" "azul" "azul" "azul" ...
$ sexo : chr "M" "M" "M" "M" ...
$ FL : num 8.1 8.8 9.2 9.6 10.8 11.6 11.8 12.3 12.6 12.8 ...
$ RW : num 6.7 7.7 7.8 7.9 9 9.1 10.5 11 10 10.9 ...
$ CL : num 16.1 18.1 19 20.1 23 24.5 25.2 26.8 27.7 27.4 ...
$ CW : num 19 20.8 22.4 23.1 26.5 28.4 29.3 31.5 31.7 31.5 ...
$ BD : num 7 7.4 7.7 8.2 9.8 10.4 10.3 11.4 11.4 11 ...
str(dados2)
'data.frame': 156 obs. of 7 variables:
$ especie: chr "azul" "azul" "azul" "azul" ...
$ sexo : chr "M" "M" "M" "M" ...
$ FL : num 8.1 8.8 9.2 9.6 10.8 11.6 11.8 12.3 12.6 12.8 ...
$ RW : num 6.7 7.7 7.8 7.9 9 9.1 10.5 11 10 10.9 ...
$ CL : num 16.1 18.1 19 20.1 23 24.5 25.2 26.8 27.7 27.4 ...
$ CW : num 19 20.8 22.4 23.1 26.5 28.4 29.3 31.5 31.7 31.5 ...
$ BD : num 7 7.4 7.7 8.2 9.8 10.4 10.3 11.4 11.4 11 ...
Podemos também visualizar algumas linhas iniciais e finais do objeto importado através de duas
funções auxiliares:
head(dados)
especie sexo FL RW CL CW BD
1 azul M 8.1 6.7 16.1 19.0 7.0
2 azul M 8.8 7.7 18.1 20.8 7.4
4.1. ENTRADA DE DADOS 59
As funções permitem ainda ler dados diretamente disponíveis na web. Por exemplo, os dados do
exemplo poderiam ser lidos diretamente com o comando a seguir, sem a necessidade de copiar
primeiro os dados para algum local no computador do usuário:
dados <- read.csv2("http://www.leg.ufpr.br/~fernandomayer/data/crabs.csv")
Para maiores informações consulte a documentação desta função com ?read.table(). Embora
read.table() seja provavelmente a função mais utilizada existem outras que podem ser úteis em
determinadas situações:
• read.fwf() é conveniente para ler fixed width formats.
• read.fortran() é semelhante à anterior porém usando o estilo Fortran de especificação das
colunas.
• read.csv(), read.csv2(), read.delim() e read.delim2(): estas funções são praticamente
iguais a read.table() porém com diferentes opções padrão. Em geral (mas não sempre)
dados em formato csv usado no Brasil são lidos diretamente com read.csv2().
Exercícios
1. Baixe os arquivos a seguir e coloque os arquivos em um local apropriado (de preferência no
mesmo diretório de trabalho que voce definiu no início da sessão), faça a importação usando
a função read.table(), e confira a estrutura dos dados com str().
a. prb0519.dat
b. tab0303.dat
c. tab1208.dat
d. ReadMe.txt
e. montgomery_6-26.csv
f. montgomery_14-12.txt
g. montgomery_ex6-2.csv
h. ipea_habitacao.csv
i. stratford.csv
2. Faça a leitura dos dados do exercício anterior, mas agora utilize o endereço web dos arquivos.
23 A 25,4 11
12 B 12,3 09
23 A 19,8 07
podem ser marcados e copiados para área de transferência e lidos diretamente com
dados.clip <- read.table("clipboard", header = TRUE, dec = ",")
str(dados.clip)
'data.frame': 3 obs. of 4 variables:
$ ID : int 23 12 23
$ Grupo: chr "A" "B" "A"
$ Gasto: num 25.4 12.3 19.8
$ Ano : int 11 9 7
nobs
The following object is masked from 'package:utils':
object.size
The following object is masked from 'package:base':
startsWith
## Leitura diretamente do Excel
dados.xls <- read.xls("dados/crabs.xls", sheet = "Plan1",
header = TRUE, dec = ",")
## Estrutura
str(dados.xls)
'data.frame': 156 obs. of 7 variables:
$ especie: chr "azul" "azul" "azul" "azul" ...
$ sexo : chr "M" "M" "M" "M" ...
$ FL : num 8.1 8.8 9.2 9.6 10.8 11.6 11.8 12.3 12.6 12.8 ...
$ RW : num 6.7 7.7 7.8 7.9 9 9.1 10.5 11 10 10.9 ...
$ CL : num 16.1 18.1 19 20.1 23 24.5 25.2 26.8 27.7 27.4 ...
$ CW : num 19 20.8 22.4 23.1 26.5 28.4 29.3 31.5 31.7 31.5 ...
4.1. ENTRADA DE DADOS 61
$ BD : num 7 7.4 7.7 8.2 9.8 10.4 10.3 11.4 11.4 11 ...
Outros pacotes que possuem funções similares são: openxlsx, xlsx, e XLConnect.
Estruturas de dados mais complexas são tipicamente armazenadas nos chamados DBMS (database
management system) ou RDBMS (relational database management system). Alguns exemplos são
Oracle, Microsoft SQL server, MySQL, PostgreSQL, Microsoft Access, dentre outros. O R possui
ferramentas implementadas em pacotes para acesso a estes sistemas gerenciadores.
Para mais detalhes consulte o manual R Data Import/Export e a documentação dos pacotes que
implementam tal funcionalidade. Alguns destes pacotes disponíveis são: RODBC, DBI, RMySQL,
RPostgreSQL, ROracle, RNetCDF, RSQLite, dentre outros.
As bases de dados também possuem páginas de documentação para explicar o que são os dados e
as colunas correspondentes. Para ver o que são os dados do mtcars por exemplo, veja ?mtcars.
62 CAPÍTULO 4. ENTRADA E SAÍDA DE DADOS NO R
O conjunto mtcars é disponibilizado prontamente pois faz parte do pacote datasets, que por
padrão é sempre carregado na inicialização do R. No entanto, existem outros conjuntos de dados,
disponibilizados por outros pacotes, que precisam ser carregados para que os dados possam ser
disponibilizados. Por exemplo, os dados do objeto topo são do pacote MASS. Se tentarmos fazer
data(topo)
Warning in data(topo): data set 'topo' not found
A função data() pode ainda ser usada para listar os conjutos de dados disponíveis,
data()
e também pode ser útil para listar os conjuntos de dados disponíveis para um pacote específico,
por exemplo
data(package = "nlme")
A função write.table() é capaz de criar um arquivo de texto no formato txt ou csv, com as
especificações definidas pelos argumentos.
Por padrão, o arquivo resultante tem colunas separadas por espaço, o separador de decimal é
ponto, e os nomes das linhas são também incluídos (o que geralmente é desnecessário). Para alterar
essa configuração podemos fazer
write.table(iris, file = "dados/iris.csv", row.names = FALSE,
sep = ";", dec = ",")
Os argumentos são
Note que o objeto a ser exportado (nesse caso iris) deve ser em formato tabular, ou seja, uma
matriz ou data frame. Outras classes de objetos podem ser exportadas, mas haverá uma coerção
para data frame, o que pode fazer com que o resultado final não seja o esperado.
Note que row.names = FALSE ainda é necessário para eliminar os nomes das linhas.
O pacote foreign também possui funções para exportar para uma variedade de formatos. Veja a
documentação em help(package = "foreign"). Os pacotes para ler dados diretamente de arquivos
do MS Excel mencionados acima também possuem funções para exportar diretamente para esse
formato.
64 CAPÍTULO 4. ENTRADA E SAÍDA DE DADOS NO R
Exercícios
1. Considere a tabela abaixo com o resultado de uma pesquisa que avaliou o número de fumates
e não fumantes por sexo.
Sexo
Condição
Masculino
Feminino
Fumante
49
54
64
61
37
79
52
64
68
29
Não fumante
27
40
58
39
52
44
41
34
30
44
2. Digite estes dados em uma planilha eletrônica em um formato apropriado para um data
frame do R, e salve em um arquivo csv.
3. Importe esse arquivo para o R com read.table().
4. Crie uma nova coluna no objeto que contém estes dados, sendo a coluna com o número de
pessoas multiplicada por 2.
5. Exporte esse novo objeto usando a função write.table().
6. Tente criar esse mesmo conjunto de dados usando comandos do R (ex.: c(), rep(),
data.frame(), etc.)
Para criar um conjunto de dados no formato textual, usamos a função dput(). Vamos criar um
data frame de exemplo e ver o resultado da chamada dessa função:
da <- data.frame(A = c(1, 2), B = c("a", "b"))
dput(da)
structure(list(A = c(1, 2), B = c("a", "b")), class = "data.frame", row.names = c(NA,
-2L))
Note que o resultado de dput() é no formato do R, e preserva metadados como as classes do objeto
e de cada coluna, e os nomes das linhas e colunas.
Outas classes de objetos são facilmente preservadas quando armazenadas com o resultado de
dput(). Por exemplo, uma matriz:
ma <- matrix(1:9, ncol = 3)
dput(ma)
structure(1:9, dim = c(3L, 3L))
E uma lista:
la <- list(da, ma)
dput(la)
list(structure(list(A = c(1, 2), B = c("a", "b")), class = "data.frame", row.names = c(NA,
-2L)), structure(1:9, dim = c(3L, 3L)))
A saída da função dput() pode ser copiada para um script do R, para garantir que qualquer pessoa
que venha usar o código (incluindo você no futuro), usará os dados no formato correto (esperado).
Isso é muito importante para a pesquisa reproduzível!
A saída de dput() também pode ser salva diretamente em um arquivo de script do R, por exemplo,
dput(da, file = "da.R")
irá criar o arquivo da.R com o resultado da função. Para importar os dados salvos dessa forma,
usamos a função dget(),
da2 <- dget(file = "da.R")
da2
A B
1 1 a
2 2 b
Múltiplos objetos podem ser armazenados em formato textual usando a função dump().
dump(c("da", "ma", "la"), file = "dados.R")
Note que os objetos são passados como um vetor de caracteres, e um arquivo chamado dados.R é
criado com todos os objetos no formato textual. Para importar estes objetos para uma sessão do R,
usamos a função source(),
source("dados.R")
que já cria os objetos na sua área de trabalho com os mesmos nomes e atributos como foram
armazenados.
Para salvar um objeto contendo dados no R, usamos a função save(). Por exemplo, para armazenar
o objeto da criado acima, fazemos
save(da, file = "dados.rda")
Esse comando irá criar o arquivo (binário) dados.rda. Note que a extensão .rda é comumente
utilizada para dados binários do R, mas não é única.
Paa salvar mais de um objeto no mesmo arquivo, basta passar os nomes na mesma função
save(da, ma, file = "dados.rda")
A função save.image() pode ser utilizada se a intenção é salvar todos os objetos criados na sua
área de trabalho (isso inclui qualquer objeto, não só os conjuntos de dados). Nesse caso, podemos
fazer
save.image(file = "workspace.RData")
Note que quando foi utilizada a função save(), a extensão do arquivo foi rda, e com save.image()
foi RData. Isso é uma convenção comum de arquivos binários do R, mas não é obrigatório. Qualquer
uma das extensões funciona em ambas as funções.
Para carregar os conjuntos de dados (ou de forma mais geral, os objetos) armazenados em formato
binário, usamos a função load()
load("dados.rda")
load("workspace.RData")
O resultado é a chamada do comando print() para cada valor que o índice i recebe (nesse caso i
recebe os valores de 1 a 10).
A sintaxe será sempre nesse formato:
for(<índice> in <valores>){
<comandos>
}
67
68 CAPÍTULO 5. PROGRAMANDO COM DADOS
x <- 100:200
for(j in 1:10){
print(x[j])
}
[1] 100
[1] 101
[1] 102
[1] 103
[1] 104
[1] 105
[1] 106
[1] 107
[1] 108
[1] 109
Veja que o índice não precisa ser i, na verdade pode ser qualquer letra ou palavra. Nesse caso,
utilizamos os valores como índice para selecionar elementos de x nas posições específicadas.
Um outro exemplo seria se quisessemos imprimir o quadrado de alguns números (não necessaria-
mente em sequência):
for(i in c(2, 9, 4, 6)){
print(iˆ2)
}
[1] 4
[1] 81
[1] 16
[1] 36
Para calcular as médias das 3 provas, precisamos inicialmente de um vetor para armazenar os
resultados. Esse vetor pode ser um novo objeto ou uma nova coluna no dataframe
## Aqui vamos criar uma nova coluna no dataframe, contendo apenas o
## valor 0
5.1. ESTRUTURA DE REPETIÇÃO FOR() 69
## Confere os resultados
head(notas)
nome prova1 prova2 prova3 media
1 Aluno_1 8 4 1 4.333333
2 Aluno_2 2 7 6 5.000000
3 Aluno_3 9 2 4 5.000000
4 Aluno_4 1 10 9 6.666667
5 Aluno_5 7 6 8 7.000000
6 Aluno_6 10 0 3 4.333333
Agora podemos melhorar o código, tornando-o mais genérico. Dessa forma fica mais fácil fazer
alterações e procurar erros. Uma forma de melhorar o código acima é generalizando alguns passos.
## Armazenamos o número de linhas no dataframe
nlinhas <- nrow(notas)
## Identificamos as colunas de interesse no cálculo da média, e
## armazenamos em um objeto separado
provas <- c("prova1", "prova2", "prova3")
## Sabendo o número de provas, fica mais fácil dividir pelo total no
## cálculo da média
nprovas <- length(provas)
## Cria uma nova coluna apenas para comparar o cálculo com o anterior
notas$media2 <- 0
## A estrutura de repetição fica
for(i in 1:nlinhas){
notas$media2[i] <- sum(notas[i, provas])/nprovas
}
## Confere
head(notas)
nome prova1 prova2 prova3 media media2
1 Aluno_1 8 4 1 4.333333 4.333333
2 Aluno_2 2 7 6 5.000000 5.000000
3 Aluno_3 9 2 4 5.000000 5.000000
4 Aluno_4 1 10 9 6.666667 6.666667
5 Aluno_5 7 6 8 7.000000 7.000000
6 Aluno_6 10 0 3 4.333333 4.333333
identical(notas$media, notas$media2)
[1] TRUE
for(i in 1:nlinhas){
notas$media3[i] <- mean(as.numeric(notas[i, provas]))
}
## Confere
head(notas)
nome prova1 prova2 prova3 media media2 media3
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333
No caso acima vimos que não era necessário calcular a média através de soma/total porque existe
uma função pronta no R para fazer esse cálculo. Mas, e se quisessemos, por exemplo, calcular a
Coeficiente de Variação (CV) entre as notas das três provas de cada aluno? Uma busca por
help.search("coefficient of variation")
não retorna nenhuma função (dos pacotes básicos) para fazer esse cálculo. O motivo é simples:
como é uma conta simples de fazer não há necessidade de se criar uma função extra dentro dos
pacotes. No entanto, nós podemos criar uma função que calcule o CV, e usá-la para o nosso
propósito
cv <- function(x){
desv.pad <- sd(x)
med <- mean(x)
cv <- desv.pad/med
return(cv)
}
NOTA: na função criada acima o único argumento que usamos foi x, que neste caso deve ser um
vetor de números para o cálculo do CV. Os argumentos colocados dentro de function() devem
ser apropriados para o propósito de cada função.
Antes de aplicar a função dentro de um for() devemos testá-la para ver se ela está funcionando
de maneira correta. Por exemplo, o CV para as notas do primeiro aluno pode ser calculado
“manualmente” por
sd(as.numeric(notas[1, provas]))/mean(as.numeric(notas[1, provas]))
[1] 0.8104349
o que mostra que a função está funcionando corretamente, e podemos aplicá-la em todas as linhas
usando a repetição
5.1. ESTRUTURA DE REPETIÇÃO FOR() 71
## Confere
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157
Podemos agora querer calcular as médias ponderadas para as provas. Por exemplo:
• Prova 1: peso 3
• Prova 2: peso 3
• Prova 3: peso 4
Usando a fórmula:
n
1
x̄ =
N ∑ x i · wi
i =1
onde wi são os pesos, e N = ∑in=1 wi é a soma dos pesos. Como já vimos, criar uma função é
uma forma mais prática (e elegante) de executar determinada tarefa, vamos criar uma função que
calcule as médias ponderadas.
med.pond <- function(notas, pesos){
## Multiplica o valor de cada prova pelo seu peso
pond <- notas * pesos
## Calcula o valor total dos pesos
peso.total <- sum(pesos)
## Calcula a soma da ponderação
sum.pond <- sum(pond)
## Finalmente calcula a média ponderada
saida <- sum.pond/peso.total
return(saida)
}
Antes de aplicar a função para o caso geral, sempre é importante testar e conferir o resultado em
um caso menor. Podemos verificar o resultado da média ponderada para o primeiro aluno
sum(notas[1, provas] * c(3, 3, 4))/10
[1] 4
Como o resultado é o mesmo podemos aplicar a função para todas as linhas através do for()
## Cria uma nova coluna para a média ponderada
notas$MP <- 0
72 CAPÍTULO 5. PROGRAMANDO COM DADOS
## Confere
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV MP
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349 4.0
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503 5.1
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103 4.9
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324 6.9
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571 7.1
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157 4.2
NOTA: uma função para calcular a média ponderada já existe implementada no R. Veja
?weighted.mean() e confira os resultados obtidos aqui.
Repare na construção da função acima: agora usamos dois argumentos, notas e pesos, pois preci-
samos dos dois vetores para calcular a média ponderada. Repare também que ambos argumentos
não possuem um valor padrão. Poderíamos, por exemplo, assumir valores padrão para os pesos, e
deixar para que o usuário mude apenas se achar necessário.
## Atribuindo pesos iguais para as provas como padrão
med.pond <- function(notas, pesos = rep(1, length(notas))){
## Multiplica o valor de cada prova pelo seu peso
pond <- notas * pesos
## Calcula o valor total dos pesos
peso.total <- sum(pesos)
## Calcula a soma da ponderação
sum.pond <- sum(pond)
## Finalmente calcula a média ponderada
saida <- sum.pond/peso.total
return(saida)
}
Repare que neste caso, como os pesos são iguais, a chamada da função sem alterar o argumento
pesos gera o mesmo resultado do cálculo da média comum.
## Cria uma nova coluna para a média ponderada para comparação
notas$MP2 <- 0
## A estrutura de repetição fica
for(i in 1:nlinhas){
notas$MP2[i] <- med.pond(notas = notas[i, provas])
}
## Confere
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV MP
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349 4.0
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503 5.1
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103 4.9
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324 6.9
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571 7.1
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157 4.2
MP2
1 4.333333
5.2. ESTRUTURA DE SELEÇÃO IF() 73
2 5.000000
3 5.000000
4 6.666667
5 7.000000
6 4.333333
Exercícios
1. Escreva um loop for que percorre os números de 1 a 700 e imprime o cubo de cada número.
2. Escreva um loop for que percorre os nomes das colunas do conjunto de dados iris e imprime
cada um junto com o número de caracteres na coluna nomes entre parênteses. Example de
output Sepal.Length (12). Dica: Use as seguintes funções print(), paste0() e nchar().
3. Escreva um loop while que imprime o erro padrão de amostras da distribuição normal
padrão (use rnorm()) e para (break) se o erro padrão obtido for maior que 1.
4. Usando o comando next adapte o loop do exercício (3) para que números menores que 0.75
não sejam mostrados.
5. Use um loop for para simular o lançamento de uma moeda (1 - cara, 0 - coroa) e armazene os
resultados em um vetor pré-especificado.
Mas também podemos considerar o que aconteceria caso contrário. Por exemplo, se o valor de xfor
maior do que 105, então imprima outro texto.
x <- 100:200
for(j in 1:10){
if(x[j] <= 105){
print("Menor ou igual a 105")
} else{
print("Maior do que 105")
}
}
[1] "Menor ou igual a 105"
[1] "Menor ou igual a 105"
[1] "Menor ou igual a 105"
[1] "Menor ou igual a 105"
[1] "Menor ou igual a 105"
74 CAPÍTULO 5. PROGRAMANDO COM DADOS
## Confere
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV MP
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349 4.0
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503 5.1
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103 4.9
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324 6.9
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571 7.1
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157 4.2
MP2 situacao
1 4.333333 reprovado
2 5.000000 reprovado
3 5.000000 reprovado
4 6.666667 reprovado
5 7.000000 aprovado
6 4.333333 reprovado
R. Por exemplo, podemos criar um vetor muito grande de números e querer calcular o quadrado
de cada número. Se pensássemos em usar uma estrutura de repetição, o cálculo seria o seguinte:
## Vetor com uma sequência de 1 a 1.000.000
x <- 1:1000000
## Calcula o quadrado de cada número da sequência em x usando for()
y1 <- numeric(length(x)) # vetor de mesmo comprimento de x que vai
# receber os resultados
for(i in 1:length(x)){
y1[i] <- x[i]ˆ2
}
Mas, da forma vetorial e usando a regra da reciclagem, a mesma operação pode ser feita apenas
com
## Calcula o quadrado de cada número da sequência em x usando a regra da
## reciclagem
y2 <- xˆ2
## Confere os resultados
identical(y1, y2)
[1] TRUE
Note que os resultados são exatamente iguais, mas então porque se prefere o formato vetorial?
Primeiro porque é muito mais simples de escrever, e segundo (e principalmente) porque a forma
vetorizada é muito mais eficiente computacionalmente. A eficiência computacional pode ser
medida de várias formas (alocação de memória, tempo de execução, etc), mas apenas para compa-
ração, vamos medir o tempo de execução destas mesmas operações usando o for() e usando a
regra da reciclagem.
## Tempo de execução usando for()
y1 <- numeric(length(x))
st1 <- system.time(
for(i in 1:length(x)){
y1[i] <- x[i]ˆ2
}
)
st1
user system elapsed
0.076 0.000 0.076
Olhando o resultado de elapsed, que é o tempo total de execução de uma função medido
por system.time(), notamos que usando a regra da reciclagem, o cálculo é aproximadamente
0.076/0.002 = 38 vezes mais rápido. Claramente esse é só um exemplo de um cálculo muito
simples. Mas em situações mais complexas, a diferença entre o tempo de execução das duas formas
pode ser muito maior.
2. Crie um objeto com tamanho suficiente para armazenar todos os resultados do loop antes de
executá-lo.
Essa simples diferença gera um aumento de tempo de execução da segunda forma em aproxima-
damente 0.304/0.083 = 3.66 vezes. Isso acontece porque, da segunda forma, o vetor out precisa ter
seu tamanho aumentado com um elemento a cada iteração. Para fazer isso, o R precisa encontrar
um espaço na memória que possa armazenar o objeto maior. É necessário então copiar o vetor de
saída e apagar sua versão anterior antes de seguir para o próximo loop. Ao final, foi necessário
escrever um milhão de vezes na memória do computador.
Já no primeiro caso, o tamanho do vetor de armazenamento nunca muda, e a memória para esse
vetor já foi alocada previamente, de uma única vez.
5.3. O MODO R: VETORIZAÇÃO 77
Voltando ao exemplo das notas, por exemplo, o cálculo da média simples poderia ser feito direta-
mente com a função apply()
notas$media.apply <- apply(X = notas[, provas], MARGIN = 1, FUN = mean)
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV MP
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349 4.0
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503 5.1
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103 4.9
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324 6.9
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571 7.1
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157 4.2
MP2 situacao media.apply
1 4.333333 reprovado 4.333333
2 5.000000 reprovado 5.000000
3 5.000000 reprovado 5.000000
4 6.666667 reprovado 6.666667
5 7.000000 aprovado 7.000000
6 4.333333 reprovado 4.333333
As médias ponderadas poderiam ser calculadas da mesma forma, e usando a função que criamos
anteriormente
78 CAPÍTULO 5. PROGRAMANDO COM DADOS
Mas note que como temos o argumento pesos especificado com um padrão, devemos alterar na
própria função apply()
notas$MP.apply <- apply(X = notas[, provas], MARGIN = 1,
FUN = med.pond, pesos = c(3, 3, 4))
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV MP
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349 4.0
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503 5.1
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103 4.9
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324 6.9
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571 7.1
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157 4.2
MP2 situacao media.apply MP.apply
1 4.333333 reprovado 4.333333 4.0
2 5.000000 reprovado 5.000000 5.1
3 5.000000 reprovado 5.000000 4.9
4 6.666667 reprovado 6.666667 6.9
5 7.000000 aprovado 7.000000 7.1
6 4.333333 reprovado 4.333333 4.2
NOTA: veja que isso é possível devido à presença do argumento ... na função apply(), que
permite passar argumentos de outras funções dentro dela.
Finalmente, a estrutura de repetição if() também possui uma forma vetorizada através da função
ifelse(). Essa função funciona da seguinte forma:
ifelse(<condição>, <valor se verdadeiro>, <valor se falso>)
Dessa forma, a atribuição da situação dos alunos poderia ser feita da seguinte forma:
notas$situacao2 <- ifelse(notas$MP >= 7, "aprovado", "reprovado")
head(notas)
nome prova1 prova2 prova3 media media2 media3 CV MP
1 Aluno_1 8 4 1 4.333333 4.333333 4.333333 0.8104349 4.0
2 Aluno_2 2 7 6 5.000000 5.000000 5.000000 0.5291503 5.1
3 Aluno_3 9 2 4 5.000000 5.000000 5.000000 0.7211103 4.9
4 Aluno_4 1 10 9 6.666667 6.666667 6.666667 0.7399324 6.9
5 Aluno_5 7 6 8 7.000000 7.000000 7.000000 0.1428571 7.1
6 Aluno_6 10 0 3 4.333333 4.333333 4.333333 1.1842157 4.2
MP2 situacao media.apply MP.apply MP2.apply CV.apply situacao2
1 4.333333 reprovado 4.333333 4.0 4.0 0.8104349 reprovado
2 5.000000 reprovado 5.000000 5.1 5.1 0.5291503 reprovado
3 5.000000 reprovado 5.000000 4.9 4.9 0.7211103 reprovado
4 6.666667 reprovado 6.666667 6.9 6.9 0.7399324 reprovado
5 7.000000 aprovado 7.000000 7.1 7.1 0.1428571 aprovado
6 4.333333 reprovado 4.333333 4.2 4.2 1.1842157 reprovado
Exercícios
1. Faça uma função usando loop for que recebe duas matrizes de mesma dimensão e retorna a
soma das matrizes. Note que é necessário verificar se as matrizes fornecidas pelo usuário
podem ser somadas, caso contrário retorne uma mensagem de erro dizendo que as matrizes
não podem ser somadas.
2. Faça uma função usando loop for para multiplicar duas matrizes compatíveis. Note que é
necessário verificar se as matrizes fornecidas pelo usuário podem ser multiplicadas, caso con-
trário retorne uma mensagem de erro dizendo que as matrizes não podem ser multiplicadas.
3. Faça uma função para resolver sistemas lineares 2 x 2 usando o método de decomposição de
Gauss. Veja esta página se você não conhece o método https://matrixcalc.org/pt/slu.html.
80 CAPÍTULO 5. PROGRAMANDO COM DADOS
4. Faça uma função que encontra o máximo de uma função fornecida pelo usuário em um
intervalo e precisão pré-determinado pelo usuário.
5. Faça uma função que resolve uma equação não-linear de um único parâmetro em um
intervalo e precisão pré-determinado pelo usuário.
O repeat é ainda mais básico, e irá executar comandos até que você explicitamente pare a execução
com o comando break.
## Mesmo exemplo
n <- 0
soma <- 0
repeat{
n <- n + 1
soma <- soma + n
if(soma > 1000) break
}
soma
[1] 1035
Exercícios
1. Crie uma função que retorna o absoluto de um vetor de inteiros.
2. Crie uma função em R que retorna o maior valor em um vetor de elementos númericos.
3. Crie uma função que retorna o número de valores maiores que a média de um vetor. Você
pode usar a função mean().
4. Crie uma função que dado um vetor de tamanho 3 retorna os seus valores em ordem crescente
e decrescente.
5. Crie uma função que calcula o fatorial de um número.
Parte II
Estatística
81
Capítulo 6
Nesta sessão vamos ver alguns (mas não todos!) comandos do R para fazer uma análise descritiva
de um conjunto de dados.
Uma boa forma de iniciar uma análise descritiva adequada é verificar os tipos de variáveis
disponíveis. Variáveis podem ser classificadas da seguinte forma:
• Qualitativas
– Nominais
– Ordinais
• Quantitativas
– Discretas
– Contínuas
e podem ser resumidas por tabelas, gráficos e/ou medidas de tendência central e dispersão.
O livro “Estatística Básica” dos Profs Wilton Bussab e Pedro Morettin (bussab+morettin:2017?)
traz no segundo capítulo um conjunto de dados hipotético de atributos de 36 funcionários da
companhia “Milsa”. Os dados estão reproduzidos na tabela a seguir. Consulte o livro para mais
detalhes sobre este dados.
83
84 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
Estes são dados no “estilo planilha”, com variáveis de diferentes tipos: categóricas e numéricas
(qualitativas e quantitativas). Portanto o formato ideal de armazenamento destes dados no R é o
data.frame.
E para conferir a estrutura dos dados podemos usar algumas funções como:
6.1. O CONJUNTO DE DADOS MILSA 85
str(milsa)
'data.frame': 36 obs. of 8 variables:
$ Funcionario: int 1 2 3 4 5 6 7 8 9 10 ...
$ Est.civil : chr "solteiro" "casado" "casado" "solteiro" ...
$ Inst : chr "1o Grau" "1o Grau" "1o Grau" "2o Grau" ...
$ Filhos : int NA 1 2 NA NA 0 NA NA 1 NA ...
$ Salario : num 4 4.56 5.25 5.73 6.26 6.66 6.86 7.39 7.59 7.44 ...
$ Anos : int 26 32 36 20 40 28 41 43 34 23 ...
$ Meses : int 3 10 5 10 7 0 0 4 10 6 ...
$ Regiao : chr "interior" "capital" "capital" "outro" ...
head(milsa)
Funcionario Est.civil Inst Filhos Salario Anos Meses Regiao
1 1 solteiro 1o Grau NA 4.00 26 3 interior
2 2 casado 1o Grau 1 4.56 32 10 capital
3 3 casado 1o Grau 2 5.25 36 5 capital
4 4 solteiro 2o Grau NA 5.73 20 10 outro
5 5 solteiro 1o Grau NA 6.26 40 7 outro
6 6 casado 1o Grau 0 6.66 28 0 interior
tail(milsa)
Funcionario Est.civil Inst Filhos Salario Anos Meses Regiao
31 31 solteiro Superior NA 16.22 31 5 outro
32 32 casado 2o Grau 1 16.61 36 4 interior
33 33 casado Superior 3 17.26 43 7 capital
34 34 solteiro Superior NA 18.75 33 7 capital
35 35 casado 2o Grau 2 19.40 48 11 capital
36 36 casado Superior 3 23.30 42 2 interior
Variável Classificação
Funcionario Quantitativa discreta
Est.civil Qualitativa nominal
Inst Qualitativa ordinal
Filhos Quantitativa discreta
Salario Quantitativa contínua
Anos Quantitativa contínua
Meses Quantitativa contínua
Regiao Qualitativa nominal
Como a variável Inst é qualitativa ordinal, podemos indicar para o R que ela deve ser tratada
como ordinal. Se observarmos os níveis desse fator:
levels(milsa$Inst)
NULL
já notamos que a ordenação está correta (da esquerda para a direita), pois sabemos que a classifica-
ção interna dos níveis é por ordem alfabética, e nesse caso, por coincidência, a ordem já está na
sequência correta. Mesmo assim, podemos indicar que este fator é ordinal, usando o argumento
ordered da função factor()
milsa$Inst <- factor(milsa$Inst, ordered = TRUE)
Caso as classes em ordem alfabética não estivessem na ordem desejada feriamos a definição mais
detalhada com:]
86 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
O argumento levels deve conter os valores que a variável assume na ordem desejada e labels são
rótulos que serão usados para se referir a estes valores e que não necessáriamente precisam ter o
mesmo nome que levels , mas precisam estar na ordem correta.
Note agora a modificação na classe dessa coluna, e a representação dos níveis:
class(milsa$Inst)
[1] "ordered" "factor"
milsa$Inst
[1] 1o Grau 1o Grau 1o Grau 2o Grau 1o Grau 1o Grau 1o Grau 1o Grau
[9] 2o Grau 2o Grau 2o Grau 1o Grau 2o Grau 1o Grau 2o Grau 2o Grau
[17] 2o Grau 1o Grau Superior 2o Grau 2o Grau 2o Grau 1o Grau Superior
[25] 2o Grau 2o Grau 1o Grau 2o Grau 2o Grau 2o Grau Superior 2o Grau
[33] Superior Superior 2o Grau Superior
Levels: 1o Grau < 2o Grau < Superior
A coluna continua sendo um factor, mas agora também é ordered (sim, um objeto pode ter mais
de uma classe, se elas foram compatíveis e/ou complementares). Os níveis agora são representados
por
1o Grau < 2o Grau < Superior
para indicar explicitamente que existe uma ordem nos níveis desse fator.
Podemos ainda definir uma nova variável, chamada Idade, a partir das variáveis Anos e Meses:
milsa$Idade <- milsa$Anos + milsa$Meses/12
Aproveitamos este comando para ilustrar uma opção interessante: usar with para referenciar
diretamente a variávelo que vai ser tratado pelo comando. Desta forma elimina-se a necessidade
de digitar milsa$ mais de uma vez.
milsa$Idade <- with(milsa, Anos + Meses/12)
Os dois comandos acima (de modificação da classe de uma variável, e a criação de uma nova
variável) poderiam ser facilmente executadas de uma única vez através do comando transform()
milsa <- transform(milsa,
Inst = factor(Inst, ordered = TRUE),
Idade = Anos + Meses/12)
Agora que os dados estão prontos podemos começar a análise descritiva. A seguir mostramos
como fazer análises descritivas uni e bivariadas. Inspecione os comandos mostrados a seguir
e os resultados por eles produzidos. Sugerimos ainda que o leitor use o R para reproduzir os
resultados mostrados no texto dos capítulos 1 a 3 do livro de Bussab & Morettin, relacionados com
este exemplo. Veja aqui os scripts do livro.
A seguir vamos mostrar como obter tabelas, gráficos e medidas com o R. Para isto vamos selecionar
uma variável de cada tipo para que o leitor possa, por analogia, obter resultados para as demais.
A variável Est.civil é uma qualitativa nominal. Desta forma podemos obter: (i) uma tabela de
frequências (absolutas e/ou relativas), (ii) um gráfico de setores, (iii) a “moda”, i.e. o valor que
ocorre com maior frequência.
Já vimos, através do resultado da função str() acima, que esta variável é um fator. A seguir
obtemos frequências absolutas e relativas (note duas formas diferentes de obter as frequências
relativas).
## Frequência absoluta
civil.tb <- with(milsa, table(Est.civil))
civil.tb
Est.civil
casado solteiro
20 16
## Frequência relativa, calculando manualmente
civil.tb/sum(civil.tb)
Est.civil
casado solteiro
0.5555556 0.4444444
## Frequência relativa, com a função prop.table()
prop.table(civil.tb)
Est.civil
casado solteiro
0.5555556 0.4444444
Os gráficos de barras e de setores são adequados para representar esta variável. Os comandos
barplot() e pie() usam o resultado da função table() para gerar os gráficos:
par(mfrow = c(1,2), mar=c(3,3,0.5,0.5))
barplot(civil.tb)
pie(civil.tb)
par(mfrow = c(1,1))
88 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
20
casado
15
10
5
solteiro
0
casado solteiro
A moda de qualquer variável aleatória é definida como o valor mais frequente encontrado na
amostra. No R não há uma função pronta para “calcular” a moda, pois ela pode ser obtida
facilmente através do uso de funções básicas. Uma opção seria usar os comandos abaixo:
names(civil.tb)[which.max(civil.tb)]
[1] "casado"
O gráfico de setores não é adequado para este tipo de variável por não expressar a ordem dos
possíveis valores. Usamos então apenas um gráfico de barras conforme mostrado abaixo
barplot(inst.tb)
6.2. ANÁLISE UNIVARIADA 89
15
10
5
0
Em alguns casos podemos querer mostrar o gráfico de barras com as barras classificadas da menor
para a maior, ou vice-versa, independente da ordem dos níveis. Para isso podemos usar a função
sort() para ordenar os valores da tabela e fazer o gráfico
par(mfrow = c(1,2))
## Menor para maior
barplot(sort(inst.tb))
## Maior para menor
barplot(sort(inst.tb, decreasing = TRUE))
par(mfrow = c(1,1))
90 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
15
15
10
10
5
5
0
Para uma variável ordinal, além da moda podemos também calcular outras medidas, tais como
a mediana conforme exemplificado a seguir. Note que o comando median() não funciona com
variáveis não numéricas, e por isso usamos o comando seguinte.
## Moda
names(inst.tb)[which.max(inst.tb)]
[1] "2o Grau"
## Mediana
with(milsa, median(Inst)) # só funciona para variáveis numéricas
Error in median.default(Inst): need numeric data
with(milsa, median(as.numeric(Inst))) # traz a mediana da codificação do nível
[1] 2
with(milsa, levels(Inst)[median(as.numeric(Inst))]) # valor correto
[1] "2o Grau"
filhos.tbr
Filhos
0 1 2 3 5
0.20 0.25 0.35 0.15 0.05
## Frequência acumulada
filhos.tba <- cumsum(filhos.tbr)
filhos.tba
0 1 2 3 5
0.20 0.45 0.80 0.95 1.00
O gráfico adequado para frequências absolutas de uma variável discreta é parecido com um gráfico
de barras, mas nesse caso, as frequências são indicadas por linhas. Usando a função plot() em um
objeto resultado da função table(), o gráfico adequado já é selecionado:
plot(filhos.tb)
7
6
5
filhos.tb
4
3
2
1
0
0 1 2 3 5
Filhos
1.0
0.30
0.8
0.20
filhos.tba
filhos.tbr
0.6
0.10
0.4
0.00
0 1 2 3 5 0.2 1 2 3 4 5
Filhos Index
Sendo a variável numérica há uma maior diversidade de medidas estatísticas que podem ser
calculadas.
A seguir mostramos como obter algumas medidas de posição: moda, mediana, média e média
aparada. Note que o argumento na.rm = TRUE é necessário porque não há informação sobre
número de filhos para alguns indivíduos (NA). Para calcular a média aparada, usamos o argumento
trim = 0.1 que indica que a média deve ser calculada excluindo-se 10% dos menores e 10% dos
maiores valores do vetor de dados. Ao final mostramos como obter os quartis, incluido o mínimo
e o máximo.
## Moda
names(filhos.tb)[which.max(filhos.tb)]
[1] "2"
## Mediana
median(milsa$Filhos, na.rm = TRUE)
[1] 2
## Média
with(milsa, mean(Filhos, na.rm = TRUE))
[1] 1.65
## Média aparada
with(milsa, mean(Filhos, trim = 0.1, na.rm = TRUE))
[1] 1.5625
## Quartis
with(milsa, quantile(Filhos, na.rm = TRUE))
0% 25% 50% 75% 100%
0 1 2 2 5
Passando agora para medidas de dispersão, vejamos como obter o máximo e mínimo, e com isso
a amplitude, além da variância, desvio padrão, e coeficiente de variação. Também obtemos os
quartis para calcular a amplitude interquartílica.
6.2. ANÁLISE UNIVARIADA 93
## Máximo e mínimo
with(milsa, max(Filhos, na.rm = TRUE))
[1] 5
with(milsa, min(Filhos, na.rm = TRUE))
[1] 0
## As duas informações juntas
with(milsa, range(Filhos, na.rm = TRUE))
[1] 0 5
## Amplitude é a diferença entre máximo e mínimo
with(milsa, diff(range(Filhos, na.rm = TRUE)))
[1] 5
## Variância
with(milsa, var(Filhos, na.rm = TRUE))
[1] 1.607895
## Desvio-padrão
with(milsa, sd(Filhos, na.rm = TRUE))
[1] 1.268028
## Coeficiente de variação
with(milsa, 100*sd(Filhos, na.rm = TRUE)/mean(Filhos, na.rm = TRUE))
[1] 76.85018
## Quartis
(filhos.qt <- with(milsa, quantile(Filhos, na.rm = TRUE)))
0% 25% 50% 75% 100%
0 1 2 2 5
## Amplitude interquartílica
filhos.qt[4] - filhos.qt[2]
75%
1
Finalmente, podemos usar a função genérica summary() para resumir os dados de uma só vez
with(milsa, summary(Filhos))
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
0.00 1.00 2.00 1.65 2.00 5.00 16
Note que uma das classes é NA. Isso ocorre pela definição das classes, que por padrão é no formato
(a,b], ou seja, o intervalo é aberto em a (não inclui a) e fechado em b (inclui b). Podemos alterar
esse padrão usando o argumento include.lowest = TRUE,
with(milsa, cut(Salario, breaks = seq(4, 23.3, length.out = 8),
include.lowest = TRUE))
[1] [4,6.76] [4,6.76] [4,6.76] [4,6.76] [4,6.76] [4,6.76]
[7] (6.76,9.51] (6.76,9.51] (6.76,9.51] (6.76,9.51] (6.76,9.51] (6.76,9.51]
[13] (6.76,9.51] (6.76,9.51] (6.76,9.51] (6.76,9.51] (9.51,12.3] (9.51,12.3]
[19] (9.51,12.3] (9.51,12.3] (9.51,12.3] (9.51,12.3] (9.51,12.3] (12.3,15]
[25] (12.3,15] (12.3,15] (12.3,15] (12.3,15] (12.3,15] (15,17.8]
[31] (15,17.8] (15,17.8] (15,17.8] (17.8,20.5] (17.8,20.5] (20.5,23.3]
7 Levels: [4,6.76] (6.76,9.51] (9.51,12.3] (12.3,15] (15,17.8] ... (20.5,23.3]
E note que agora a primeira classe fica [a,b], ou seja, fechada (incluindo) os dois lados. Para que o
intervalo seja fechado à esquerda, usamos o argumento right = FALSE. As combinações possíveis
para esses dois argumentos, e as classes resultantes são apresentadas na tabela abaixo:
Argumentos Resultado
include.lowest = T, right = T [a,b], ..., (y,z]
include.lowest = F, right = T (a,b], ..., (y,z]
include.lowest = F, right = F [a,b), ..., [y,z)
include.lowest = T, right = F [a,b), ..., [y,z]
Outra opção para “acomodar” todos os extremos dentro das classes, seria naturalmente atribuir
valores um pouco menores que o mínimo, e um pouco maiores que o máximo. Abaixo, usamos
essa abordagem e fazemos uma tabela com as frequências absolutas e relativas.
salario.cut <- with(milsa,
cut(Salario, breaks = seq(3.5, 23.5, length.out = 8)))
salario.cut
[1] (3.5,6.36] (3.5,6.36] (3.5,6.36] (3.5,6.36] (3.5,6.36] (6.36,9.21]
[7] (6.36,9.21] (6.36,9.21] (6.36,9.21] (6.36,9.21] (6.36,9.21] (6.36,9.21]
[13] (6.36,9.21] (6.36,9.21] (6.36,9.21] (9.21,12.1] (9.21,12.1] (9.21,12.1]
[19] (9.21,12.1] (9.21,12.1] (9.21,12.1] (9.21,12.1] (9.21,12.1] (12.1,14.9]
[25] (12.1,14.9] (12.1,14.9] (12.1,14.9] (12.1,14.9] (12.1,14.9] (14.9,17.8]
[31] (14.9,17.8] (14.9,17.8] (14.9,17.8] (17.8,20.6] (17.8,20.6] (20.6,23.5]
7 Levels: (3.5,6.36] (6.36,9.21] (9.21,12.1] (12.1,14.9] ... (20.6,23.5]
## Tabela com as frequencias absolutas por classe
salario.tb <- table(salario.cut)
salario.tb
salario.cut
(3.5,6.36] (6.36,9.21] (9.21,12.1] (12.1,14.9] (14.9,17.8] (17.8,20.6]
5 10 8 6 4 2
(20.6,23.5]
1
## Tabela com as frequências relativas
prop.table(salario.tb)
salario.cut
6.2. ANÁLISE UNIVARIADA 95
Na sequência vamos mostrar dois possíveis gráficos para variáveis contínuas: o histograma e o
box-plot.
Histogram of Salario
8
6
Frequency
4
2
0
5 10 15 20
Salario
A função hist() possui vários argumentos para alterar o comportamento da saída do gráfico. Por
exemplo, com labels = TRUE as frequências são mostradas acima de cada barra. Com freq =
FALSE, o gráfico é feito com as frequências relativas. O título no alto do gráfico pode ser redefinido
ou excluído usando o argumento main. A divisão das classes segue os mesmo padrões de função
cut().
with(milsa, hist(Salario, freq = FALSE, labels = TRUE, main=""))
96 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
0.111
0.083
0.08
0.069
Density
0.056 0.056
0.042 0.042
0.04
0.028
0.014
0
0.00
5 10 15 20
Salario
Por padrão, a função hist() calcula automaticamente o número de classes e os valores limites de
cada classe. No entanto, isto pode ser alterado com o argumento breaks, que pode receber um
vetor definindo os limites das classes, uma função para definir as quebras, um nome de critério
(por exemplo, "Sturges"), ou um único escalar definido o número de classes. As últimas três
opções são apenas sugestões utilizadas pela função. O argumento nclass também funciona dessa
forma, recebendo apenas um valor com o número de classes (como sugestão).
with(milsa, hist(Salario, nclass = 15))
6.2. ANÁLISE UNIVARIADA 97
Histogram of Salario
4
3
Frequency
2
1
0
5 10 15 20
Salario
Assim como na função cut(), os argumentos include.lowest e right são utilizados para controlar
a borda das classes.
Uma característica importante da função hist() é que ela retorna não apenas o gráfico, mas também
uma lista com as informações utilizadas para construir o gráfico. Associando um histograma a um
objeto, podemos ver o seu conteúdo:
salario.hist <- with(milsa, hist(Salario))
98 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
Histogram of Salario
8
6
Frequency
4
2
0
5 10 15 20
Salario
salario.hist
$breaks
[1] 4 6 8 10 12 14 16 18 20 22 24
$counts
[1] 4 6 8 5 4 3 3 2 0 1
$density
[1] 0.05555556 0.08333333 0.11111111 0.06944444 0.05555556 0.04166667
[7] 0.04166667 0.02777778 0.00000000 0.01388889
$mids
[1] 5 7 9 11 13 15 17 19 21 23
$xname
[1] "Salario"
$equidist
[1] TRUE
attr(,"class")
[1] "histogram"
Estas informações podem então ser utilizadas para outros propósitos dentro do R.
Os boxplots são úteis para revelar o centro, a dispersão e a distribuição dos dados, além de outliers.
São construídos da seguinte forma:
• A linha central mais escura representa a mediana. Os extremos da caixa são o 1o (q1) e o 3o
(q3) quartis.
6.2. ANÁLISE UNIVARIADA 99
q1 − 1, 5 · IQR e q3 + 1, 5 · IQR
onde IQR é o intervalo inter-quartil. As linhas vão até os valores máximo e mínimo que
ainda se encontram dentro deste intervalo.
with(milsa, boxplot(Salario))
20
15
10
5
Existem também vários argumentos que permitem variações do boxplot, tais como caixas com
tamanho proporcional aos tamanhos dos grupos (varwidth = TRUE), e caixas “acinturadas” (notched
boxplot) (notch = TRUE).
with(milsa, boxplot(Salario, varwidth = TRUE, notch = TRUE))
100 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
20
15
10
5
Ambas opções são úteis quando há mais de um grupo e a comparação entre os boxplots é facilitada.
Finalmente, podemos obter as medidas de posição e dispersão da mesma forma que para variáveis
discretas. Veja alguns exemplos a seguir. Note que aqui não é necessário o uso do argumento
na.rm = TRUE, pois não existem NAs nesta variável.
## Mediana
with(milsa, median(Salario))
[1] 10.165
## Média
with(milsa, mean(Salario))
[1] 11.12222
## Média aparada
with(milsa, mean(Salario, trim = 0.1))
[1] 10.838
## Quartis
with(milsa, quantile(Salario))
0% 25% 50% 75% 100%
4.0000 7.5525 10.1650 14.0600 23.3000
## Máximo e mínimo
with(milsa, max(Salario))
[1] 23.3
with(milsa, min(Salario))
[1] 4
## As duas informações juntas
with(milsa, range(Salario))
[1] 4.0 23.3
## Amplitude é a diferença entre máximo e mínimo
with(milsa, diff(range(Salario)))
[1] 19.3
## Variância
with(milsa, var(Salario))
6.3. ANÁLISE BIVARIADA 101
[1] 21.04477
## Desvio-padrão
with(milsa, sd(Salario))
[1] 4.587458
## Coeficiente de variação
with(milsa, 100 * sd(Salario)/mean(Salario))
[1] 41.24587
## Quartis
salario.qt <- with(milsa, quantile(Salario))
## Amplitude interquartílica
salario.qt[4] - salario.qt[2]
75%
6.5075
Tabelas de frequências relativas são obtidas com prop.table(), mas aqui existem três possibilida-
des para as proporções em cada casela:
Abaixo são representados quatro tipos de gráficos de barras que podem ser usados para representar
o cruzamento das variáveis. A transposição da tabela com t() permite alterar a variável que
define os grupos no eixo horizontal. O uso de prop.table() permite o obtenção de gráficos com
frequências relativas.
par(mfrow = c(2,2))
barplot(civ.inst.tb, legend = TRUE)
barplot(t(civ.inst.tb), legend = TRUE)
barplot(civ.inst.tb, beside = TRUE, legend = TRUE)
barplot(t(prop.table(civ.inst.tb)), beside = TRUE, legend = TRUE)
par(mfrow = c(1,1))
6.3. ANÁLISE BIVARIADA 103
20
15
solteiro Superior
10
casado 2o Grau
0 5
1o Grau
0
1o Grau 2o Grau Superior casado solteiro
8 12
0.20
casado 1o Grau
solteiro 2o Grau
4
Superior
0.00
0
No gráfico vamos considerar que neste exemplo a instrução deve ser a variável explicativa e
portanto colocada no eixo X, e o salário é a variável resposta, e portanto deve ser colocada no eixo
Y. Isto é, consideramos que a instrução deve explicar, ainda que parcialmente, o salário (e não o
contrário!).
Vamos então obter um boxplot dos salários para cada nível de instrução. Note que na função
abaixo, usamos a notação de fórmula do R, com Salario ~ Inst indicando que a variável Salario
é explicada, ou descrita, (∼) pela variável Inst.
boxplot(Salario ~ Inst, data = milsa)
20
15
Salario
10
5
Inst
Poderíamos ainda fazer gráficos com a variável Salario agrupada em classes, e neste caso os
gráficos seriam como no caso anterior com duas variáveis qualitativas.
Para as medidas descritivas, o usual é obter um resumo da variável quantitativa como mostrado
na análise univariada, porém agora informando este resumo para cada nível do fator qualitativo
de interesse.
A seguir mostramos alguns exemplos de como obter a média, desvio padrão e o resumo de cinco
números do salário para cada nível de instrução.
with(milsa, tapply(Salario, Inst, mean))
1o Grau 2o Grau Superior
7.836667 11.528333 16.475000
with(milsa, tapply(Salario, Inst, sd))
1o Grau 2o Grau Superior
2.956464 3.715144 4.502438
with(milsa, tapply(Salario, Inst, quantile))
$`1o Grau`
0% 25% 50% 75% 100%
4.0000 6.0075 7.1250 9.1625 13.8500
6.3. ANÁLISE BIVARIADA 105
$`2o Grau`
0% 25% 50% 75% 100%
5.7300 8.8375 10.9100 14.4175 19.4000
$Superior
0% 25% 50% 75% 100%
10.5300 13.6475 16.7400 18.3775 23.3000
NOTE que aqui usamos a função tapply(). Para saber mais sobre os recursos dessa
função e de outras da família *apply, veja o script_gapminder.R.
Caso queiramos definir um número menor de classes podemos fazer como no exemplo a seguir
onde cada variável é dividida em 3 classes e gerando um tabela de cruzamento 3 × 3.
idade.cut2 <- with(milsa, cut(Idade,
breaks = quantile(Idade, seq(0, 1, length = 4)),
include.lowest = TRUE))
salario.cut2 <- with(milsa, cut(Salario,
breaks = quantile(Salario, seq(0, 1, length = 4)),
106 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
include.lowest = TRUE))
table(idade.cut2, salario.cut2)
salario.cut2
idade.cut2 [4,8.65] (8.65,12.9] (12.9,23.3]
[20.8,32.1] 5 5 2
(32.1,37.8] 4 3 5
(37.8,48.9] 3 4 5
prop.table(table(idade.cut2, salario.cut2), margin = 1)
salario.cut2
idade.cut2 [4,8.65] (8.65,12.9] (12.9,23.3]
[20.8,32.1] 0.4166667 0.4166667 0.1666667
(32.1,37.8] 0.3333333 0.2500000 0.4166667
(37.8,48.9] 0.2500000 0.3333333 0.4166667
10
5
20 25 30 35 40 45 50
Idade
Para quantificar a associação entre variáveis deste tipo, usamos o coeficiente de correlação. A
função cor() possui opção para três coeficientes de correlação, tendo como default o coeficiente de
correlação linear de Pearson.
with(milsa, cor(Idade, Salario))
[1] 0.3651397
with(milsa, cor(Idade, Salario, method = "kendall"))
[1] 0.214456
6.3. ANÁLISE BIVARIADA 107
Exercícios
1. Experimente as funções mean(), var(), sd(), median(), quantile() nos dados mostrados
anteriormente (milsa). Veja a documentação das funções e as opções de uso.
2. Carregue o conjunto de dados women com data(women). Veja o que são os dados com
help(women), e faça uma análise descritiva adequada.
3. Carregue o conjunto de dados USArrests com data(USArrests). Examine a sua documenta-
ção com help(USArrests) e responda as perguntas a seguir:
1. Qual o número médio e mediano de cada um dos crimes?
2. Encontre a mediana e quartis para cada crime.
3. Encontre o número máximo e mínimo para cada crime.
4. Faça um gráfico adequado para o número de assassinatos (Murder).
5. Faça um boxplot para o número de estupros (Rape).
6. Verifique se há correlação entre os diferentes tipos de crime.
7. Verifique se há correlação entre os crimes e a proporção de população urbana.
8. Encontre os estados com maior e menor ocorrência de cada tipo de crime.
9. Encontre os estados com maior e menor ocorrência per capta de cada tipo de crime.
10. Encontre os estados com maior e menor ocorrência do total de crimes.
11. Calcule a média de crimes (entre Murder, Assault e Rape) para cada estado.
A resolução de todos os exercícios desta página está disponível neste script.
108 CAPÍTULO 6. ANÁLISE EXPLORATÓRIA DE DADOS
Capítulo 7
Os problemas desta sessão foram retirados do livro de Bussab e Morettin (2017). Veja também os
códigos do R dos exemplos do livro para os capítulos 6 e 7, disponíveis aqui.
Dada a função
2e−2x
, se x ≥ 0
f (x) =
0 , se x < 0
Para ser f.d.p. a função não deve ter valores negativos e deve integrar 1 em seu domínio. Vamos
começar definindo esta função como uma função no R para qual daremos o nome de f1.
f1 <- function(x){
fx <- ifelse(x < 0, 0, 2 * exp(-2 * x))
return(fx)
}
A seguir fazemos o gráfico da função. Como a função tem valores positivos para x no intervalo de
zero a infinito, temos que definir um limite em x até onde vai o gráfico da função. Vamos achar
este limite tentando vários valores, conforme mostrado nos comandos abaixo.
par(mfrow = c(2, 2))
plot(f1)
plot(f1, from = 0, to = 5)
plot(f1, from = 0, to = 7)
plot(f1, from = 0, to = 10)
par(mfrow = c(1, 1))
109
110 CAPÍTULO 7. PROBABILIDADE E VARIÁVEIS ALEATÓRIAS
2.0
1.5
1.0
f1
f1
0.5
0.0
0.0 0.2 0.4 0.6 0.8 1.0 0 1 2 3 4 5
x x
2.0
2.0
1.0
1.0
f1
f1
0.0
0.0
0 1 2 3 4 5 6 7 0 2 4 6 8 10
x x
Para verificar que a integral da função é igual a 1 podemos usar a função integrate(), que efetua
integração numérica. A função recebe como argumentos o objeto com a função a ser integrada e os
limites de integração. Neste exemplo o objeto é f1 definido acima, e o domínio da função é [0, ∞).
A saída da função mostra o valor da integral acima, e o erro máximo da aproximação numérica.
integrate(f1, lower = 0, upper = Inf)
1 with absolute error < 5e-07
Para fazer os cálculos pedidos nos itens (b) e (c) lembramos que a probabilidade é dada pela área
sob a curva da função no intervalo pedido. Desta forma as soluções seriam dadas pelas expressões
Z ∞ Z ∞
pb = P ( X > 1) = f ( x )dx = 2 e−2x dx
1 1
Z 0,8 Z 0.8
pc = P(0, 2 < X < 0, 8) = f ( x )dx = 2 e−2x dx
0,2 0.2
0.5
pc
pb
0.0
0 1 2 3 4 5
2
3 x , se 0 ≤ x < 1
f (x) = − 3x + 1 , se 1 ≤ x<3 (7.1)
0 , se x < 0 ou x ≥ 3
return(fx)
}
A seguir verificamos que a integral da função é 1 e fazemos o seu gráfico conforme mostrado
abaixo:
integrate(f2, 0, 3) ## verificando que a integral vale 1
1 with absolute error < 1.1e-15
plot(f2, -1, 4) ## fazendo o gráfico da função
0.6
0.4
f2
0.2
0.0
−1 0 1 2 3 4
Agora vamos responder às questões levantadas. Na questão (a) pede-se a probabilidade de que
sejam vendidos mais que 150 kg (1,5 centenas de quilos), portanto a probabilidade P[ X > 1, 5].
R ∞probabilidade corresponde à área sob a função no intervalo pedido, ou seja, P[ X > 1, 5] =
A
1,5 f ( x ) dx, que pode ser vista na figura abaixo.
plot(f2, -1, 4)
polygon(x = c(1.5, 1.5, 3), y = c(0, f2(1.5), 0), dens = 10)
7.1. CONCEITOS BÁSICOS SOBRE DISTRIBUIÇÕES DE PROBABILIDADE 113
0.6
0.4
f2
0.2
0.0
−1 0 1 2 3 4
A venda esperada emR trinta dias é 30 vezes o valor esperado de venda em um dia. Para calcular
a esperança E[ X ] = x f ( x )dx definimos uma nova função e resolvemos a integral. A função
integrate() retorna uma lista onde um dos elementos (value) é o valor da integral.
ef2 <- function(x) { x * f2(x) }
integrate(ef2, 0, 3)
1.333333 with absolute error < 7.3e-05
30 * integrate(ef2, 0, 3)$value
[1] 40
Finalmente lembramos que os exemplos discutidos aqui são simples e não requerem soluções
numéricas, devendo ser resolvidos analiticamente. Utilizamos estes exemplos somente para ilustrar
a obtenção de soluções numéricas com o uso do R, que na prática deve ser utilizado em problemas
mais complexos onde soluções analíticas não são triviais ou mesmo impossíveis.
Exercícios
1. (Adaptado de Bussab e Morettin, cap. 7, ex. 28). Em uma determinada localidade a
distribuição de renda, em u.m. (unidade monetária) é uma variável aleatória X com função
de distribuição de probabilidade:
1 1
10 x + 10 se 0 ≤ x ≤ 2
f (x) = 3 9
− 40 x + 20 se 2 < x ≤ 6
0 se x < 0 ou x > 6
c. Calcule a probabilidade de encontrar uma pessoa com renda acima de 4,5 u.m. e indique
o resultado no gráfico da distribuição.
2. Sabe-se que uma variável aleatória contínua X é equiprovável no intervalo 10 e 20.
a. Apresente o gráfico da função densidade de probabilidade.
b. Calcule P( X < 15).
c. Calcule P(12 ≤ X ≤ 18).
d. Calcule E( X ) e V ( X ).
3. Dois jogadores se alternam lançando dois dados equilibrados. O jogador A vence o jogo
se ocorrer soma 6, enquanto B vencerá se ocorrer 7. Faça um estudo de simulação para
responder as seguintes questões:
a. Se A começa jogando, qual é a sua probabilidade de vitória?
b. Qual é a probabilidade do iniciante, escolhido ao acaso, vencer o jogo?
4. A duração, em anos, de uma certa lâmpada especial é uma variável aleatória contínua com
densidade dada por:
2 exp−2x x ≥ 0
f (x) =
0 x<0
a. Crie uma função para calcular a função de distribuição acumulado de X.
b. Calcule P( X > 2).
c. Calcule P(0.5 < X < 1.2).
d. Calcule P( X > 3).
e. Calcule P( X < 3| X > 1).
5. (Desafio - Problema da ruína do jogador) Dois jogadores participam de um jogo com uma
moeda que tem probabilidade de cara igual a p e de coroa igual a q, sujeito a p + q = 1. O
jogador A inicia o jogo com i fichas e ganha mais uma de B, cada vez que der cara. O jogador
B começa com N − i fichas e, em cada lançamento que resultar coroa, ganha uma ficha de A.
Para enfatizar a dependência do número inicial de fichas i, denomine por p(i) a probabilidade
do jogador A ficar com todas as fichas, o que implica na ruína de B. Condicione no resultado
do primeiro lançamento da moeda, para estabelecer uma relação de recorrência entre os p(i)′ s .
1−(q/p)i 1 i
Usando p(0) = 0 e p N = 1, mostre via simulação que p(i) = 1−(q/p) N
para p ̸= 2 e p (i ) = N
para p = 12 .
[1] 0.1586553
qnorm(0.975)
[1] 1.959964
rnorm(10)
[1] -0.50219235 0.13153117 -0.07891709 0.88678481 0.11697127 0.31863009
[7] -0.58179068 0.71453271 -0.82525943 -0.35986213
" #
1 x−µ 2
1
f (x) = √ exp −
σ 2π 2 σ
irá exibir em uma janela a documentação da função que pode também ser chamada com ?rnorm.
Note que ao final da documentação são apresentados exemplos que podem ser rodados pelo usuá-
rio e que auxiliam na compreensão da funcionalidade. Note também que as 4 funções relacionadas
à distribuição normal são documentadas conjuntamente, portanto help(rnorm), help(qnorm),
help(dnorm) e help(pnorm) irão exibir a mesma documentação.
116 CAPÍTULO 7. PROBABILIDADE E VARIÁVEIS ALEATÓRIAS
Cálculos de probabilidades usuais, para os quais utilizavamos tabelas estatísticas podem ser
facilmente obtidos como no exemplo a seguir.
• P[ X < 95]
• P[90 < X < 110]
• P[ X > 95]
Calcule estas probabilidades de forma usual, usando a tabela da normal. Depois compare com os
resultados fornecidos pelo R. Os comandos do R para obter as probabilidades pedidas são:
## P[X < 95]
pnorm(95, 100, 10)
[1] 0.3085375
## P[90 < X < 110]
pnorm(110, 100, 10) - pnorm(90, 100, 10)
[1] 0.6826895
## P[X > 95] = 1 - P[X < 95]
1 - pnorm(95, 100, 10)
[1] 0.6914625
pnorm(95, 100, 10, lower.tail = FALSE) # melhor
[1] 0.6914625
Note que a última probabilidade foi calculada de duas formas diferentes, a segunda usando o
argumento lower.tail que implementa um algorítmo de cálculo de probabilidades mais estável
numericamente, e essa forma é preferida no lugar de usar o complementar.
A seguir vamos ver comandos para fazer gráficos de distribuições de probabilidade. Vamos fazer
gráficos de funções de densidade e de probabilidade acumulada. Estude cuidadosamente os
comandos abaixo e verifique os gráficos por eles produzidos.
0.4
1.0
0.8
0.3
0.6
dnorm
pnorm
0.2
0.4
0.1
0.2
0.0
0.0
−3 −1 0 1 2 3 −3 −1 0 1 2 3
x x
0.05
1.0
0.04
0.8
0.03
0.6
Fx
fx
0.02
0.4
0.01
0.2
0.00
x x
Note que, alternativamente, os mesmos gráficos poderiam ser produzidos com os comandos a
seguir, onde fazemos usa da função plot.function().
par(mfrow = c(1, 2))
plot(function(x) dnorm(x, 100, 8), from = 70, to = 130)
plot(function(x) pnorm(x, 100, 8), from = 70, to = 130)
par(mfrow = c(1, 1))
7.2. DISTRIBUIÇÕES DE PROBABILIDADE 119
0.05
1.0
function(x) dnorm(x, 100, 8)
0.8
0.03
0.6
0.02
0.4
0.01
0.2
0.00
x x
Comandos usuais do R podem ser usados para modificar a aparência dos gráficos. Por exemplo,
podemos incluir títulos e mudar texto dos eixos conforme mostrado abaixo.
plot(dnorm, from = -3, to = 3,
xlab = "Valores de X",
ylab = "Densidade de probabilidade")
title("Distribuicão Normal\nX ~ N(0, 1)")
120 CAPÍTULO 7. PROBABILIDADE E VARIÁVEIS ALEATÓRIAS
Distribuicão Normal
0.4 X ~ N(0, 1)
Densidade de probabilidade
0.3
0.2
0.1
0.0
−3 −2 −1 0 1 2 3
Valores de X
Os demais comandos abaixo mostram como colocar diferentes densidades em um mesmo gráfico,
usando o argumento add = TRUE.
plot(function(x) dnorm(x, 100, 8), 60, 140, ylab = 'f(x)')
plot(function(x) dnorm(x, 90, 8), 60, 140, add = TRUE, col = 2)
plot(function(x) dnorm(x, 100, 15), 60, 140, add = TRUE, col = 3)
legend(120, 0.05, fill = 1:3,
legend = c("N(100,64)", "N(90,64)", "N(100,225)"))
7.2. DISTRIBUIÇÕES DE PROBABILIDADE 121
0.05
N(100,64)
0.04
N(90,64)
N(100,225)
0.03
f(x)
0.02
0.01
0.00
Seja X uma v.a com distribuição binomial, com n = 10 e p = 0.35. Vamos ver os comandos do R
para:
• Fazer o gráfico da função de probabilidade.
• Idem para a função de distribuição acumulada.
• Calcular P( X = 7).
• Calcular P( X ≤ 7).
• Calcular P( X > 7).
• Calcular P(3 < X ≤ 6).
Note que sendo uma distribuição discreta de probabilidades os gráficos são diferentes dos obtidos
para a distribuição normal e os cálculos de probabilidades devem considerar as probabilidades nos
pontos específicos. Os gráficos das funções de probabilidade e distribuição são mostrados abaixo.
par(mfrow = c(1, 2))
x <- 0:10
fx <- dbinom(x, size = 10, prob = 0.35)
plot(x, fx, type = "h")
Fx <- pbinom(x, size = 10, prob = 0.35)
plot(x, Fx, type = "s")
par(mfrow = c(1, 1))
122 CAPÍTULO 7. PROBABILIDADE E VARIÁVEIS ALEATÓRIAS
1.0
0.8
0.6
Fx
fx
0 2 4 6 8 10 0.4
0.2
0.0 0 2 4 6 8 10
x x
Denominamos esse experimento de processo de Poisson. Vamos associar a v.a X como sendo
o número de ocorrências em um intervalo. Portanto X poderá assumir os valores 0, 1, . . . , (sem
7.2. DISTRIBUIÇÕES DE PROBABILIDADE 123
limite superior).
Uma v.a X segue o modelo de Poisson se surge a partir de um processo de Poisson, e sua função
de probabilidade for dada por
e−µ µ x
P( X = x ) = , x = 0, 1, . . .
x!
onde
µ = λ·t
O parâmetro µ indica a taxa de ocorrência (λ) por unidade de medida (t), ou seja,
• Notação: X ∼ Pois(µ)
• Esperança e variância: E( X ) = µ = Var( X )
µ=1 µ=5
0.4
0.4
P[X = x]
P[X = x]
0.2
0.2
0.0
0.0
0 5 10 15 20 25 30 0 5 10 15 20 25 30
X X
µ = 10 µ = 15
0.4
0.4
P[X = x]
P[X = x]
0.2
0.2
0.0
0.0
0 5 10 15 20 25 30 0 5 10 15 20 25 30
X X
• Exemplo: Suponha que 150 erros de impressão são distribuídos aleatoriamente em um livro
de 200 páginas. Encontre a probabilidade de que em 2 páginas contenham:
7.2. DISTRIBUIÇÕES DE PROBABILIDADE 125
Portanto, o default é uma distribuição uniforme no intervalo [0, 1] e os argumentos opcionais são
min e max. Por exemplo, para simular 5 valores de X ∼ U (5, 20) usamos:
runif(5, min = 5, max = 20)
[1] 7.571303 16.554524 18.229304 13.236451 9.165856
a possibilidade de associar diferentes probabilidades a cada elemento (argumento prob, que por
padrão associa probabilidades iguais para todos os elementos).
args(sample)
function (x, size, replace = FALSE, prob = NULL)
NULL
• Idem ao anterior, porém agora com a probabilidade de cada face proporcional ao valor da
face.
sample(1:6, size = 10, replace = TRUE, prob = 1:6)
[1] 6 4 3 6 5 3 2 6 5 5
Este último exemplo ilustra ainda que os valores passados para o argumento prob não precisam
ser probabilidades, são apenas entendidos como pesos. A própria função trata isto internamente
fazendo a ponderação adequada.
Vamos agora “esquecer” o comando pnorm() e ver uma outra forma de resolver usando integração
numérica. Lembrando que a normal tem a função de densidade dada por
" #
1 x−µ 2
1
f (x) = √ exp − .
σ 2π 2 σ
Para obter o gráfico desta distribuição, usamos o fato que a maior parte da massa da função está
no intervalo entre a média +/- três desvios padrões, portanto entre 70 e 130. Podemos então fazer
como nos comandos que se seguem. Para marcar no gráfico a área que corresponde a probabilidade
pedida criamos um polígono com coordenadas ax e ay definindo o perímetro desta área.
x <- seq(70, 130, length.out = 200)
fx <- fn(x, mu = 100, sigma = 10)
plot(x, fx, type = "l")
ax <- c(70, 70, x[x < 95], 95, 95)
ay <- c(0, fn(70, 100, 10), fx[x < 95], fn(95, 100, 10),0)
polygon(ax, ay, density = 10)
0.04
0.03
0.02
fx
0.01
0.00
Para calcular a área pedida sem usar a função pnorm() podemos usar a função de integração
numérica. Note que esta função, diferentemente da pnorm() reporta ainda o erro de aproximação
numérica.
integrate(fn, mu = 100, sigma = 10, lower = -Inf, upper = 95)
0.3085375 with absolute error < 2.1e-06
Portanto para os demais ítens do problema, P(90 < X < 110), e P( X > 95) fazemos:
integrate(fn, mu = 100, sigma = 10, lower = 90, upper = 110)
0.6826895 with absolute error < 7.6e-15
integrate(fn, mu = 100, sigma = 10, lower = 95, upper = +Inf)
0.6914625 with absolute error < 8.1e-05
Note ainda que na prática não precisamos definir e usar a função fn(), pois ela fornece o mesmo
resultado que a função dnorm().
Exercícios
Nos exercícios abaixo iremos também usar o R como uma calculadora estatística para resolver
alguns exemplos/exercícios de probabilidade tipicamente apresentados em um curso de estatística
básica.
1. Para X ∼ N (90, 100), obtenha:
a. P( X ≤ 115).
b. P( X ≥ 80).
c. P( X ≤ 75).
d. P(85 ≤ X ≤ 110).
e. P(| X − 90| ≤ 10).
f. O valor de a tal que P(90 − a ≤ X ≤ 90 + a) = 0.95.
2. Sendo X uma variável seguindo o modelo Binomial com parâmetros n = 15 e p = 0.4,
pergunta-se:
a. P( X ≥ 14).
b. P(8 < X ≤ 10).
c. P( X < 2 ou X ≥ 11).
d. P( X ≥ 11 ou X > 13).
e. P( X > 3 e X < 6).
f. P( X ≤ 13 | X ≥ 11).
3. Uma empresa informa que 30% de suas contas a receber de outras empresas encontram-
se vencidas. Se o contador da empresa seleciona aleatoriamente 5 contas, determine a
probabilidade de:
a. Nenhuma conta estar vencida
b. Exatamente duas contas estarem vencidas
c. Três ou mais contas estarem vencidas
4. Uma empresa recebe 720 emails em um intervalo de 8 horas. Qual a probabilidade de que:
a. Em 6 minutos receba pelo menos 3 emails?
b. Em 4 minutos não receba nenhum email?
5. O processo de empacotamento de uma fábrica de cereais foi ajustado de maneira que uma
média de µ = 13, 0 kg de cereal seja colocado em cada caixa. Sabe-se que existe uma pequena
variabilidade no enchimento dos pacotes devido à fatores aleatórios, e que o desvio-padrão
do peso de enchimento é de σ = 0, 1 kg. Assume-se que a distribuição dos pesos tem
distribuição normal. Com isso, determine as probabilidades de que uma caixa escolhida ao
acaso:
a. Pese entre 13,0 e 13,2 kg.
b. Tenha um peso maior do que 13,25 kg.
c. Pese entre 12,8 e 13,1 kg.
d. Pese entre 13,1 e 13,2 kg.
6. Faça os seguintes gráficos:
a. da função de densidade de uma variável com distribuição de Poisson com parâmetro
λ = 5.
b. da densidade de uma variável X ∼ N (90, 100).
c. sobreponha ao gráfico anterior a densidade de uma variável Y ∼ N (90, 80) e outra
Z ∼ N (85, 100).
d. densidades de distribuições χ2 com 1, 2 e 5 graus de liberdade.
Capítulo 8
Inferência estatística
129
130 CAPÍTULO 8. INFERÊNCIA ESTATÍSTICA
como sendo Y - votar no candidato X. Note que esta é uma v.a binária, ou seja, apresenta apenas
os valores 0-não vai votar no candidato X ou 1 vai votar no candidato X. Neste caso, podemos
especificar que Y ∼ B( p), ou seja, Y segue o modelo de Bernoulli com parâmetro p. Importante
lembrar que o espaço paramétrico de p neste caso é o intervalo unitário, ou seja, p ∈ (0, 1).
Uma vez com o modelo especificado precisamos de informações sobre o parâmetro populacional
de interesse, neste caso p que representa a proporção de eleitores do candidato X. Para obter
informações sobre p vamos coletar uma amostra da população de interesse e medir a variável
de interesse. Neste caso, isso significa simplesmente perguntar se o eleitor vai ou não votar no
candidato X. Em R podemos facilmente simular esta situação prática usando a função rbinom(),
conforme ilustra o código abaixo
set.seed(123)
y <- rbinom(n = 10, size = 1, prob = 0.5)
y
[1] 0 1 0 1 1 0 1 1 1 0
Note que para simular uma amostra nós precisamos especificar o tamanho da amostra, neste caso
n = 10 o número de ensaios Bernoulli neste caso apenas 1 e a probabilidade de sucesso (proporção
populacional). É claro que na prática a proporção populacional é desconhecida, mas neste caso
fixamos um valor para simular observações e o objetivo é apenas baseado nas realizações da
variável aleatória descobrir ou inferir qual é o verdadeiro valor de p. De forma mais geral os
objetivos da inferência estatística são:
• Estimar p baseado apenas na amostra (valor pontual)! Pense que deseja-se responder a
pergunta: Quanto você acha que é a proporção de eleitores do candidato X na população?
• Informar o quanto você acredita no valor estimado (intervalo de confiança).
• Decidir sobre possíveis valores de p baseado apenas na amostra. Por exemplo, O candidato
X vai ganhar (p > 0,50)?
Interessante notar que até este momento não fizemos nenhuma suposição em como as observações
foram obtidas. No entanto, se supomos que as observações são independentes podemos facilmente
obter a distribuição conjunta de todas as variáveis aleatórias envolvidas no modelo como o produto
da distribuição de cada uma. Neste caso, todas as observações vêm de uma população Bernoulli
com parâmetro p. Assim, a distribuição conjunta é dada pelo seguinte produtório
n n n
P (Y = y ) = ∏ p y i ( 1 − p ) 1 − y i = p ∑ i =1 y i ( 1 − p ) n − ∑ i =1 y i .
i =1
n y
P (Y = y ) = P (Y = y ) = p (1 − p ) n − y .
y
É importante enfatizar que após a amostra ser coletada o número y de sucesso é fixo. Para a nossa
amostra, temos y = 6. Lembre-se que o n foi fixado, assim para avaliar a equação acima em algum
ponto, só precisamos fixar o valor de p.
Agora vamos refletir sobre o que a equação acima está nos fornecendo. Suponha que em um
primeiro momento você apenas precise decidir se p = 0.5 ou p = 0.8. Como poderíamos usar o
nosso modelo para tomar esta decisão?
Note que podemos calcular qual é a probabilidade de obter 6 sucessos em n ensaios supondo que
p = 0.5 e também supondo que p = 0.8. Vamos fazer estas contas
10
P(Y = 6| p = 0.5) = 0.56 (1 − 0.5)10−6 = 0.205.
6
8.1. INTRODUÇÃO AO PENSAMENTO ESTATÍSTICO 131
10
P(Y = 6| p = 0.8) = 0.86 (1 − 0.8)10−6 = 0.088.
6
Em R temos,
dbinom(6, size = 10, prob = 0.5)
[1] 0.2050781
dbinom(6, size = 10, prob = 0.8)
[1] 0.08808038
Para enfatizar esta idéia vamos rescrever a função acima para enfatizar que a quantidade desco-
nhecida agora é p e não mais y.
n y
L( p|y) = p (1 − p ) n − y .
y
10 6
L( p|y) = p (1 − p)10−6 .
6
Na prática é mais comum trabalhar com o log da verossimilhança por conveniência computacional.
Isso leva a chamada função de log-verossimilhança, cujo gráfico é apresentado abaixo para o nosso
exemplo
ll <- function(p, n, y) {
out <- dbinom(y, size = n, prob = p, log = TRUE)
return(out)
}
curve(ll(x, n = 10, y = 6), 0.4, 0.8)
abline(v = mean(y))
8.1. INTRODUÇÃO AO PENSAMENTO ESTATÍSTICO 133
Não é dificil mostrar usando ferramentas padrões de cálculo diferencial que o ponto de máximo
ocorre em p̂ = y/n, ou seja, na proporção amostral de eleitores do candidato X.
Com essa ideia simples resolvemos o primeiro objetivo da inferência estatística que consiste em
dizer qual valor achamos razoável para p dado a amostra que coletamos. O próximo objetivo é
dizer o quanto acreditamos neste valor. Note que uma vez que temos a função de verossimilhança
ou log-verossmilhança basta olhar para a função para responder a tal pergunta. O ponto de
máximo é o mais compatível, porém valores ao redor do máximo também apresentam uma boa
compatibilidade com a amostra e portanto são bons candidatos a valor de p. Essa ideia pode ser
resumida por fazer um corte horizontal na função de log-verossimilhança. Assim, todos os pontos
acima do corte são bons candidatos a verdadeiro valor de p.
curve(ll(x, n = 10, y = 6), 0.4, 0.8)
abline(h = -2)
134 CAPÍTULO 8. INFERÊNCIA ESTATÍSTICA
Entretanto, onde fazer tal corte não é uma tarefa simples e explicar como e por que fazer isso em
detalhes está fora do escopo deste material. Esta é a ideia por traz da definição do que se chama
popularmente de intervalo de confiança. Uma forma alternativa é fazer um gráfico da função de
verossimilhança relativa, definida como a verossimilhança divida pela verossimilhança no ponto
de máximo,
Neste caso um intervalo pode ser obtido por definir algum valor entre 0 e 1 para obter intervalos
não vazios. Por exemplo, podemos definir que uma compatibilidade de pelo menos 0.4 com a
amostra é necessário para que um valor seja parte do intervalo. Ilustrando graficamente temos,
LR <- function(p, p_hat, n, y) {
out <- L(p = p, n = n, y = y)/L(p = p_hat, n = n, y = y)
return(out)
}
curve(LR(x, p_hat = 0.6, n = 10, y = 6), 0, 1)
abline(h = 0.4)
8.1. INTRODUÇÃO AO PENSAMENTO ESTATÍSTICO 135
1.0
LR(x, p_hat = 0.6, n = 10, y = 6)
0.8
0.6
0.4
0.2
0.0
Por fim, o último objetivo da inferência consiste em decidir se um determinado valor hipotético
para p é ou não compatível com a amostra observada. Note que o valor mais compatível é o
máximo da verossimilhança, assim para decidir se um valor é ou não compatível com a amostra,
basta verificar se ele está perto ou longe do valor que tem maior compatibilidade. Esta ideia é o
que esta por traz do que se chama de teste de hipóteses e é ilustrada abaixo.
0.6 1.0
0.8
LR(p|y=6)
L(p0) L(p
^)
0.4 0.2
0.0
^
p ^
p ^p0
p
I S
par(mfrow = c(1,1), mar=c(2.6, 2.8, 1.2, 0.5), mgp = c(1.6, 0.6, 0))
plot(prop.table(table(p.hat)), main = "",
ylab = "Proporção observada",
xlab = expression(hat(p)), xlim = c(0,1))
0.20
Proporção observada
0.05 0.10 0.15
0.00
A Figura acima mostra que mesmo o verdadeiro valor de p sendo 0.5 existe uma probabilidade
razoável de observarmos p̂ = 0.4 e p̂ = 0.6 em uma amostra de tamanho 10. Porém, quando
nos distanciamos de 0.5 a probabilidade de observar p̂ mais extremos como 0.1 ou 0.9 é pequena.
No geral, a incerteza com relação ao valor de p é grande. Para diminuir tal incerteza precisamos
8.2. ESTIMAÇÃO PONTUAL E INTERVALOS DE CONFIANÇA 137
ganhar mais informações sobre o valor de p e para isso precisamos de mais amostras.
Note que para cada possível amostra coletada o valor de p̂ é alterado. Isso é decorrente de p̂
ser também uma função da variável aleatória Y. Para enfatizar isso usamos a notação p̂ = Y/n
e neste caso chamamos p̂ de estimador do valor de p. Pensando desta forma p̂ é também uma
variável aleatória e consequentemente ele deve ter uma distribuição de probabilidade que pode
ser resumida, por exemplo, usando esperança e variância.
A Figura abaixo mostra o efeito do tamanho da amostra sobre a distribuição amostral do estimador
p̂.
set.seed(1234)
p.hat.list <- list()
amostra <- c(10, 50, 100, 250,500, 1000)
par(mfrow = c(2,3), mar=c(2.6, 2.8, 1.2, 0.5), mgp = c(1.6, 0.6, 0))
for(j in 1:6) {
p.hat.list[[j]] <- matrix(NA, ncol = 1, nrow = 1000)
for(i in 1:1000) {
y <- rbinom(amostra[j], prob = 0.5, size = 1)
p.hat.list[[j]][i,] <- mean(y)
}
hist(p.hat.list[[j]], prob = TRUE, main = paste("Amostra", amostra[j]),
ylab = "Proporção observada",
xlab = expression(hat(p)), xlim = c(0,1))
}
Proporção observada
Proporção observada
6
2.0
6
4
4
1.0
2
0.0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p
Amostra 250 Amostra 500 Amostra 1000
Proporção observada
Proporção observada
Proporção observada
25
12
5 10 15
8
15
4
0 5
0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p
Note que quanto maior a amostra a distribuição amostral fica mais concentrada ao redor do
verdadeiro valor de p. Isso é decorrente da Lei dos grandes números. Além disso, note que a
distribuição é muito parecida com a distribuição normal, um resultado conhecido como Teorema
Central do Limite.
A idéia de intervalo de confiança é simplesmente olhar para a distribuição amostral e responder a
pergunta: Qual o intervalo em que p̂ tem uma probabilidade, digamos (1 − α) de pertencer?
O valor de α deve ser especificado e alguns valores populares são 0.05 e 0.01. A Figura abaixo
ilustra esta ideia.
set.seed(1234)
p.hat.list <- list()
amostra <- c(10, 50, 100)
par(mfrow = c(1,3), mar=c(2.6, 2.8, 1.2, 0.5), mgp = c(1.6, 0.6, 0))
138 CAPÍTULO 8. INFERÊNCIA ESTATÍSTICA
for(j in 1:3) {
p.hat.list[[j]] <- matrix(NA, ncol = 1, nrow = 1000)
for(i in 1:1000) {
y <- rbinom(amostra[j], prob = 0.5, size = 1)
p.hat.list[[j]][i,] <- mean(y)
}
hist(p.hat.list[[j]], prob = TRUE, main = paste("Amostra", amostra[j]),
ylab = "Densidade",
xlab = expression(hat(p)), xlim = c(0,1))
abline(v= c(quantile(p.hat.list[[j]], probs = c(0.025, 0.975))), col = "red")
}
7
6
2.0
6
2 3 4 5
3 4 5
Densidade
Densidade
Densidade
1.0 1.5
2
0.5
1
0.0
0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p
Temos um procedimento bastante simples para obter os limites do intervalo de confiança, porém
tal procedimento depende de sermos capazes de realizar o experimento um número grande de
vezes. Na prática só temos uma amostra coletada e baseado apenas nesta amostra precisamos
inferir sobre p. É neste ponto que entra o fato de p̂ ser uma variável aleatória. Este fato permite
que exploremos sua distribuição mesmo sem realizar um grande número de experimentos.
De forma geral obter a distribuição de probabilidade de um estimador não é uma tarefa trivial,
porém o Teorema Central do Limite nos fornece uma boa aproximação, ao menos para grandes
amostras. O Teorema Central do limite em sua versão mais simples é como segue:
• Teorema Lindeberg-Levy: Seja Y1 , . . . , Yn uma amostra iid com E(Yi ) = µ e V (Yi ) = σ2 < ∞.
Então,
√ Ȳ − µ D
n → Z ∼ N (0, 1), para n → ∞.
σ
• Isso significa que, para todo y ∈ ℜ,
onde Z y
1 1
Φ(y) = ϕ(z)dz e ϕ(z) = √ exp − z2 .
−∞ 2π 2
• Forma alternativa: Ȳ ∼ N (µ, σ2 /n).
Particularizando para o nosso exemplo temos que:
• Estimador de máxima verossimilhança p̂ = Yn .
• Usando as propriedades da distribuição binomial, temos
1 np
E( p̂) = E(Y/n) = E (Y ) = = p.
n n
1 np(1 − p) p (1 − p )
Var ( p̂) = Var (Y/n) = Var (Y ) = = .
n2 n2 n
8.2. ESTIMAÇÃO PONTUAL E INTERVALOS DE CONFIANÇA 139
6
Densidade
Densidade
Densidade
4
4
1.0
2
0.0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p
Amostra 250 Amostra 500 Amostra 1000
25
12
5 10 15
Densidade
Densidade
Densidade
8
15
4
5
0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p
yi
onde λ̂ = ∑in=1 n.
O intervalo de confiança deve ser interpretado sempre com muito cuidado. A interpretação
frequentista é a seguinte: Se o experimento for repetido um número n de vezes e para cada
realização obtermos o intervalo de confiança, esperamos que (1 − α)% dos intervalos contenham o
verdadeiro valor do parâmetro. Note que a variável aleatória é o próprio intervalo de confiança.
O código abaixo ilustra computacionalmente tal interpretação.
set.seed(12)
results_wald <- matrix(NA, ncol = 2, nrow = 100)
for(i in 1:100) {
y <- rbinom(100, size = 1, prob = 0.5)
p_hat <- mean(y)
v_hat <- (p_hat*(1-p_hat))/100
temp_wald <- c(p_hat - qnorm(0.975)*sqrt(v_hat), p_hat + qnorm(0.975)*sqrt(v_hat))
results_wald[i,] <- temp_wald
}
## Intervalo Wald
plot(c(0.30,0.72) ~ c(1,100), type = "n", ylab = expression(p), xlab = "Ensaio")
abline(h=0.50)
for(i in 1:100) {
arrows(c(i),results_wald[i,1],c(i),results_wald[i,2],code=3,angle=90,length=0.03,
col=ifelse(results_wald[i,1] > 0.5 | results_wald[i,2] < 0.5, "darkred","lightgray"))
}
0.7
0.6
p
0.5
0.4
0.3
0 20 40 60 80 100
Ensaio
8.2. ESTIMAÇÃO PONTUAL E INTERVALOS DE CONFIANÇA 141
Exemplo 1 No caso do candidato X suponha que é de interesse apresentar uma estimativa intervalar
para a proporção de eleitores de X na população. Assumindo que a estimativa amostral foi de 0, 60
(seis sucessos em dez ensaios) o intervalo com 95% de confiança é dado por
q q
p̂ I = 0, 6 − 1.96 0, 6(1 − 0, 6)/10 = 0.296 e p̂S = 0, 6 − 1.96 0, 6(1 − 0, 6)/10 = 0.904.
Exemplo 2 Num grupo de pacientes, o nível de colesterol é uma variável aleatória com distribuição
Normal, de média desconhecida e variância 64(mg/ml )2 . - Para uma amostra de 46 indivíduos
que forneceu nível médio de colesterol de 120 mg/ml, construa o intervalo de confiança de 88%.
media <- 120
sd <- sqrt(64)
n <- 46
alpha = 0.12
mu_I <- media - qnorm((1 - alpha/2))*sd/sqrt(46)
mu_S <- media + qnorm((1 - alpha/2))*sd/sqrt(46)
c(mu_I, mu_S)
[1] 118.1661 121.8339
Exercícios
1. Por analogia a produtos similares, o tempo de reação de um novo medicamento pode
ser considerado como tendo distribuição Normal com desvio padrão igual a 2 minutos
(a média desconhecida). Vinte pacientes foram sorteados, receberam o medicamento
e tiveram seu tempo de reação anotado. Os dados foram os seguintes (em minutos):
2, 9; 3, 4; 3, 5; 4, 1; 4, 6; 4, 7; 4, 5; 3, 8; 5, 3; 4, 9; 4, 8; 5, 7; 5, 8; 5, 0; 3, 4; 5, 9; 6, 3; 4, 6; 5, 5 e 6, 2.
Obtenha um intervalo de confiança para o tempo médio de reação. Use 96% de confiança.
2. Uma amostra de 25 observações de uma Normal (µ, 16) foi coletada e forneceu uma média
amostral de 8. Construa intervalos de confiança com 80%, 85%, 90% e 95% de confiança.
Comente as diferenças encontradas.
3. Numa pesquisa com 50 eleitores, o candidato José João obteve 0, 34 da preferência dos
eleitores. Construa, para a confiança de 94% o intervalo de confiança para a proporção de
votos a serem recebidos pelo candidato mencionado.
4. Considere a seguinte amostra da distribuição de Poisson de parâmetro λ. Proponha um esti-
mador pontual e intervalar para λ usando o método de máxima verossimilhança. Implemente
seu método em R. Faça um estudo de simulação para ilustrar a distribuição aproximada
deste estimador.
5. O número de atendimentos em um pronto-socorro pode ser modelado por uma distribuição
de Poisson de parâmetro λ. Suponha que o interesse seja modelar o número de atendimentos
por hora e que para um conjunto de 30 horas o número de atendimentos por hora foi contado
e as observações são mostradas abaixo.
# A tibble: 3 x 1
`matrix(y, 3, 10)`[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
<int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 6 11 8 8 9 12 7 9 9 9
2 10 13 12 13 8 6 13 9 9 6
3 7 4 8 8 5 3 12 16 8 5
O seu interesse é dimensionar o número de médicos para este pronto socorro. Suponha que um
médico consegue atender até quatro pessoas em um período de uma hora. A politica do hospital
especifica que se deve manter um contigente de médicos necessários para atender a demanda em
95% dos dias. Especifique quantos médicos devem estar de plantão para que a politica do hospital
seja respeitada.
142 CAPÍTULO 8. INFERÊNCIA ESTATÍSTICA
Voltando ao nosso exemplo do candidato X, podemos estar interessados por exemplo em saber se
a proporção de votos no candidato X é maior que 0.5, o que implicaria que ele ganharia a eleição.
Em termos de distribuição de probabilidade essa é uma afirmativa acerca do valor do parâmetro p.
Sendo assim, enunciamos as hipóteses da seguinte forma:
1 1
H0 : p = vs H1 : p ̸= .
2 2
Nesta notação H0 é chamada de hipótese nula. Por outro lado, H1 é chamada de hipótese alterna-
tiva.
0.20
Proporção observada
0.05 0.10 0.15 0.00
Veja que mesmo a hipótese nula sendo verdadeira existe uma probabilidade não desprezível
de observarmos 8 eleitores de X em 10 eleitores. A incerteza associada a decisão no caso de
apenas 10 observações é grande. Para diminuir a incerteza precisamos de mais informação o que
conseguimos aumentanto a amostra. A Figura abaixo ilustra esta situação
set.seed(1234)
p.hat.list <- list()
amostra <- c(10, 50, 100, 250,500)
par(mfrow = c(1,5), mar=c(2.6, 2.8, 1.2, 0.5), mgp = c(1.6, 0.6, 0))
for(j in 1:5) {
p.hat.list[[j]] <- matrix(NA, ncol = 1, nrow = 1000)
for(i in 1:1000) {
y <- rbinom(amostra[j], prob = 0.5, size = 1)
p.hat.list[[j]][i,] <- mean(y)
}
hist(p.hat.list[[j]], prob = TRUE, main = paste("Amostra", amostra[j]),
ylab = "Proporção observada",
xlab = expression(hat(p)), xlim = c(0,1))
}
Amostra 10 Amostra 50 Amostra 100 Amostra 250 Amostra 500
1 2 3 4 5 6 7
2 4 6 8 10 12
1 2 3 4 5 6
0.5 1.0 1.5 2.0
Proporção observada
Proporção observada
Proporção observada
Proporção observada
Proporção observada
5 10 15
0.0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p ^
p ^
p
set.seed(1234)
p.hat.list <- list()
amostra <- c(10, 50, 100, 250,500)
par(mfrow = c(1,5), mar=c(2.6, 2.8, 1.2, 0.5), mgp = c(1.6, 0.6, 0))
for(j in 1:5) {
p.hat.list[[j]] <- matrix(NA, ncol = 1, nrow = 1000)
for(i in 1:1000) {
y <- rbinom(amostra[j], prob = 0.5, size = 1)
p.hat.list[[j]][i,] <- mean(y)
}
hist(p.hat.list[[j]], prob = TRUE, main = paste("Amostra", amostra[j]),
ylab = "Proporção observada",
xlab = expression(hat(p)), xlim = c(0,1))
abline(v= c(quantile(p.hat.list[[j]], probs = c(0.025, 0.975))), col = "red")
}
2 4 6 8 10 12
1 2 3 4 5 6
0.5 1.0 1.5 2.0
Proporção observada
Proporção observada
Proporção observada
Proporção observada
Proporção observada
5 10 15
0.0
0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
^
p ^
p ^
p ^
p ^
p
Novamente em termos práticos não temos como repetir o experimento um número grande vezes.
Assim, recorremos novamente ao Teorema Central do Limite e estabelecemos a região critica de
forma aproximada usando a aproximação Gaussiana. No caso Bernoulli, este procedimento resulta
na seguinte estatística de teste
p̂ − p0
Z= q ∼ N (0, 1).
p0 (1− p0 )
n
O procedimento aqui descrito em linhas gerais é bastante genérico e perfaz toda a estatística.
No entanto está fora do escopo deste material discutir tais procedimentos em detalhes. Na
sequência apresentamos o resumo de alguns casos notáveis de testes de hipóteses que aparecem
com frequência em cursos de estatística básica.
Exemplo 1 Considere que seja de interesse verificar se existe evidências que o candidato X vai
ganhar as eleições. Em termos estatístico isso significa que
Suponha que adotamos 5% de significância. Neste caso a região crítica é unilateral, e tem a seguinte
forma
√
pc = 0.5 + 1.64 0.25/10 = 0.76.
Vamos fazer um gráfico da região de aceitação e rejeição e verificar onde a proporção amostral está
localizada para concluir o teste.
curve(dnorm(x, mean = 0.5, sd = sqrt(0.25/10)), 0.1, 0.9,
ylab = "Densidade", xlab = expression(hat(p)))
abline(v = 0.5+qnorm(0.95)*sqrt(0.25/10))
abline(v = 6/10, col = "red", lty = 2, lwd = 2)
8.3. TESTE DE HIPÓTESE 145
2.5
2.0
Densidade
1.5
1.0
0.5
Lembre-se que a proporção amostral foi de 0.6 em 10 entrevistas. Assim, vemos claramente que
não temos evidências para rejeitar H0 . Neste caso não temos evidências para dizer que o candidato
X irá ganhar a eleição.
• Estatística do teste caso Normal
No caso de população Normal, a estatística de teste para testar H0 : µ = µ0 contra H1 : µ ̸= µ0
com variância conhecida σ2 é dada por
ŷ − µ0
√ ∼ N (0, 1)
σ/ n
onde µ0 é o valor especificado sob a hipótese nula. Neste caso a região crítica para testes bilaterais
toma a seguinte forma:
p p
y I = µ0 − Zα/2 σ2 /n e yS = µ0 + Zα/2 σ2 /n.
Exemplo 2 (Magalhães e Lima, pg. 252). Um pesquisador deseja estudar o efeito de certa
substância no tempo de reação de seres vivos a um certo tipo de estímulo. Um experimento
é desenvolvido com cobaias que são inoculadas com a substância e submetidas a um estimulo
elétrico, com seus tempos de reação (em segundos) anotados. Os seguintes valores foram obtidos:
9, 1; 9, 3; 7, 2; 7, 5; 13, 3; 10, 9; 7, 2; 9, 9; 8, 0; 8, 6. Admite-se que o tempo de reação
segue, em geral o modelo Normal com média 8 e desvio padrão σ = 2 segundos. O pesquisador
desconfia, entretanto, que o tempo médio sofre alteração por influência da substância. Neste caso
as hipóteses de interesse são:
• H0 : as cobais apresentam tempo de reação padrão;
• H1 : as cobais tem o tempo de reação alterado.
Em termos de modelo estatístico, tais hipóteses são traduzidas para afirmações acerca do parâmetro
µ.
• H0 : µ = 8 contra H1 : µ ̸= 8.
146 CAPÍTULO 8. INFERÊNCIA ESTATÍSTICA
6 7 8 9 10
y^
Exemplo 3: (Magalhães e Lima, pg. 259). Deseja-se investigar se uma certa moléstia que ataca
o rim altera o consumo de oxigênio desse orgão. Para indivíduos sadios, admite-se que esse
consumo tem distribuição Normal com média 12 cm3 /min. Os valores medidos em cinco pacientes
com a moléstia foram: 14, 4; 12, 9; 15, 0; 13, 7; e 13, 5. Qual seria a conclusão, ao nível de 1% de
significância?
O teste de interesse é
• H0 : A moléstia não altera a média de consumo renal de oxigênio;
• H1 : Indivíduos portadores da moléstia têm média alterada.
Passando as hipóteses em termos do nosso modelo
• H0 : µ = 12 contra H1 : µ ̸= 12.
O R conta com uma função especifica para este teste, conforme mostra o código abaixo.
y <- c(14.4,12.9,15,13.7,13.5)
t.test(x = y, mu = 12)
data: y
t = 5.2099, df = 4, p-value = 0.006472
alternative hypothesis: true mean is not equal to 12
95 percent confidence interval:
12.88745 14.91255
sample estimates:
mean of x
13.9
Neste caso rejeitamos H0 em favor de H1 . Note que a função retorna uma série de informações
úteis. Temos o tipo de teste realizado, o valor da estatística t e os graus de liberdade do teste ao
lado do p − valor. A função já apresenta a conclusão do teste e por reporta o intervalo de confiança
para a média amostral e a média amostral.
<dbl> <dbl>
1 10 15
2 13 12
3 9 18
4 10 16
5 14 15
6 13 17
7 10 17
8 15 15
9 12 16
10 10 17
11 9 11
12 10 17
13 13 14
14 14 NA
Apesar de não conhecidas, as variâncias populacionais são assumidas iguais com base em estudos
anteriores. Suponha que o interesse é testar
• H0 : µ J = µ A contra H1 : µ J ̸= µ A .
t.test(x = J, y = A, paired = FALSE, var.equal = TRUE)
data: J and A
t = -4.7965, df = 25, p-value = 6.313e-05
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-5.450501 -2.175872
sample estimates:
mean of x mean of y
11.57143 15.38462
Exemplo 5 Considere o exemplo dos digitadores, porém agora sem assumir que as variâncias
populacionais são iguais. O teste t neste caso pode ser realizado da seguinte forma:
t.test(x = J, y = A, paired = FALSE, var.equal = FALSE)
data: J and A
t = -4.7967, df = 24.856, p-value = 6.399e-05
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-5.450930 -2.175444
sample estimates:
8.3. TESTE DE HIPÓTESE 149
mean of x mean of y
11.57143 15.38462
Paired t-test
8.3.5 Teste F
• Teste F para igualdade de variâncias.
– Hipóteses: H0 : σ12 = σ22 × H1 : σ12 ̸= σ22 .
s21
– Estatística de teste: F = s22
∼ F(n1 −1)(n2 −1) .
– Suposições Y1 ∼ N (µ1 , σ12 ) e Y2 ∼ N (µ2 , σ22 ).
– Em geral, este teste é conhecido por ser sensível a suposição de normalidade.
• Se normalidade é duvidosa, use o teste para variâncias diferentes.
• Poder e tamanho do teste podem ser altamente sensíveis a suposições.
• Para grandes amostras o TCL fornece uma opção robusta a não-normalidade.
• Regra do dedão Amostra maior que 30 TCL funciona bem!
• Mas cuidado!! depende da situação!!
Exemplo 7 Sabe-se que em uma região do país a altura média é de 1, 68m, com variância de 0, 30m2 .
Um pesquisador acredita que a alimentação rotineira em uma cidade litorânea, sendo diferente da
região como um todo, contribui para que as pessoas apresentem alturas mais homogêneas, apesar
de não alterar a altura média da população da cidade. Para verificar sua suspeita, ele coletou um
amostra de 31 pessoas e obteve a seguinte amostra:
y <- c(1.77, 1.72, 2.39, 1.95, 1.69, 1.84, 1.86, 1.57, 1.38, 1.47, 1.94,
1.15, 1.93, 2.18, 1.37, 1.56, 1.28, 1.81, 1.66, 1.99, 2.07, 1.67,
1.40, 1.03, 1.58, 1.99, 1.48, 1.73, 1.44, 1.35, 1.54)
data: y and x
F = 1.1044, num df = 30, denom df = 19, p-value = 0.5811
alternative hypothesis: true ratio of variances is less than 1
95 percent confidence interval:
0.000000 2.148239
sample estimates:
ratio of variances
1.10436
Exercícios
1. Uma empresa de pesquisa de mercado usou uma amostra de indivíduos para avaliar o
potencial de compra de determinado produto antes e depois de as pessoas virem um novo
comercial de televisão a respeito do produto. As avaliações do potencial de compra basearam-
se em uma escala de 0 a 10, e os valores mais altos indicavam maior potencial de compra. A
hipótese nula declarava que a avaliação média depois seria igual a avaliação média antes.
A rejeição dessa hipótese demonstraria que o comercial melhorou a avaliação do potencial
médio de compra. Use α = 0, 05 e os dados apresentados abaixo para testar a hipótese e
comentar o valor do comercial.
# A tibble: 8 x 3
ind Depois Antes
<int> <dbl> <dbl>
1 1 6 5
8.3. TESTE DE HIPÓTESE 151
2 2 6 4
3 3 7 7
4 4 4 3
5 5 3 5
6 6 9 8
7 7 7 5
8 8 6 6
2. Os preços por galçao (3,78 litros) de gasolina para carros de aluguel foram amostrados
em oito grandes aeroportos. Os dados relativos às empresas de carros de aluguel Hertz e
National são apresentados a seguir
# A tibble: 8 x 3
Aero Hertz National
<chr> <dbl> <dbl>
1 "Boston" 1.55 1.56
2 "Chicago" 1.62 1.59
3 " Los Angeles" 1.72 1.78
4 "Miami" 1.65 1.49
5 "Nova York (JFK)" 1.72 1.51
6 "Nova York (La Guardia)" 1.67 1.5
7 "Orange County" 1.68 1.77
8 "Washington" 1.52 1.41
Use α = 0, 05 para testar a hipótese de que não há diferença entre os preços médios populacionais
por galão em relação às duas empresas.
3. Na Western University, a média histórica das pontuações nos exames para obtenção de bolsas
de estudo correspondente às inscrições feitas por calouros é 900. Presume-se que o desvio
padrão histórico da população é σ = 180 seja conhecido. Anualmente, o vice-reitor usa uma
amostra das inscrições para determinar se a média da pontuação nos exames dos calouros se
modificou.
• Estabeleça as hipóteses.
• Qual é a estimação pontual e o intervalo de confiança de 95% da média populacional
nos exames se a seguinte amostra de tamanho 50 for observada.
# A tibble: 10 x 1
`matrix(x, 10, 5)`[,1] [,2] [,3] [,4] [,5]
<dbl> <dbl> <dbl> <dbl> <dbl>
1 799. 1120. 708. 977. 775.
2 859. 965. 861. 847. 863.
3 1181. 972. 715. 1061. 672.
4 913. 920. 769. 1058. 1290.
5 923. 800. 787. 1048. 1117.
6 1209. 1222. 596. 1024. 698.
7 983. 990. 1051. 1000. 827.
8 672. 546. 928. 889. 816.
9 776. 1026. 695. 845. 1040.
10 820. 815. 1126. 832. 885.
• Realize um teste de hipótese para verificar a suspeita do vice-reitor. Use α = 0, 05. Qual é a
sua conclusão?
4. Mensalmente o governo federal publica uma série de estatísticas sobre o número de pessoas
que estão desempregadas e a média de tempo em que estão desempregadas. Em relação a
novembro de 1998, o governo divulgou que a duração média nacional de desemprego era
14,6 semanas. O prefeito de Curitiba solicitou um estudo sobre a situação de desemprego
na cidade. Uma amostra de 50 habitantes desempregados em Curitiba incluiu dados sobre
a idade e o número de semanas em que estavam desempregados. O conjunto de dados é
152 CAPÍTULO 8. INFERÊNCIA ESTATÍSTICA
apresentado abaixo:
Idade.1.10. Semanas.1.10. Idade.11.20. Semanas.11.20. Idade.21.30.
1 36 9 32 7 30
2 34 7 47 8 38
3 34 7 27 8 34
4 43 11 36 9 30
5 33 12 37 12 36
6 43 6 35 9 34
7 25 13 40 7 35
8 28 10 47 8 37
9 36 9 32 4 32
10 37 4 29 6 30
Semanas.21.30. Idade.31.40. Semanas.31.40. Idade.41.50. Semanas.41.50.
1 7 36 10 32 10
2 6 41 7 44 5
3 11 37 14 33 7
4 5 33 14 28 8
5 10 41 10 45 11
6 8 40 6 35 12
7 9 38 6 41 11
8 5 36 9 31 9
9 9 31 6 34 13
10 6 42 8 30 8
• Use estatísticas descritivas para resumir os dados.
• Desenvolva uma estimação por intervalo de confiança de 95% da média de idade e semanas
desempregadas em Curitiba.
• Realize um teste de hipótese para determinar se a duração média do desemprego em Curitiba
é maior que a duração média nacional de 14,6 semanas. Use um nível de confiança de 0,01.
Qual a sua conclusão.
• Há uma relação entre a idade do individuo desempregado e o número de semanas de
desemprego? Explique.
Apêndice A
Documentos dinâmicos
A ideia geral de um documento dinâmico é a de que ele pode ser gerado a partir de um código-
fonte:
Como gerenciamos apenas o código-fonte do documento, ficamos livres de etapas manuais como
ter que refazer um gráfico ou uma tabela após qualquer alteração na análise.
Donald Knuth
O ideia básica por trás de documentos dinâmicos decorre diretamente do conceito de literate
programming (“programação letrada”), um paradigma concebido por Donald Knuth em 1984.
O objetivo da literate programming é criar um documento que “entrelaça” (mistura) texto e código.
O texto é legível para humanos e o código é legível para máquinas. A análise é descrita em uma
série de texto e blocos de código (code chunks). Cada bloco de código irá executar uma etapa da
análise, e estará diretamente associado ao texto explicativo acima ou abaixo do bloco.
Para podermos usar um sistema como esse, é necessário então uma linguagem de documentação
para humanos (e.g. LaTeX ou Markdown), e uma linguagem de programação que será compilada
com o documento (e.g. R ou Python).
Knuth criou inicialmente um sistema chamado WEB para fazer essa mistura dos seus textos em
TeX com a linguagem Pascal. Atualmente muitos outros sistemas existem para misturar códigos
com texto em várias linguagens de documentação e de programação.
153
154 APÊNDICE A. DOCUMENTOS DINÂMICOS
Posteriormente, os arquivos .tex gerados podem ser compilados com qualquer distribuição LaTeX,
(e.g TeXLive, MikTeX), por exemplo
pdflatex Exemplo0-Sweave.Rnw
pdflatex Exemplo0-knitr.Rnw
A.3 Markdown
Segundo o próprio criador da linguagem:
Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write
using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid
XHTML (or HTML).
John Gruber
• Markdown é uma linguagem de marcação simples para escrever textos
• O texto pode ser lido sem nenhum processamento, ou seja, da maneira como está escrito
• Outras linguagens de marcação como HTML e LaTeX requerem um grande número de tags
para formatar o texto, muitas vezes dificultando a leitura do código-fonte
• A proposta do Markdown é que o escritor se concentre no texto e não na formatação
• Pode ser convertido para vários outros formatos além de HTML
A.3. MARKDOWN 155
Cabeçalhos
# Título
## Sub-título
### Sub-sub-título
Itálico
*Este texto aparecerá em itálico.*
Este texto aparecerá em itálico.
Negrito
**Este texto aparecerá em negrito.**
Este texto aparecerá em negrito.
Listas não-ordenadas
- Primeiro item
- Segundo item
- Terceiro item
• Primeiro item
• Segundo item
• Terceiro item
Listas ordenadas
1. Primeiro item
2. Segundo item
3. Terceiro item
1. Primeiro item
2. Segundo item
3. Terceiro item
Sub-listas
Utilize 4 espaços para criar uma sub-lista:
1. Primeiro item
- Um sub-item
- Outro sub-item
2. Segundo item
3. Terceiro item
1. Primeiro item
• Um sub-item
• Outro sub-item
2. Segundo item
3. Terceiro item
156 APÊNDICE A. DOCUMENTOS DINÂMICOS
Links
Links para endereços Web podem ser inseridos com [texto](link):
O criador do conceito de "literate programming" foi
[Donald Knuth](https://en.wikipedia.org/wiki/Donald_Knuth).
O criador do conceito de “literate programming” foi Donald Knuth.
Devemos instalar o pacote [knitr](http://yihui.name/knitr) para poder
usar o R Markdown.
Devemos instalar o pacote knitr para poder usar o R Markdown.
Imagens
Para inserir uma imagem, a sintaxe é a mesma de inserir um link, mas com uma exclamação (!) na
frente: ![texto](imagem).
O link para a imagem pode ser um enderço Web:
![Logo do R](img/Rlogo-5.png)
Ou um endereço local:
![Logo do Markdown](img/markdown.png)
Parágrafo
Para criar parágrafos basta pular uma linha:
O criador do conceito de "literate programming" foi
[Donald Knuth](https://en.wikipedia.org/wiki/Donald_Knuth).
Códigos
Para apresentar códigos na própria linha, colocamos o texto entre duas crases ( ‘):
Para gerar números aleatórios de uma distribuição normal no R, use a
função `rnorm()`.
Para gerar números aleatórios de uma distribuição normal no R, use a função rnorm().
Para apresentar blocos de código, coloque o texto entre três crases seguidas (```) no início e no
final. O bloco
A.3. MARKDOWN 157
```
x <- rnorm(n = 10, mean = 100, sd = 5)
hist(x, main = "")
```
Irá gerar
x <- rnorm(n = 10, mean = 100, sd = 5)
hist(x, main = "")
Note que esse código não será interpretado, ele apenas será mostrado no texto. Esse será o papel
do R aqui mais adiante!
Tabelas
Tabelas podem ser escritas da seguinte forma:
Caracter | Permissão
---------|----------
`r` | Permissão de leitura (*read*)
`w` | Permissão de escrita (*write*)
`x` | Permissão de execução (*execute*)
`-` | Permissão desabilitada
Para gerar o seguinte resultado:
Caracter Permissão
r Permissão de leitura (read)
w Permissão de escrita (write)
x Permissão de execução (execute)
- Permissão desabilitada
Equações matemáticas
Equações matemáticas podem ser escritas em formato LaTeX. A página HTML resultante irá
renderizar as equações através do MathJax.
Equações na própria linha podem ser inseridas entre $:
Um modelo de regressão linear simples: $Y = \beta_0 + \beta_1 x + \epsilon$.
Um modelo de regressão linear simples: Y = β 0 + β 1 x + ϵ.
Equações podem ser exibidas entre $$ para ficarem centralizadas em uma linha própria:
$$
f(x;\mu,\sigma^2) = \frac{1}{\sigma\sqrt{2\pi}}
e^{ -\frac{1}{2}\left(\frac{x-\mu}{\sigma}\right)^2 }
$$
1 1 x −µ 2
f ( x; µ, σ2 ) = √ e− 2 ( σ )
σ 2π
# Um documento em Markdown
## Sobre o Markdown
## Mais um título
```
(x <- rnorm(30))
```
```
hist(x)
```
Para converter um documento Markdown em HTML (ou outro formato) é necessário um conversor.
O conversor padrão do Markdown é escrito em Perl, e pode ser integrado em diversas ferramentas,
mas não é apropriado para usuários comuns. Para testar a conversão do documento, copie e cole
na página do Dingus.
A.4 Pandoc
O Pandoc é um conversor extremamente versátil, capaz de converter diversos formatos, incluindo
Markdown para HTML.
Se o Pandoc estiver instalado no seu sistema (Unix) é possível converter o documento na linha de
comando (shell) com
pandoc -f markdown -t html Exemplo1.md -o Exemplo1.html
O pacote knitr possui a função pandoc() que é um wrapper para executar o programa pandoc no
sistema.
pandoc(input = "exemplos/Exemplo1.md", format = "html")
## Sobre o Markdown
## Mais um título
```{r}
160 APÊNDICE A. DOCUMENTOS DINÂMICOS
(x <- rnorm(30))
```
## Comentários
## Visualização
```{r}
hist(x)
```
Agora usamos o knitr, através da função knit() para compilar o documento .Rmd em um docu-
mento com sintaxe Markdown .md
knit("exemplos/Exemplo1-knitr.Rmd", output = "exemplos/Exemplo1-knitr.md")
| |.....................
label: unnamed-chunk-455
| |.....................
ordinary text without R code
| |.....................
label: unnamed-chunk-456
| |.....................
inline R code fragments
output file: exemplos/Exemplo1-knitr.md
[1] "exemplos/Exemplo1-knitr.md"
A.5. DOCUMENTOS DINÂMICOS COM MARKDOWN E R 161
# Um documento em Markdown
## Sobre o Markdown
## Mais um título
```r
(x <- rnorm(30))
[1] -0.50219235 0.13153117 -0.07891709 0.88678481 0.11697127 0.31863009
[7] -0.58179068 0.71453271 -0.82525943 -0.35986213 0.08988614 0.09627446
[13] -0.20163395 0.73984050 0.12337950 -0.02931671 -0.38885425 0.51085626
[19] -0.91381419 2.31029682 -0.43808998 0.76406062 0.26196129 0.77340460
[25] -0.81437912 -0.43845057 -0.72022155 0.23094453 -1.15772946 0.24707599
```
## Comentários
162 APÊNDICE A. DOCUMENTOS DINÂMICOS
## Visualização
```r
hist(x)
```
\begin{center}\includegraphics{figures/unnamed-chunk-456-1} \end{center}
No RStudio, esse pacote já vem instalado, assim como uma versão embutida do Pandoc.
| |.....................
label: unnamed-chunk-1-2
| |.....................
ordinary text without R code
| |.....................
label: unnamed-chunk-3-4
| |.....................
inline R code fragments
output file: Exemplo2-knitr.knit.md
/usr/bin/pandoc +RTS -K512m -RTS Exemplo2-knitr.knit.md --to html4 --from markdown+autolink_bare_uris+t
No RStudio, esse processo todo pode ser feito pelo botão Knit.
164 APÊNDICE A. DOCUMENTOS DINÂMICOS
A.6.1 Metadados
Uma opção interessante ao utilizar o Pandoc é incluir metados no formato YAML (Yet Another
Markup Language). Os metadados em YAML são escritos em formato de lista aninhada, e o Pandoc
usa essas informações para incluir, por exemplo, título, autor, e data em um documento.
A opção mais importante para o rmarkdown é o campo output, que permite especificar o formato
desejado de saída, o mesmo especificado no argumento output_format = da função render().
Os metadados em YAML são colocados sempre no início de um documento, e são delimitados por
---. Um exemplo típico seria:
---
title: "Meu primeiro documento em R Markdown"
author: "Fernando Mayer"
date: "Abril, 2018"
output: html_document
---
Com isso, não é mais necessário especificar o argumento output_format = na chamada da função
render().
Veja o arquivo Exemplo1-yaml.Rmd. Para renderizar esse aquivo, usamos:
render("exemplos/Exemplo1-yaml.Rmd")
| |.....................
label: unnamed-chunk-1-2
| |.....................
ordinary text without R code
| |.....................
label: unnamed-chunk-3-4
| |.....................
inline R code fragments
output file: Exemplo1-yaml.knit.md
/usr/bin/pandoc +RTS -K512m -RTS Exemplo1-yaml.knit.md --to html4 --from markdown+autolink_bare_uris+te
– slidy_presentation
– beamer_presentation
Apresentações em slides HTML podem ser geradas em diversos formatos, um deles é o ioslides
render("exemplos/Exemplo1-yaml.Rmd",
output_format = "ioslides_presentation",
output_file = "Exemplo1-yaml-ioslides.html")
Tabelas podem ser também geradas automaticamente a partir de resultados de funções do R. Para
gerar uma tabela a partir de um objeto do R, podemos usar a função knitr::kable(). Para isso,
também é necesário utilizar a opção results = "asis" no chunk, para que o resultado seja tratado
como texto literal em Markdown.
166 APÊNDICE A. DOCUMENTOS DINÂMICOS
A.6.4 Citações
Também é possível escrever documentos que com referências bibliográficas. Isso é possível
pois o Pandoc suporta arquivos BibTeX (.bib), que é o formato padrão de armazenamento e
gerenciamento de referências no LaTeX.
Para isso, basta então especificar o arquivo .bib no YAML com a tag:
bibliography: referencias.bib
As citações são então feitas com @<identificador>. Veja o arquivo Exemplo3-knitr.Rmd.
render("exemplos/Exemplo3-knitr.Rmd", output_format = "all")
Dessa forma serão gerados 3 formatos diferentes: HTML, PDF e MS Word. Note que o tema usado
para o HTML (journal) é uma possibilidade entre algumas disponíveis em https://bootswatch.c
om/.
[1] TRUE
Isso criará um script R Exemplo3-knitr.R com apenas os códigos presentes nos chunks do docu-
mento.
Nesta sessão vamos abordar como funcionam os métodos como definidos pelo sistema S3, por
ser o mais utilizado na prática para se criar novas funções no R. Para saber mais sobre os outros
métodos, consulte o livro Advanced R.
Vamos entender como uma função genérica pode ser criada através de um exemplo. Usando
a função methods(), podemos verificar quais métodos estão disponíveis para uma determinada
função, por exemplo, para a função mean():
methods(mean)
[1] mean.Date mean.default mean.difftime mean.POSIXct
[5] mean.POSIXlt mean.quosure* mean.vctrs_vctr*
see '?methods' for accessing help and source code
O resultado são expressões do tipo mean.<classe>, onde <classe> é uma classe de objeto como
aquelas vistas anteriormente. Isso significa que a função mean(), quando aplicada à um objeto
da classe Date, por exemplo, pode ter um comportamento diferente quando a mesma função for
aplicada à um objeto de outra classe (numérica).
169
170 APÊNDICE B. PROGRAMAÇÃO ORIENTADA A OBJETOS
set.seed(1)
vec <- rnorm(100)
class(vec)
[1] "numeric"
e queremos calcular sua média. Basta aplicar a função mean() nesse objeto para obtermos o
resultado esperado
mean(vec)
[1] 0.1088874
Mas isso só é possível porque existe um método definido espcificamente para um vetor da classe
numeric, que nesse caso é a função mean.default. A função genérica nesse caso é a mean(), e a
função método é a mean.default. Veja que não precisamos escrever o nome inteiro da função
genérica para que ela seja utilizada, como por exemplo,
mean.default(vec)
[1] 0.1088874
Uma vez passado um objeto para uma função, é a classe do objeto que irá definir qual método
utilizar, de acordo com os métodos disponíveis. Veja o que acontece se forçarmos o uso da função
mean.Date() nesse vetor
mean.Date(vec)
[1] "1970-01-01"
O resultado não faz sentido pois ele é específico para um objeto da classe Date.
Pode-se ainda alterar a classe de um objeto, que passa a ser tratado pelo método associado a esta
classe, se houver.
class(vec) <- "Date"
mean(vec)
[1] "1970-01-01"
Em S3 um objeto pode ter mais de uma classe e neste caso a procura por método segue a ordem
de especificação. Procura-se, sequencialmente, métodos para todos as classes definidas. Veja esta
sequência de três atribuições de classes.
class(vec) <- c("numeric", "Date")
mean(vec)
[1] "1970-01-01"
class(vec) <- c("Date", "numeric")
mean(vec)
[1] "1970-01-01"
class(vec) <- c("foo", "Date")
mean(vec)
[1] "1970-01-01"
Em todos casos foi processada o método mean.Date(). Na primeira e terceira porque não existe
método específico para classes numeric ou foo. Na segunda porque Date era a primeira classe do
objeto para qual há um método específico.
Tudo isso acontece por causa de um mecanismo chamado de despacho de métodos (method
dispatch), que é responsável por identificar a classe do objeto e utilizar (“despachar”) a função
método correta para aquela classe. Toda função genérica possui a mesma forma: uma chamada
para a função UseMethod(), que especifica o nome genérico e o objeto a ser despachado. Por
exemplo, veja o código fonte da função mean()
mean
function (x, ...)
UseMethod("mean")
171
<bytecode: 0x55b631ed6590>
<environment: namespace:base>
Agora veja o código fonte da função mean.default, que é o método específico para vetores numéri-
cos
mean.default
function (x, trim = 0, na.rm = FALSE, ...)
{
if (!is.numeric(x) && !is.complex(x) && !is.logical(x)) {
warning("argument is not numeric or logical: returning NA")
return(NA_real_)
}
if (isTRUE(na.rm))
x <- x[!is.na(x)]
if (!is.numeric(trim) || length(trim) != 1L)
stop("'trim' must be numeric of length one")
n <- length(x)
if (trim > 0 && n) {
if (is.complex(x))
stop("trimmed means are not defined for complex data")
if (anyNA(x))
return(NA_real_)
if (trim >= 0.5)
return(stats::median(x, na.rm = FALSE))
lo <- floor(n * trim) + 1
hi <- n + 1 - lo
x <- sort.int(x, partial = unique(c(lo, hi)))[lo:hi]
}
.Internal(mean(x))
}
<bytecode: 0x55b6322a4058>
<environment: namespace:base>
Agora suponha que você ddeseja criar uma função que calcule a média para um objeto de uma
classe diferente daquelas previamente definidas. Por exemplo, suponha que você quer que a
função mean() retorne a média das linhas de uma matriz.
set.seed(1)
mat <- matrix(rnorm(50), nrow = 5)
mean(mat)
[1] 0.1004483
O resultado é a média de todos os elementos, e não de cada linha. Nesse caso, podemos definir
nossa própria função método para fazer o cálculo que precisamos. Por exemplo:
mean.matrix <- function(x, ...) rowMeans(x)
Uma função método é sempre definida dessa forma: <funçãogenérica>.<classe>. Agora podemos
ver novamente os métodos disponíveis para a função mean()
methods(mean)
[1] mean.Date mean.default mean.difftime mean.matrix
[5] mean.POSIXct mean.POSIXlt mean.quosure* mean.vctrs_vctr*
see '?methods' for accessing help and source code
e simplesmente aplicar a função genérica mean() à um objeto da classe matrix para obter o resultado
que desejamos
172 APÊNDICE B. PROGRAMAÇÃO ORIENTADA A OBJETOS
class(mat)
[1] "matrix" "array"
mean(mat)
[1] 0.09544402 0.12852087 0.06229588 -0.01993810 0.23591872
Esse exemplo ilustra como é simples criar funções método para diferentes classes de objetos.
Poderíamos fazer o mesmo para objetos das classes data.frame e list
mean.data.frame <- function(x, ...) sapply(x, mean, ...)
mean.list <- function(x, ...) lapply(x, mean)
[[2]]
[1] 0.4946632
Obviamente esse processo todo é extremamente importante ao se criar novas funções no R. Pode-
mos tanto criar uma função genérica (como a mean()) e diversos métodos para ela usando classes
de objetos existentes, quanto (inclusive) criar novas classes e funções método para elas. Essa é uma
das grandes lberdades que o método S3 de orientação à objetos permite, e possivelmente um dos
motivos pelos quais é relativamente simples criar pacotes inteiros no R.
Apêndice C
Scripts
173