Vídeo economist-friendly para aqueles que querem começar no assunto:
Mês: janeiro 2016
Adivinhe a correlação
Manipulação de Textos – Parte 1
***
Parte do livro Introdução à análise de dados com R. Este trabalho está em andamento, o texto é bastante preliminar e sofrerá muitas alterações.
Quer fazer sugestões? Deixe um comentário abaixo ou, se você sabe utilizar o github, acesse aqui.
Não copie ou reproduza este material sem autorização.
Volte para ver atualizações!
***
Criando textos
No R, textos são representados por vetores do tipo character
. Você pode criar manualmente um elemento do tipo character
colocando o texto entre aspas, podendo ser tanto aspas simples (‘texto’) quanto aspas duplas (“texto”).
# criando um vetor de textos # aspas simples x1 <- 'texto 1' # aspas duplas x2 <- "texto 2"
Como já vimos, para saber se um objeto é do tipo texto você pode utilizar a função is.character()
e também é possível converter objetos de outros tipos para textos utilizando a função as.character()
.
# criando um vetor de inteiros x3 <- 1:10 # É texto? Não. is.character(x3)
## [1] FALSE
# Convertendo para texto x3 <- as.character(x3) # Agora é texto? Sim. is.character(x3)
## [1] TRUE
Operações com textos
Operações como ordenação e comparações são definidas para textos. A ordenação de um texto é feita de maneira lexicográfica, tal como em um dicionário.
# ordenação de letras sort(c("c", "d", "a", "f"))
## [1] "a" "c" "d" "f"
# ordenação de palavras # tal como um dicionário sort(c("cor", "casa", "árvore", "zebra", "branco", "banco"))
## [1] "árvore" "banco" "branco" "casa" "cor" "zebra"
Como a comparação é lexicográfica, é preciso tomar alguns cuidados. Por exemplo, o texto “2” é maior do que o texto “100”. Se por acaso seus números forem transformados em texto, você não vai receber uma mensagem de erro na comparação "2" > "100"
mas sim um resultado errado: TRUE
.
# CUIDADO! 2 > 100
## [1] FALSE
"2" > "100"
## [1] TRUE
# b > a "b" > "a"
## [1] TRUE
# A > a "A" > "a"
## [1] TRUE
# casa > banana "casa" > "banana"
## [1] TRUE
Imprimindo textos
Se você estiver usando o R
de modo interativo, chamar o objeto fará com que ele seja exibido na tela usando print()
.
# Imprime texto na tela print(x1)
## [1] "texto 1"
# Quando em modo interativo # Equivalente a print(x1) x1
## [1] "texto 1"
Se você não estiver usando o R
de modo interativo — como ao dar source()
em um script ou dentro de um loop — é preciso chamar explicitamente uma função que exiba o texto na tela.
# sem print não acontece nada for(i in 1:3) i # com print o valor de i é exibido for(i in 1:3) print(i)
## [1] 1 ## [1] 2 ## [1] 3
Existem outras opções para “imprimir” e formatar textos além do print()
. Uma função bastante utilizada para exibir textos na tela é a função cat()
(concatenate and print).
cat(x1)
## texto 1
cat("A função cat exibe o texto sem aspas:", x1)
## A função cat exibe o texto sem aspas: texto 1
Por padrão, cat()
separa os textos com um espaço em branco, mas é possível alterar este comportamento com o argumento sep
.
cat(x1, x2)
## texto 1 texto 2
cat(x1, x2, sep = " - ")
## texto 1 - texto 2
Outra funções úteis são sprintf()
e format()
, principalmente para formatar e exibir números. Para mais detalhes sobre as funções, olhar a ajuda ?sprintf
e ?format
.
# %.2f (float, 2 casas decimais) sprintf("R$ %.2f", 312.12312312)
## [1] "R$ 312.12"
# duas casas decimais, separador de milhar e decimal format(10500.5102, nsmall=2, big.mark=".", decimal.mark=",")
## [1] "10.500,51"
Caracteres especiais
Como fazemos para gerar um texto com separação entre linhas no R? Criemos a separação de linhas manualmente para ver o que acontece:
texto_nova_linha <- "texto com nova linha" texto_nova_linha
## [1] "texto\ncom nova linha"
Note que aparece um \n
no meio do texto. Isso é um caractere especial: \n
simboliza justamente uma nova linha. Quando você exibe um texto na tela com print()
, caracteres especiais não são processados e aparecem de maneira literal. Já se você exibir o texto na tela usando cat()
, os caracteres especiais serão processados. No nosso exemplo, o \n
será exibido como uma nova linha.
# print: \n aparece literalmente print(texto_nova_linha)
## [1] "texto\ncom nova linha"
# cat: \n aparece como nova linha cat(texto_nova_linha)
## texto ## com nova linha
Caracteres especiais são sempre “escapados” com a barra invertida \
. Além da nova linha (\n
), outros caracteres especiais recorrentes são o tab
(\t
) e a própria barra invertida, que precisa ela mesma ser escapada (\\
). Vejamos alguns exemplos:
cat("colocando uma \nnova linha")
## colocando uma ## nova linha
cat("colocando um \ttab")
## colocando um tab
cat("colocando uma \\ barra")
## colocando uma \ barra
cat("texto com novas linhas e\numa barra no final\n\\")
## texto com novas linhas e ## uma barra no final ## \
Para colocar aspas simples ou duplas dentro do texto há duas opções. A primeira é alternar entre as aspas simples e duplas, uma para definir o objeto do tipo character
e a outra servido literalmente como aspas.
# Aspas simples dentro do texto aspas1 <- "Texto com 'aspas' simples dentro" aspas1
## [1] "Texto com 'aspas' simples dentro"
# Aspas duplas dentro do texto aspas2 <- 'Texto com "aspas" duplas dentro' cat(aspas2)
## Texto com "aspas" duplas dentro
Outra opção é colocar as aspas como caracter expecial. Neste caso, não é preciso alternar entre aspas simples e duplas.
aspas3 <- "Texto com \"aspas\" duplas" cat(aspas3)
## Texto com "aspas" duplas
aspas4 <- 'Texto com \'aspas\' simples' cat(aspas4)
## Texto com 'aspas' simples
Utilidade das funções de exibição
Qual a utilidade de funções que exibam coisas na tela?
Um caso bastante comum é exibir mensagens durante a execução de alguma rotina ou função. Por exemplo, você pode exibir o percentual de conclusão de um loop a cada 25 rodadas:
for(i in 1:100){ # imprime quando o resto da divisão # de i por 25 é igual a 0 if(i %% 25 == 0){ cat("Executando: ", i, "%\n", sep = "") } # alguma rotina Sys.sleep(0.01) }
## Executando: 25% ## Executando: 50% ## Executando: 75% ## Executando: 100%
Outro uso frequente é criar métodos de exibição para suas próprias classes. Vejamos um exemplo simples de uma fução base do R
, a função rle()
, que computa tamanhos de sequências repetidas de valores em um vetor. O resultado da função é uma lista, mas ao exibirmos o objeto na tela, o print
não é igual ao de uma lista comum:
x <- rle(c(1,1,1,0)) # resultado é uma lista str(x)
## List of 2 ## $ lengths: int [1:2] 3 1 ## $ values : num [1:2] 1 0 ## - attr(*, "class")= chr "rle"
# print do objeto na tela # não é como uma lista comum x
## Run Length Encoding ## lengths: int [1:2] 3 1 ## values : num [1:2] 1 0
# tirando a classe do objeto # veja que o print agora é como uma lista comum unclass(x)
## $lengths ## [1] 3 1 ## ## $values ## [1] 1 0
Isso ocorre porque a classe rle
tem um método de print
próprio, print.rle()
:
print.rle <- function (x, digits = getOption("digits"), prefix = "", ...) { if (is.null(digits)) digits <- getOption("digits") cat("", "Run Length Encoding\n", " lengths:", sep = prefix) utils::str(x$lengths) cat("", " values :", sep = prefix) utils::str(x$values, digits.d = digits) invisible(x) }
Tamanho do texto
A função nchar()
retorna o número de caracteres de um elemento do tipo texto. Note que isso é diferente da função length()
que retorna o tamanho do vetor.
# O vetor x1 tem apenas um elemento length(x1)
## [1] 1
# O elemento do vetor x1 tem 7 caracteres # note que espaços em brancos contam nchar(x1)
## [1] 7
A função nchar()
é vetorizada.
# vetor do tipo character y <- c("texto 1", "texto 11") # vetor tem dois elementos length(y)
## [1] 2
# O primeiro elemento tem 7 caracteres # O segundo 8. nchar(y) # vetorizada
## [1] 7 8
Manipulando textos
Manipulação de textos é uma atividade bastante comum na análise de dados. O R possui uma série de funções para isso e suporta o uso de expressões regulares. Nesta seção veremos exemplos simples das principais funções de manipulação de textos. Na próxima seção abordaremos um pouco de expressões regulares.
Colando (ou concatenando) textos
A função paste()
é uma das funções mais úteis para manipulação de textos. Como o próprio nome diz, ela serve para “colar” textos.
# Colando textos tipo <- "Apartamento" bairro <- "Asa Sul" texto <- paste(tipo,"na", bairro ) texto
## [1] "Apartamento na Asa Sul"
Por default, paste()
separa os textos com um espaço em branco. Você pode alterar isso modificando o argumento sep
. Caso não queira nenhum espaço entre as strings, basta definir sep = ""
ou utilizar a função paste0()
. Como usual, todas essas funções são vetorizadas.
# separação padrão paste("x", 1:5)
## [1] "x 1" "x 2" "x 3" "x 4" "x 5"
# separando por ponto paste("x", 1:5, sep=".")
## [1] "x.1" "x.2" "x.3" "x.4" "x.5"
# sem separação paste("x", 1:5, sep ="")
## [1] "x1" "x2" "x3" "x4" "x5"
# sem separação, usando paste0. paste0("x", 1:5)
## [1] "x1" "x2" "x3" "x4" "x5"
Note que foram gerados 5 elementos diferentes nos exemplos acima. É possível “colar” todos os elementos em um único texto com a opção collapse()
.
paste("x", 1:5, sep="", collapse=" ")
## [1] "x1 x2 x3 x4 x5"
Separando textos
Outra atividade frequente em análise de dados é separar um texto em elementos diferentes. Por exemplo, suponha que você tenha que trabalhar com um conjunto de números, mas que eles estejam em um formato de texto separados por ponto e vírgula:
dados <- "1;2;3;4;5;6;7;8;9;10" dados
## [1] "1;2;3;4;5;6;7;8;9;10"
Com a função strsplit()
é fácil realizar essa tarefa:
dados_separados <- strsplit(dados, split=";") dados_separados
## [[1]] ## [1] "1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
Note que o resultado da função é uma lista. Agora é possível converter os dados em números e trabalhar normalmente.
# convertendo o resultado em número dados_separados <- as.numeric(dados_separados[[1]]) # agora é possível trabalhar com os números # média mean(dados_separados)
## [1] 5.5
# soma sum(dados_separados)
## [1] 55
Encontrando partes de um texto
Quando você estiver trabalhando com suas bases de dados, muitas vezes será preciso encontrar certas palavras ou padrões dentro do texto. Por exemplo, imagine que você tenha uma base de dados de aluguéis de apartamentos e você gostaria de encontrar imóveis em um certo endereço. Vejamos este exemplo com dados online de aluguel em Brasília.
# Carrega arquivo de anúncios de aluguel (2014) arquivo <- url("https://dl.dropboxusercontent.com/u/44201187/aluguel.rds") con <- gzcon(arquivo) aluguel <- readRDS(con) close(con)
Vejamos a estrutura da nossa base de dados:
str(aluguel)
## 'data.frame': 2612 obs. of 5 variables: ## $ bairro : chr "Asa Norte" "Asa Norte" "Sudoeste" "Asa Norte" ... ## $ endereco: chr "CLN 310 BLOCO A " "SCRN 716 BLOCO G ENT. 26 3º ANDAR" "QMSW 06 ED.STUDIO IN" "CLN 406 BLOCO D - ED. POP CENTER (APARTAMENTO)" ... ## $ quartos : num 1 1 1 1 1 1 1 1 1 1 ... ## $ m2 : num 22.9 26 30 30 30 30 30 30 28 30 ... ## $ preco : num 650 750 800 800 800 820 850 850 850 860 ... ## - attr(*, "na.action")=Class 'omit' Named int [1:120] 15943 16001 17264 17323 18600 18659 19935 19996 21278 22617 ... ## .. ..- attr(*, "names")= chr [1:120] "15943" "16001" "17264" "17323" ...
Temos mais de 2 mil anúnciso, como encontrar aqueles apartamentos que queremos, como, por exemplos, os que contenham “CLN 310” no endereço? Neste caso você pode utilizar a função grep()
para encontrar padrões dentro do texto. A função retornará o índice das observações que contém o texto:
busca_indice <- grep(pattern = "CLN 310", aluguel$endereco) busca_indice
## [1] 1 1812
aluguel[busca_indice, ]
## bairro endereco quartos m2 preco ## 1 Asa Norte CLN 310 BLOCO A 1 22.9 650 ## 1812 Asa Norte CLN 310 BLOCO E ENTRADA 52 SALA 216 0 30.0 900
Uma variante da função grep()
é a função grepl()
, que realiza a mesma coisa, mas ao invés de retornar um índice numérico, retorna um vetor lógico:
busca_logico <- grepl(pattern = "CLN 310", aluguel$endereco) str(busca_logico)
## logi [1:2612] TRUE FALSE FALSE FALSE FALSE FALSE ...
aluguel[busca_indice, ]
## bairro endereco quartos m2 preco ## 1 Asa Norte CLN 310 BLOCO A 1 22.9 650 ## 1812 Asa Norte CLN 310 BLOCO E ENTRADA 52 SALA 216 0 30.0 900
Nossa busca é útil, mas ainda é simples. Quando aprendermos expressões regulares, essas buscas ficarão bem mais poderosas. Lá também aprenderemos outras funções como regexpr()
, gregexpr()
, regexec()
e regmatches()
.
Substituindo partes de um texto
A função sub()
substitui o primeiro padrão (pattern
) que encontra:
texto2 <- paste(texto, ", Apartamento na Asa Norte") texto2
## [1] "Apartamento na Asa Sul , Apartamento na Asa Norte"
# Vamos substituir "apartamento" por "Casa" # Mas apenas o primeiro caso sub(pattern = "Apartamento", replacement = "Casa", texto2)
## [1] "Casa na Asa Sul , Apartamento na Asa Norte"
Já a função gsub()
substitui todos os padrões que encontra:
# Vamos substituir "apartamento" por "Casa" # Agora em todos os casos gsub(pattern="Apartamento", replacement="Casa", texto2)
## [1] "Casa na Asa Sul , Casa na Asa Norte"
Você pode usar as funções sub()
e gsub()
para “deletar” partes indesejadas do texto, basta colocar como replacement
um caractere vazio ""
. Um exemplo bem corriqueiro, quando se trabalha com com nomes de arquivos, é a remoção das extensões:
# nomes dos arquivos arquivos <- c("simulacao_1.csv","simulacao_2.csv") # queremos eliminar a extensão .csv # note que o ponto precisa ser escapado nomes_sem_csv <- gsub("\\.csv", "", arquivos) nomes_sem_csv
## [1] "simulacao_1" "simulacao_2"
Extraindo partes específicas de um texto
Às vezes você precisa extrair apenas algumas partes específicas de um texto, em determinadas posições. Para isso você pode usar as funções substr()
e substring()
.
Para essas funções, você basicamente passa as posições dos caracteres inicial e final que deseja extrair.
# extraindo caracteres da posição 4 à posição 8 x <- "Um texto de exemplo" substr(x, start = 4, stop = 8)
## [1] "texto"
É possível utilizar essas funções para alterar partes específicas do texto.
# substituindo caracteres da posição 4 à posição 8 substr(x, start = 4, stop = 8) <- "TEXTO" x
## [1] "Um TEXTO de exemplo"
A principal diferença entre substr()
e substring()
é que a segunda permite você passar vários valores iniciais e finais:
# pega caracteres de (4 a 8) e de (10 a 11) substring(x, first = c(4, 10), last = c(8, 11))
## [1] "TEXTO" "de"
# pega caracteres de (1 ao último), (2 ao último) ... substring("abcdef", first = 1:6)
## [1] "abcdef" "bcdef" "cdef" "def" "ef" "f"
**** A SEGUIR ****
- expressões regulares
- regmatches, regexpr, gregexpr, regexc
- fuzzy matching
- stringr
Simulações – Parte 1
***
Parte do livro Introdução à análise de dados com R. Este trabalho está em andamento, o texto é bastante preliminar e sofrerá muitas alterações.
Quer fazer sugestões? Deixe um comentário abaixo ou, se você sabe utilizar o github, acesse aqui.
Não copie ou reproduza este material sem autorização.
Volte para ver atualizações!
***
Distribuições de probabilidade
O R vem com diversas funções para simular distribuições estatísticas. Em geral essas funções têm o seguinte formato: rnomedadistribuicao
, dnomedadistribuicao
, pnomedadistribuicao
ou qnomedadistribuicao
. Mais detalhadamente, a primeira letra da função, que pode ser r
, d
, p
ou q
, indica, respectivamente, se a função é: (i) geradora de variáveis aleatórias; (ii) de densidade; (iii) de distribuição acumulada; ou, (iv) de quantil. E, logo em seguida, temos um nome abreviado da distribuição de probabilidade.
Dessa forma, por exemplo, se você quiser gerar dados aleatórios de uma distribuição normal a função para tanto é rnorm
(r
pois trata-se de um gerador de números aleatórios e norm
pois trata-se da distribuição normal).
Na tabela abaixo temos várias das distribuições presentes de forma nativa no R:
Sementes para as simulações
Durante todo o livro nós utilizamos o comando set.seed
quando fizemos simulações. Isso garante que os resultados obtidos possam ser reproduzidos em qualquer computador.
Veja que, se rodarmos o comando rnorm
sem definir o estado do gerador de números aleatórios com set.seed,
você não conseguirá obter os mesmos valores em seu computador:
rnorm(1) ## [1] 0.5748481 rnorm(1) ## [1] 0.4052027
Contudo, uma vez definida a semente, obteremos sempre o mesmo valor:
set.seed(1) rnorm(1) ## [1] -0.6264538 set.seed(1) rnorm(1) ## [1] -0.6264538
O básico de r
,d
p
,q
com a distribuição normal
Para começar a entender o que cada função do R
faz, trabalhemos cada uma delas usando a distribuição normal. A função densidade da distribuição normal-padrão (uma normal com média zero e desvio-padrão igual a um) tem a seguinte forma:
A primeira dúvida que alguém pode ter é: como extrair valores aleatoriamente desta distribuição? Vejamos:
# semente para reproducibilidade set.seed(2) # gerando 5 variáveis aleatórias da distribuição Normal(0,1) x1 <- rnorm(5) x1 ## [1] -0.89691455 0.18484918 1.58784533 -1.13037567 -0.08025176
Com o comando acima geramos 5 valores da normal-padrão.
Mas e se quisermos valores de uma normal com média e desvio-padrão diferentes? Para isso, basta mudarmos os parâmetros mean
sd
(standard deviation) da função rnorm
:
# semente para reproducibilidade set.seed(2) # gerando 6 variáveis aleatórias da distribuição Normal(10,2) x2 <- rnorm(5, mean = 10, sd = 2) x2 ## [1] 8.206171 10.369698 13.175691 7.739249 9.839496
Com o código acima, geramos 5 valores de uma distribuição normal com média 10 e desvio-padrão 2. Entretanto, você também poderia ter gerado os mesmos valores a partir da normal-padrão: x2
nada mais é do que x1*2 + 10
:
all.equal(x1*2 + 10, x2) ## [1] TRUE
Saber como tranformar uma distribuição em outra é algo bastante útil e pode poupar bastante tempo na hora de fazer simulações. Veremos exemplos práticos disso nos exercícios.
Às vezes, ao invés de gerar números aleatórios, nós temos valores que, presume-se, foram gerados por uma distribuição normal, e queremos saber a densidade ou a probabilidade associada àquele valor.
Por exemplo, supondo uma distribuição normal-padrão, qual a probabilidade de x ser menor do que 1.65? Isto é, queremos saber o valor da área hachurada da curva de densidade:
Para responder essa pergunta, você vai usar a função pnorm
:
# probabilidade de X < 1.65 pnorm(1.65) ## [1] 0.9505285
Note que aproximadamente 95% dos valores da normal-padrão estão abaixo de 1.65. E se quisermos fazer a pergunta contrária: qual o valor de x tal que 95% dos valores da curva estejam abaixo deste valor? Para isso usamos a função qnorm
:
qnorm(0.95) ## [1] 1.644854
Para calcularmos os valores da função densidade utilizamos a função dnorm
. Vejamos como fazer isso reproduzindo os gráficos da função densidade exibidos anteriormente:
# Sequencia de -3 a 3 igualmente espaçada e # com valores redondos x <- pretty(c(-3, 3), 1000) # Função densidade de -3 a 3 y <- dnorm(x) # Gráfico Função Densidade plot.new() plot.window(xlim=range(x), ylim=range(y)) axis(1); axis(2) polygon(x, y, col = "lightblue") title(main = "Distribuição Normal \nFunção Densidade") # Gráfico Função Densidade Hachurado plot.new() plot.window(xlim=range(x), ylim=range(y)) axis(1);axis(2) polygon(x, y, col = "lightblue") title(main = "Distribuição Normal \nFunção Densidade") z <- 1.65 lines(c(z, z), y = c(dnorm(-3), dnorm(z))) polygon(c(x[x<=z], z), c(y[x<=z], min(y)), density = 10, angle = 45) text(x = z + 0.3, y = dnorm(z) + 0.01,"1.65")
Exemplo 1: Teorema Central do Limite
O teorema cental do limite nos diz que, sob certas condições de regularidade (como variância finita), quanto mais observações tivermos, a distribuição amostral da média de uma variável aleatória será aproximadamente normal, independentemente do formato original da distribuição.
Vejamos um exemplo com a distribuição exponencial. A função densidade da exponencial pode ser escrita como , com média
e desvio padrão
.
Para nosso exemplo, tomaremos . Assim, temos que
e, segundo o teorema central do limite, a variável
tende a uma normal-padrão (
é a média amostral de
)
Note que o formato do histograma da exponencial () não se parece com o formato de sino da distribuição normal, que vimos na seção anterior:
# semente para reproducibilidade set.seed(10) # geramos 1000 variávels aleatórias de uma distribuição exponencial x <- rexp(n = 1000, rate = 1) # histograma hist(x, col = "lightblue", main = "Distribuição Exponencial", freq = F)
Entretanto, o que ocorre com a distribuição de quando aumentamos o valor de
? Façamos uma simulação para seis valores de tamanho amostral diferentes: 1, 5, 10, 100, 500 e 1000.
# Simulacõees TCL - exponencial # semente para reproducibilidade set.seed(100) # diferentes tamanhos amostrais que iremos simular n <- c(1, 5, 10, 100, 500, 1000) # número de replicações para cada n n.rep <- 1000 ## simulações sims <- lapply(n, function(n) replicate(n.rep, (mean(rexp(n)) - 1)*sqrt(n)))
Na prática, a simulação toda foi feita com apenas uma linha, combinando o lapply
com replicate
. Explicando melhor o código acima, com o comando lapply(n, ...)
estamos dizendo para o R
que iremos aplicar uma função para cada valor de n
. Mas que função estamos aplicando? Neste caso, a função anômima function(n) replicate(n.rep, (mean(rexp(n)) - 1)*sqrt(n))
. Mais detalhadamente, com o comando replicate(n.rep, (mean(rexp(n)) - 1)*sqrt(n)))
repetimos n.rep
vezes a expressão (mean(rexp(n)) - 1)*sqrt(n))
, que nada mais é do que a média padronizada de uma exponencial () de tamanho amostral
n
multiplicada por
O resultado de nossas simulações está na lista sims
que tem a seguinte estrutura:
## nomes para as listas names(sims) <- as.character(n) ## estrutura do resultado str(sims) ## List of 6 ## $ 1 : num [1:1000] -0.0758 -0.2762 -0.8954 2.0974 -0.3752 ... ## $ 5 : num [1:1000] -0.25122 0.00986 -1.19437 -1.29553 1.14441 ... ## $ 10 : num [1:1000] -0.237 1.042 0.523 1.228 0.929 ... ## $ 100 : num [1:1000] -0.303 0.43 -0.25 -0.339 -0.659 ... ## $ 500 : num [1:1000] 2.072 0.239 -0.91 0.421 -0.353 ... ## $ 1000: num [1:1000] -1.0039 0.0282 -0.0259 -0.0925 -0.9421 ...
Perceba que temos uma lista com 6 elementos, um para cada n
diferente. Você pode acessar os resultados da lista ou pelo índice ou pelo nome do elemento:
# pega os resultados de n = 1000 sims[[6]] sims[["1000"]]
Vejamos todos os resultados da simulação ao mesmo tempo em um gráfico. O histograma dos valores simulados estão em azul claro e a função densidade da normal-padrão em vermelho.
Quando n = 1
, a distribuição segue o mesmo formato da exponencial. Todavia, note que a convergência para a distribuição normal ocorre bem rapidamente neste exemplo. Com n = 100
as diferenças entre a normal e os dados simulados já se tornam bastante pequenas.
Fizemos o gráfico acima com o ggplot2
:
library(ggplot2) library(reshape2) # Prepara base de dados para gráfico ## Transforma em data.frame sims.df <- as.data.frame(do.call("cbind", sims)) ## Empilha para o ggplot2 sims.df <- melt(sims.df, variable.name = "n", value.name = "Valor") sims.df$n <- paste("n =", sims.df$n) sims.df$n <- factor(sims.df$n, levels = unique(sims.df$n)) # Histogramas vs Densidade Normal (ggplot2) ggplot(sims.df, aes(x = Valor)) + # Histograma geom_histogram(aes(y = ..density..), fill = "lightblue", col = "black", binwidth = 0.5) + xlim(c(-6, 6)) + # Uma faceta para cada n facet_wrap(~n) + ## Densidade da normal(0,1) para comparação stat_function(fun = dnorm, col = "red", size = 0.8) + # Titulo principal e do eixo Y ggtitle("Teorema Central do Limite\nDistribuição Expoencial") + ylab("Densidade") + ## Tema em preto e branco theme_bw()
Sua vez!
Nós simulamos o teorema central do limite usando funções da família apply
: lapply
e replicate
. Isso permite nos expressarmos de maneira bastante concisa, em apenas uma linha.
Como você faria a mesma simulação usando loops? Compare os resultados e veja se eles são idênticos.
# Resposta sugerida # Com FOR ## para reproducibilidade set.seed(100) ## tamanho amostral n <- c(1, 5, 10, 100, 500, 1000) ## numero de replicacoes n.rep <- 1000 # lista para armazenar os resultados para cada n sims.for <- vector("list", length(n)) ## começo do for ## faremos n.rep replicacoes para cada n ## para cada i de n for (i in seq_along(n)) { # crie um vetor temporario para realizar n.rep repetições temp <- numeric(n.rep) # realiza n.rep repetições de (mean(rexp(n[i])) - 1)*sqrt(n[i]) for (j in 1:n.rep) { temp[j] <- (mean(rexp(n[i])) - 1)*sqrt(n[i]) } # guarda resultado na lista sims.for[[i]] <- temp } # nomes para os resultados da lista names(sims.for) <- n # compara com simulação anterior all.equal(sims, sims.for) ## [1] TRUE