Os vídeos da conferência do RStudio já estão disponíveis aqui.
RStudio
Novo preview do RStudio
RStudio finalmente permite editor de texto em janela separada!
Quem usa o RStudio sabe há quanto tempo aguardamos isso! Provavelmente era uma das sugestões mais pedidas. E agora está disponível no preview release.
Introdução ao dplyr
***
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!
***
Eficiente e intuitivo
Com as funções da família apply
e similares, você consegue fazer praticamente tudo o que você precisa para explorar os dados e deixá-los no(s) formato(s) necessário(s) para análise. E é importante você ser exposto a essas funções para se familiarizar com o ambiente base do R.
Entretanto, muitas vezes essas funções podem ser pouco intuitivas para o iniciante e, além disso, deixar a desejar em performance. Como alternativa, existe um pacote bastante rápido para manipulação de data.frame
s e com sintaxe muito intuitiva chamado dplyr
. É provável que para o grosso de suas necessidades o dplyr
seja a solução mais rápida e mais eficiente.
Se você ainda não tem o dplyr
instalado na sua máquina, rode o seguinte comando.
install.packages("dplyr", repos = "http://cran.r-project.org")
Depois carregue o pacote:
library(dplyr)
Nesta seção continuaremos utilizando a base de dados de web scraping de imóveis utilizada na seção anterior (você pode baixar aqui).
Funções principais
As funções do dplyr
são todas em formas de verbo e, se você sabe um pouco de inglês, são razoavelmente auto-explicativas. Vamos ver aqui as seis principais funções que, em conjunto, já te permitem fazer bastante coisa. Todas as funções possuem a mesma estrutura: o primeiro argumento é o data.frame
que você quer manipular e os argumentos subsequentes dizem o que fazer com os dados. Além disso, as funções do dplyr
sempre retornam um data.frame
, isto é, ela não vai tentar simplificar o resultado para um vetor ou outro tipo de objeto.
- filter: filtra um
data.frame
com vetores lógicos. Em outras palavras, deixa apenas as linhas que satisfazem a certo critério. Por exemplo, nos nossos dados de imóveis, poderíamos filtrar somente aqueles anúncios de aluguel com valores de preço por metro quadrado menores ou maiores do que determinado nível.
# com dplyr filter(dados, pm2 > 96, tipo == "aluguel") # equivalente com R base dados[dados$pm2 > 96 & dados$tipo == "aluguel", ]
- select: seleciona uma ou mais colunas de um
data.frame
. Por exemplo, poderíamos selecionar a coluna de preços e quartos do anúncio.
# com dplyr select(dados, preco, quartos) # equivalente com R base dados[, c("preco", "quartos")]
- mutate: cria uma nova coluna. Por exemplo, vamos criar a coluna
pm2
comopreco/m2
.
# com dplyr dados <- mutate(dados, pm2 = preco/m2) # equivalente com R base dados$pm2 <- dados$preco/dados$m2
- arrange: orderna o
data.frame
com base em uma coluna. Por exemplo, ordernar observações dos apartamentos segundo os preços por metro quadrado.
# com dplyr arrange(dados, pm2) # equivalente com R base dados[order(dados$pm2), ]
Os próximos dois verbos são group_by
e summarise
que, em geral, são utilizados em conjunto com outros verbos. Deixaremos, assim, para ver exemplos com essas estruturas logo a seguir, quando conectarmos todos os verbos do dplyr
com o operador %>%
.
- group_by: agrupa um
data.frame
segundo um vetor de categorias. “Agrupar” aqui quer dizer que todas as operações subsequentes serão feitas separadas por grupos. É equivalente aosplit
, que vimos antes. - summarise: o
summarise
transforma um vetor com vários números (por exemplo, um vetor de preços) em um único número de acordo com uma função (por exemplo, preço médio ou preço mediano).
Conectando tudo com %>%
Até agora talvez você não tenha visto muita vantagem em utilizar o dplyr
. Escrever filter(dados, pm2 > 96, tipo == "aluguel")
pode ser mais intuitivo do que dados[dados$pm2 > 96 & dados$tipo == "aluguel", ]
mas talvez não tanto assim. A grande vantagem do pacote e das funções em formas de verbo aparece quando concatenamos várias operações em sequência com o auxílio do operador %>%
.
O dplyr
foi desenhado para trabalhar com o pipe operator %>%
do pacote magritrr
. Basicamente, o operador faz com que você possa escrever x %>% f()
ao invés de f(x)
. Pode não parecer muito, mas na prática esse pequeno detalhe tem uma grande utilidade: você vai poder escrever o código de manipulação dos dados da mesma forma que você pensa nas atividades.
Pense numa receita que tenha as seguintes instruções: junte os igredientes, misture e leve ao forno. Na forma usual do R, tais instruções provavelmente teriam a seguinte forma:
forno(misture(junte(ingredientes)))
Note que temos que pensar “de dentro para fora”. O primeiro comando que lemos é forno
que, na verdade, é a última operação que será realizada! Com o pipe operator, por outro lado, você escreveria algo mais ou menos assim:
ingredientes %>% junte %>% misture %>% forno
É quase igual a ler instruções verbais da receita. Parece mais intuitivo, não?
Vejamos exemplos de manipulações de dados com o dplyr
usando nossa base de dados de imóveis.
Filtrando, selecionando e criando colunas
Instrução: Filtre apenas os dados coletados de apartamento, selecione as colunas bairro e preco, crie uma coluna pm2 = preco/m2
, ordene os dados de forma decrescente em pm2
e mostre apenas as 6 primeiras linhas (head
).
Código:
dados %>% filter(imovel=="apartamento") %>% select(bairro, preco, m2) %>% mutate(pm2 = preco/m2) %>% arrange(desc(pm2)) %>% head
## Source: local data frame [6 x 4] ## ## bairro preco m2 pm2 ## (chr) (dbl) (dbl) (dbl) ## 1 Asa Sul 4259579 215.72 19745.87 ## 2 Asa Sul 4259579 215.72 19745.87 ## 3 Asa Sul 4259579 215.72 19745.87 ## 4 Asa Sul 4259579 215.72 19745.87 ## 5 Asa Sul 4259579 215.72 19745.87 ## 6 Asa Sul 4259579 215.72 19745.87
Agrupando e sumarizando
Instrução: Filtre apenas os dados de venda de apartamento. Agrupe os dados por bairro. Calcule as medianas do preco
, m2
e pm2
, bem como o número de observações. Filtre apenas os grupos com mais de 30 observações. Ordene de forma decrescente com base na mediana de pm2
.
Código:
dados %>% filter(imovel=="apartamento", tipo=="venda") %>% group_by(bairro) %>% summarise(Mediana_Preco = median(preco), Mediana_M2 = median(m2), Mediana_pm2 = median(pm2), Obs = length(pm2)) %>% filter(Obs > 30) %>% arrange(desc(Mediana_pm2))
## Source: local data frame [6 x 5] ## ## bairro Mediana_Preco Mediana_M2 Mediana_pm2 Obs ## (chr) (dbl) (dbl) (dbl) (int) ## 1 Sudoeste 850000 86.00 9689.922 20356 ## 2 Noroeste 950000 100.90 9654.000 36610 ## 3 Asa Sul 950000 107.00 9066.667 35241 ## 4 Asa Norte 780000 94.00 9000.000 40023 ## 5 Lago Norte 470000 57.55 8329.250 5938 ## 6 Lago Sul 488307 88.55 5199.120 477
Exercícios de fixação
Considerando a base de dados, responda:
- Qual o bairro com o maior preço mediano de venda?
- Qual o bairro com o maior preço por m2 de venda?
- Qual o bairro com o maior preço mediano de venda para apartamentos?
- Qual o bairro com o maior preço mediano de venda para lojas?
Soluções:
# Qual o bairro com o maior preço mediano de venda? dados %>% filter(tipo == "venda") %>% # Filtra tipo "venda" group_by(bairro) %>% # agrupa por bairro summarise(mediana = median(preco)) %>% # calcula mediana do preco arrange(desc(mediana)) # ordena de forma decrescente
## Source: local data frame [6 x 2] ## ## bairro mediana ## (chr) (dbl) ## 1 Lago Sul 2800000.0 ## 2 Noroeste 950000.0 ## 3 Asa Sul 834572.1 ## 4 Lago Norte 679000.0 ## 5 Asa Norte 600000.0 ## 6 Sudoeste 520000.0
# Qual o bairro com o maior preço por m2 de venda? dados %>% filter(tipo == "venda") %>% # Filtra tipo "venda" group_by(bairro) %>% # agrupa por bairro summarise(mediana = median(pm2)) %>% # calcula mediana do pm2 arrange(desc(mediana)) # ordena de forma decrescente
## Source: local data frame [6 x 2] ## ## bairro mediana ## (chr) (dbl) ## 1 Noroeste 9666.561 ## 2 Sudoeste 9473.684 ## 3 Asa Sul 9210.526 ## 4 Asa Norte 9000.000 ## 5 Lago Norte 6753.247 ## 6 Lago Sul 5516.129
# Qual o bairro com o maior preço mediano de venda para apartamentos? dados %>% filter(tipo == "venda", imovel == "apartamento") %>% # Filtra tipo "venda" e imovel "apartamento" group_by(bairro) %>% # agrupa por bairro summarise(mediana = median(preco)) %>% # calcula mediana do preco arrange(desc(mediana)) # ordena de forma decrescente
## Source: local data frame [6 x 2] ## ## bairro mediana ## (chr) (dbl) ## 1 Asa Sul 950000 ## 2 Noroeste 950000 ## 3 Sudoeste 850000 ## 4 Asa Norte 780000 ## 5 Lago Sul 488307 ## 6 Lago Norte 470000
# Qual o bairro com o maior preço mediano de venda para lojas? dados %>% filter(tipo == "venda", imovel == "loja") %>% # Filtra tipo "venda" e imovel "loja" group_by(bairro) %>% # agrupa por bairro summarise(mediana = median(preco)) %>% # calcula mediana do preco arrange(desc(mediana)) # ordena de forma decrescente
## Source: local data frame [6 x 2] ## ## bairro mediana ## (chr) (dbl) ## 1 Noroeste 1107735 ## 2 Asa Sul 1050000 ## 3 Asa Norte 550000 ## 4 Lago Norte 430000 ## 5 Sudoeste 330000 ## 6 Lago Sul 320000
useR! 2015 – R mainstream
Se eu tiver que passar uma impressão principal do useR! 2015 é a de que o R provavelmente chegou em um tipping point e está se tornando, oficialmente, mainstream.
O grande diferencial do R sempre foi sua comunidade com a grande quantidade de pacotes disponíveis. Entretanto, como a comunidade era basicamente em torno do meio acadêmico, havia um pouco mais de dificuldade de dedicar recursos para aplicações comerciais e corporativas. Além disso, por ser uma linguagem feita por e para estatísticos, não necessariamente a implementação atual é a mais eficiente, podendo, em algumas circunstâncias, deixar a desejar em performance (mas garantindo correição e acurácia).
Esses são dois pontos que já estão mudando: (i) várias empresas (como Microsoft, Rstudio, Oracle, Google) se reuniram oficialmente para colocar dinheiro na comunidade do R; e, (ii) a popularidade do R está estimulando iniciativas para o tornar mais rápido e eficiente. Acredito que em pouco tempo veremos os benefícios disso.
Empresas investindo na comunidade: o R Consortium
A Linux Foundation anunciou a criação do R Consortium, uma organização com o objetivo de dar suporte à R Foundation e às demais organizações envolvidas com o desenvolvimento do R. Em resumo, as empresas participantes do consórcio vão se juntar para colocar dinheiro no desenvolvimento de projetos em torno da linguagem principalmente em projetos de infraestrutura (como o R-Forge ou o próprio encontro anual useR! – que será em Stanford em 2016).
Entre os fundadores estão:
- a própria R Foundation;
- membros platinum: Microsoft e RStudio;
- membros ouro, TIBCO;
- membros prata: Alteryx, Google, HP, Soluções Mango, Ketchum Trading e Oracle.
Durante o encontro, todas as empresas mostraram que já implementaram (ou estão implementando) aplicações corporativas do R em seus produtos, como, por exemplo, o R dentro do SQL server 2016 da Microsoft.
O R está ficando e vai ficar ainda mais rápido e eficiente
A popularidade do R está estimulando uma saudável competição em torno de uma implementação eficiente da linguagem. Além do trabalho da Microsoft com a Revolution R – ou de outras implementações corporativas – duas apresentações chamaram bastante a atenção: (i) o projeto CXXR que reescreve o interpretador do R em C++; e, (ii) o fastR da Oracle que – na verdade dentro de um projeto mais ambicioso envolvendo várias linguagens – reescreve o interpretador do R em Java. O fastR não tem uma data precisa para soltar uma versão plenamente funcional, mas o CXXR, aparentemente, já vai ter uma versão compatível com o GNU R a partir da próxima versão (3.3).
***
Faço questão de ressaltar aqui – como muitos já o fizeram – que a organização do useR! 2015 foi impecável! Mesmo com um público duas vezes maior do que o esperado (foram mais de 650 pessoas) tudo correu perfeitamente, tendo, inclusive, jantar Viking com arremessos de machados (literalmente). Meus parabéns para o pessoal da universidade de Aalborg e, em especial, ao Torben Tvedebrink – ano que vem o encontro será em Stanford e Aalborg elevou o nível para os próximos organizadores.
Dividir, Aplicar e Combinar (Split, Apply and Combine)
***
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.
As partes do livro não estão sendo publicadas na ordem – por exemplo, a seção abaixo não é uma explicação da família apply, mas sim da estratégia split-apply-combine
e de algumas funções que podem ser utilizadas nesta estratégia (como o trio split, lapply, do.call
, a função tapply
, ou a função aggregate
). A explicação sobre diferentes funções apply e derivados (apply
, sapply
, mapply
, lapply
, vapply
, rapply
, replicate
, rowSums, colSums, rowMeans, colMeans
) é feita em seção anterior a essa seção (ainda não disponível no blog).
Volte para ver atualizações!
***
Um padrão recorrente
Nossa base de dados (clique aqui para download) contém preços tanto de aluguel quanto de venda de apartamentos. Suponha que queiramos tirar a médias dos preços. Não faz muito sentido tirar a média dos dois tipos (aluguel e venda) juntos, certo? Como poderíamos fazer isso então? Uma possível solução seria a seguinte:
Primeiramente, dividimos a base de dados, criando duas outras, uma para cada grupo: aluguel e venda.
# 1) separar a base em duas bases diferentes: # - aluguel; e, # - venda aluguel <- dados[dados$tipo == "aluguel", ] venda <- dados[dados$tipo == "venda", ]
Em seguida nós calculamos a média para cada uma das novas bases que criamos.
# 2) calcular a média para cada uma das bases media_aluguel <- mean(aluguel$preco) media_venda <- mean(venda$preco)
Por fim, nós combinamos os resultados em um único vetor:
# 3) combinar os resultados em um único vetor medias = c(aluguel = media_aluguel, venda = media_venda) medias
## aluguel venda ## 4594.757 1232719.524
Pronto! Calculamos as duas médias que queríamos. Todavia, note que gastamos cerca de 5 linhas para chegar ao resultado – e que foram 5 linhas porque temos apenas 2 categorias (alguel e venda) neste exemplo. Imagine se tívessemos que analisar separadamente 200 ou 2000 categorias? Teríamos que criar uma base separada para cada uma delas?
Não necessariamente. Na verdade podemos fazer isso (ou coisas mais complexas) com apenas uma ou duas linhas. Para você saber aonde queremos chegar, seguem alguns exemplos mais sucintos que realizam o mesmo cálculo feito anteriormente:
# com tapply tapply(X = dados$preco, INDEX = dados$tipo, FUN = mean)
## aluguel venda ## 4594.757 1232719.524
# com aggregate aggregate(x = list(media = dados$preco), by = list(tipo = dados$tipo), FUN = mean)
## tipo media ## 1 aluguel 4594.757 ## 2 venda 1232719.524
# com dplyr library(dplyr) dados %>% group_by(tipo) %>% summarise(media = mean(preco))
## Source: local data frame [2 x 2] ## ## tipo media ## 1 aluguel 4594.757 ## 2 venda 1232719.524
Mas, antes de entrarmos nas formas mais concisas de escrever essas operações, vejamos, primeiramente, como fazê-las com algumas funções mais básicas do R, o que vai lhe permitir maior flexibilidade em alguns casos.
Dividir, Aplicar e Combinar (Split, Apply and Combine)
O padrão de análise descrito na seção anterior é bastante recorrente quando trabalhamos com dados. Dentro da comunidade do R
, esse processo é conhecido como Dividir, Aplicar e Combinar (DAC) ou, em inglês, Split, Apply and Combine (SAC). Em nosso caso específico, nós pegamos um vetor (o vetor de preços), dividimos segundo algum critério (por tipo), aplicamos um função em cada um dos grupos separadamente (no nosso caso, a média) e depois combinamos os resultados novamente.
Para quem conhece SQL, muitas dessas operações são similares ao group by
, ou, para quem usa Excel, similar a uma tabela dinâmica – mas note que não são coisas exatamente equivalentes, pois o conceito aqui é mais flexível. Isso vai ficar mais claro na medida em que usarmos exemplos mais complicados.
Apesar de só estarmos introduzindo o conceito de DAC agora, nós, na verdade, já tínhamos visto este padrão diversas vezes quando estudamos as funções do tipo apply. Por exemplo, ao aplicar uma função por linhas, você está dividindo a matriz por uma das dimensões (a dimensão das linhas), aplicando funções a cada uma das partes (a cada uma das linhas) e combinando os resultados em um único vetor:
Vejamos algumas peças para construir essa estratégia de análise de dados usando as funções base do R.
Dividir: a função split
A primeira função que você deve conehcer é a função split()
(dividir, em inglês) que, literalmente, divide um objeto segundo um conjunto de características. A função tem a seguinte estrutura:
str(split)
## function (x, f, drop = FALSE, ...)
\pause
Em que os principais parâmetros são:
- x: vetor ou data.frame que será divido;
- f: fatores que irão definir os grupos de divisão.
O resultado da função é uma lista para cada fator, contendo os vetores ou data.frames do respectivo grupo.
Voltando ao nosso exemplo, vamos dividir nosso data.frame segundo a lista de fatores tipo
(aluguel ou venda). Note que o resultado é uma lista contendo dois vetores: (i) um para aluguel; (ii) e outro para venda.
alug_venda <- split(dados$preco, dados$tipo) str(alug_venda, max.level = 1)
## List of 2 ## $ aluguel: num [1:76085] 650 750 800 800 800 820 850 850 850 860 ... ## $ venda : num [1:216517] 159000 170000 175000 180000 180000 180000 185000 185000 190000 195000 ...
Aplicar e combinar – voltando à família apply
Como visto, o resultado do split é uma lista para cada categoria. Queremos aplicar uma função a cada um dos elementos dessa lista. Ora, já vimos uma função que faz isso: o lapply()
. Dessa forma, com o comando lapply(alug_venda, mean)
podemos calcular a média de cada um dos elementos da lista, separadamente:
medias <- lapply(alug_venda, mean) medias
## $aluguel ## [1] 4594.757 ## ## $venda ## [1] 1232720
Combinando os resultados com unlist()
Ok, estamos quase lá, já temos o resultado final, mas ele está no formato de uma lista, que não é um dos formatos mais convenientes. Geralmente, em casos como esse, queremos um vetor. Vamos, assim, tentar simplificar este objeto. Uma das formas de fazer isso seria utilizar uma função que nós tambem já vimos quando estudamos os objetos básicos do R: a função unlist()
unlist(medias)
## aluguel venda ## 4594.757 1232719.524
Combinando com do.call()
Existe outra função de conveniência que, em conjunto com rbind()
e cbind()
pode ser bastante útil para simplificar nossos resultados: a função do.call()
.
Como ela funciona?
A função do.call()
tem a seguinte sintaxe: na primeira posição passamos, em formato texto, uma função que queremos utilizar (como cbind()
); já na segunda posição passamos a lista de argumentos que que serão utilizadas pela função que está na primeira posição.
Em outras palavras – e mais diretamente – o comando:
do.call("alguma_funcao", lista_de_argumentos)
É equivalente a:
alguma_funcao(lista_de_argumentos[1], lista_de_argumentos[2], ..., lista_de_argumentos[n])
No nosso caso, temos apenas duas médias, então não seria complicado elencar um a um os elementos no rbind()
ou no cbind()
. Todavia, imagine um caso em que temos centenas de médias. Nesta situação, a função do.call()
é bastante conveniente.
do.call("rbind", medias)
## [,1] ## aluguel 4594.757 ## venda 1232719.524
do.call("cbind", medias)
## aluguel venda ## [1,] 4594.757 1232720
Aplicando e simplificando ao mesmo tempo: sapply()
Agora podemos encaixar conceitualmente outra função que já tínhamos aprendido, o sapply()
. Essa função tenta fazer os dois passos do DAC ao mesmo tempo: Aplicar e Combinar (que neste caso é sinônimo de simplificar):
sapply(alug_venda, mean)
## aluguel venda ## 4594.757 1232719.524
Aplicando e simplificando ao mesmo tempo: vapply()
Existe, ainda, uma versão mais restrita do sapply()
: o vapply()
. A principal diferença entre eles é que o vapply()
exige que você especifique o formato do resultado esperado da operação.
Enquanto o o primeiro é mais prático para uso interativo, o segundo é mais seguro para programar suas próprias funções, pois, se o resultado não vier conforme esperado, ele irá acusar o erro.
Por exemplo, no comando abaixo estamos dizendo explicitamente ao R que queremos um resultado do tipo numérico. Assim, se por acaso vier algo diferente, o R acusará um erro.
vapply(alug_venda, mean, numeric(1))
## aluguel venda ## 4594.757 1232719.524
Para ilustrar essa situação, suponha que esperássemos que o resultado do nosso cálculo fosse um vetor do tipo character
com um elemento. Note agora R fornece uma mensagem de erro bastante explicativa.
vapply(alug_venda, mean, character(1))
## Error in vapply(alug_venda, mean, character(1)): valores devem ser do tipo 'character', ## mas o resultado de FUN(X[[1]]) é de tipo 'double'
Dividir, Aplicar e Combinar: fazendo tudo ao mesmo tempo
Conhecer as funções mais fundamentais da estrutura Split, Apply, Combine é importante para você ter a flexibilidade de fazer análises mais personalizadas quando precisar. O exemplo anterior é bastante simples para podermos nos concentrar nos conceitos, entretanto, não se engane: combinando apenas as funções do tipo apply()
com as funções split()
e do.call()
é possível fazer diversas operações relativamente complexas com poucas linhas (prepare-se para os exercícios!).
Contudo, existem funções que realizam grande parte do processo de manipulação de dados de uma forma mais simples e compacta (e muitas vezes mais intuitiva, como o dplyr
!) e essas funções serão suficientes para a maior parte do seu trabalho!
Nessa seção veremos duas funções base do R: tapply()
e aggregate()
.
DAC com tapply
A função tapply()
tem a seguinte estrutura:
str(tapply)
## function (X, INDEX, FUN = NULL, ..., simplify = TRUE)
- X: o objeto que será agregado. Ex: preços;
- INDEX: uma lista de vetores que servirão de índice para agregar o objeto. Ex: bairros;
- FUN: a função que será aplicada a X para cada INDEX. Ex: mediana.
- simplify: tentará simplificar o resultado para uma estrutura mais simples?
Voltemos, assim, ao nosso exemplo inicial: calcular a mediana do metro quadrado para aluguel e para venda. Como ficaria com o tapply
? Como tínhamos visto, basta uma única linha:
tapply(dados$pm2, dados$tipo, median)
## aluguel venda ## 35.71429 9000.00000
Podemos passar mais de um fator para a função? Sim! Vamos, por exemplo, calcular a mediana dos preços separadas por aluguel, venda e bairro. Note que o resultado, agora, não é um vetor, mas uma matriz:
tapply(dados$pm2, list(dados$bairro, dados$tipo), median)
## aluguel venda ## Asa Norte 35.55556 9000.000 ## Asa Sul 38.68472 9210.526 ## Lago Norte 34.61538 6753.247 ## Lago Sul 32.83582 5516.129 ## Noroeste 37.83784 9666.561 ## Sudoeste 33.84307 9473.684
É possível colocar mais fatores ainda? Claro! Que tal a mediana por aluguel e venda, separada por tipo de imóvel e por bairro? Ao invés de uma matriz, como passamos três fatores, teremos como resultado um array com três dimensões:
tabelas <- tapply(dados$pm2, list(dados$imovel, dados$tipo, dados$bairro), median) str(tabelas)
## num [1:5, 1:2, 1:6] 31.4 29.2 32.7 48 45.7 ... ## - attr(*, "dimnames")=List of 3 ## ..$ : chr [1:5] "apartamento" "casa" "kitinete" "loja" ... ## ..$ : chr [1:2] "aluguel" "venda" ## ..$ : chr [1:6] "Asa Norte" "Asa Sul" "Lago Norte" "Lago Sul" ...
Note que a primeira dimensão separa os resultados por tipo do imóvel; a segunda dimensão, por aluguel e venda; e, por fim, a terceira dimensão separa os resultados por bairros. Deste modo você pode filtrar o array
em qualquer uma das três dimensões para selecionar um subconjunto dos valores. Por exemplo, ao selecionar apenas Asa Norte, obtemos uma matriz com as medianas de aluguel e venda, separadas por tipo de imóvel, mas somente deste bairro:
tabelas[,,"Asa Norte"]
## aluguel venda ## apartamento 31.42857 9000.000 ## casa 29.16667 5823.529 ## kitinete 32.66667 8035.714 ## loja 48.00000 5868.545 ## sala-comercial 45.71429 10733.453
Já se selecionarmos vendas, obtemos uma matriz com as medianas de venda por tipo de imóvel, separadas por bairro. E assim por diante.
tabelas[,"venda",] # venda por tipo de imóvel e bairro
## Asa Norte Asa Sul Lago Norte Lago Sul Noroeste Sudoeste ## apartamento 9000.000 9066.667 8329.250 5199.120 9654.000 9689.922 ## casa 5823.529 5611.728 4375.000 5510.204 NA NA ## kitinete 8035.714 12142.857 7621.467 8648.649 9641.136 8166.667 ## loja 5868.545 11666.667 7818.182 8648.649 18729.515 8800.603 ## sala-comercial 10733.453 10346.487 10600.000 6111.111 17872.222 8931.034
DAC com aggregate
O aggregate()
é similar ao tapply()
mas, ao invés de retornar um array, retorna um data.frame com dados empilhados (veremos mais detalhes sobre dados empilhados ao final deste capítulo) colocando uma coluna diferente para cada índice e apenas uma coluna com os valores.
A função aggregate()
tem duas sintaxes principais.
A primeira, similar ao tapply()
é:
aggregate(dados$valor, by=list(dados$indice1, dados$indice2), funcao)
Já a segunda sintaxe utiliza a formula interface do R e é do tipo:
aggregate(valor ~ indice1 + indice2, dados, funcao)
Trataremos mais fundo como funcionam fórmulas no R em outro capítulo. Por equanto você pode ler a formula valor~indice1+indice2
da seguinte forma: queremos a variável valor
separada (~
) pelo indice1
e (+
) pelo indice2
.
Vejamos um exemplo do aggregate()
. Vamos calcular a mediana do preço por metro quadrado, separada por bairro, venda ou aluguel, e tipo de imóvel. Note a diferença do formato deste resultado para o formato do tapply
. Ao invés de termos três dimensões, temos um data.frame com uma coluna para cada fator (bairro
, tipo
e imovel
) e apenas uma coluna de valores (pm2
):
pm2_bairro_tipo_imovel <- aggregate(pm2 ~ bairro + tipo + imovel, data=dados, median) str(pm2_bairro_tipo_imovel)
## 'data.frame': 55 obs. of 4 variables: ## $ bairro: chr "Asa Norte" "Asa Sul" "Lago Norte" "Lago Sul" ... ## $ tipo : chr "aluguel" "aluguel" "aluguel" "aluguel" ... ## $ imovel: chr "apartamento" "apartamento" "apartamento" "apartamento" ... ## $ pm2 : num 31.4 30.8 34 29.3 37.5 ...
head(pm2_bairro_tipo_imovel)
## bairro tipo imovel pm2 ## 1 Asa Norte aluguel apartamento 31.42857 ## 2 Asa Sul aluguel apartamento 30.83333 ## 3 Lago Norte aluguel apartamento 34.04255 ## 4 Lago Sul aluguel apartamento 29.28870 ## 5 Noroeste aluguel apartamento 37.50000 ## 6 Sudoeste aluguel apartamento 32.60870
O aggregate()
também é mais flexível que o tapply()
em outros aspectos. É possível passar mais de uma variável a ser agregada utilizando cbind()
e, além disso, passar argumentos para fazer a análise de apenas um subconjunto (subset) dos dados.
Vejamos outro exemplo: vamos calcular a mediana do preço, do metro quadrado e do preço por metro quadrado dos valores de aluguel de apartamento separados por bairro.
mediana_aluguel <- aggregate(cbind(preco, m2, pm2) ~ bairro, data = dados, subset = (dados$tipo=="aluguel" & dados$imovel=="apartamento"), FUN = median) mediana_aluguel <- mediana_aluguel[order(mediana_aluguel$pm2, decreasing=TRUE), ] mediana_aluguel
## bairro preco m2 pm2 ## 5 Noroeste 2600 74.6 37.50000 ## 3 Lago Norte 1800 55.0 34.04255 ## 6 Sudoeste 2700 82.0 32.60870 ## 1 Asa Norte 2300 70.0 31.42857 ## 2 Asa Sul 2800 80.0 30.83333 ## 4 Lago Sul 1500 51.0 29.28870
Note que fizemos várias coisas – filtramos o data.frame para selecionar apenas os dados de aluguel de apartamento, separamos por bairro, e calculamos a mediana para três variáveis – diretamente com o aggregate()
Excel, csv e C++ no R. Livro do Alvin Roth, Nova biografia de Steve Jobs. PCO e liberdade de expressão.
Alguns links interessantes:
R
O pessoal do RStudio não para de trabalhar:
– Novo pacote (readr) para ler arquivos de texto (csv e similares) no R;
– Novo pacote (readxl) para ler arquivos do Excel no R;
– Novo pacote (dygraphs) para fazer gráficos interativos de séries temporais no R usando JavaScript; e
Livros
– O Nobel Alvin Roth irá lançar um novo livro para o público geral: Who Gets What and Why: The New Economics of Matchmaking and Market Design. O livro está em pré-venda, previsto para sair em junho.
– Nova biografia de Steve Jobs está tendo uma boa repercussão no público e na crítica: Becoming Steve Jobs: The Evolution of a Reckless Upstart into a Visionary Leader.
Para finalizar
– Ainda estou na dúvida se é sério, mas o PCO tem um texto – aparentemente de verdade – defendendo a liberdade de expressão:
Funções: Definição, argumentos e operadores binários
***
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. As partes do livro não estão sendo publicadas na ordem. Volte para ver atualizaçõ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.
***
Por que funções?
Uma das grandes vantagens de usar uma linguagem de programação é automatizar o seu trabalho ou análise. Você será capaz de realizar grande parte do trabalho utilizando as funções internas do R ou de pacotes de terceiros em um script. Entretanto, você ganha ainda mais flexibilidade e agilidade criando suas próprias funções.
Vejamos um exemplo de script:
# vetor de precos em formato de texto ao invés de numérico # e com registros errados (0.1 e 10000000) # queremos converter para numérico, retirar os dados discrepantes # dividir por 1000 e arredondar o resultado precos <- c("0.1", "1250.55", "2346.87", "3467.40", "10000000") precos <- as.numeric(precos) precos <- precos[!(precos < 1 | precos > 10000)] precos <- precos/1000 precos <- round(precos) precos
## [1] 1 2 3
Nosso script faz o trabalho corretamente. Mas imagine que você queira realizar o mesmo procedimento com um vetor de preços diferente, digamos, precos2
. Da forma como o seu código foi feito, você terá que copiar e colar os comandos e substituir os nomes.
# novo vetor de precos precos2 <- c("0.0074", "5547.85", "2669.98", "8789.45", "150000000") precos2 <- as.numeric(precos2) precos2 <- precos2[!(precos2 < 1 | precos2 > 10000)] precos2 <- precos2/1000 precos2 <- round(precos2) precos2
## [1] 6 3 9
Note como isto é ineficiente. Além de ter que repetir todo o seu código para cada análise diferente que você desejar fazer, você ainda estará sujeito a diversos erros operacionais, como esquecer de trocar um dos nomes ao copiar e colar.
O ideal, aqui, é criar uma função que realize este trabalho.
Definindo funções
Uma função, no R, é definida da seguinte forma:
nomeDaFuncao <- function(arg1, arg2, arg3 = default3, ...){ # corpo da função: uma série de comados válidos. return(resultado) # opcional }
- o comando
function()
diz para o R que você está definindo uma função. - os valores dentro dos parênteses de
function()
são os argumentos (ou parâmetros) da função. Argumentos podem ter valores default (padrão), que são definidos com o sinal de igualdade (no casoarg3
tem como default o valordefault3
). Existe um parâmetro “coringa” muito útil, o...
, que permite passsar argumentos para outras funções. Veremos mais sobre o...
em seguida. - dentro das chaves encontra-se o “corpo” da função, isto é, uma série de comandos válidos que serão realizados.
- o comando
return()
encerra a função e retorna seu argumento. Como veremos, oreturn()
é opcional. Caso omitido, a função retorna o último objeto calculado.
Criemos nossas primeiras funções:
# retorna o quadrado de um número quadrado <- function(x){ x^2 } quadrado(3)
## [1] 9
## forma mais sucinta ## se o corpo da função for na mesma linha não é necessário colocar chaves quadrado <- function(x) x^2 quadrado(3)
## [1] 9
## função mais geral, elevar um número x à potência n elevado_n <- function(x,n) x^n elevado_n(3, 3)
## [1] 27
Funções criam um ambiente local e, em geral, não alteram o objeto ao qual são aplicadas. Isto é, se você passa um valor x
para uma função que eleva x
ao quadrado, o valor original de x
não muda. Funções tomam objetos como argumentos e criam outro objeto, modificado, como resultado. Na maior parte dos casos, a idéia é que uma função no R não tenha efeitos colaterais, isto é, que ela não modifique objetos fora de seu ambiente.
x <- 10 elevado_n(x, 2) # isso alterou o valor de x?
## [1] 100
# note que não x
## [1] 10
# se você quer salvar o resultado # tem que atribuí-lo a outro objeto y <- elevado_n(x, 2) y
## [1] 100
Voltando ao exemplo
Montemos uma função que realiza o tratamento dos dados visto anteriormente:
limparDados <- function(dados){ dados <- as.numeric(dados) dados <- dados[!(dados < 1 | dados > 10000)] dados <- dados/1000 dados <- round(dados) return(dados) } ls() # note que a função foi criada
## [1] "elevado_n" "limparDados" "precos" "precos2" "quadrado" ## [6] "x" "y"
Vejamos em detalhes:
- o comando
function()
diz para o R que você está definindo uma função. - os valores dentro dos parênteses de
function()
são os argumentos da função. No nosso caso definimos um único argumento chamadodados
. - dentro das chaves encontra-se o “corpo” da função, isto é, as operações que serão realizadas. Neste caso, transformamos
dados
emnumeric
, retiramos aqueles valores menores do que 1 e maiores do que 10000, dividimos por 1000 e, finalmente, arredondamos. - a função
return()
encerra a função e retorna o vetordados
modificado.
Pronta a função, sempre que você quiser realizar essas operações em um vetor diferente, basta utilizar limparDados()
. Testemos com novos vetores:
precos3 <- c("0.02", "4560.45", "1234.32", "7894.41", "12000000") precos4 <- c("0.001", "1500000", "1200.9", "2000.2", "4520.5") precos5 <- c("0.05", "1500000", "1000000", "7123.4", "9871.5") # limpando os dados limparDados(precos3)
## [1] 5 1 8
limparDados(precos4)
## [1] 1 2 5
limparDados(precos5)
## [1] 7 10
Ficou bem melhor do que o script. Note que tínhamos 3 vetores diferentes e bastou chamar a função três vezes, ao invés de ter que copiar e colar três vezes o código. Note, também, que se houver algum erro, temos que corrigir apenas a definicão da função e não três partes distintas do código.
Mais argumentos
Podemos refinar mais a função limparDados()
. Por exemplo, perceba que não função ainda não é geral o suficiente. Da forma como está escrita, os valores de corte de mínimo e de máximo serão sempre 1 e 10000; além disso, os resultados sempre serão dividos por 1000. E se quisermos modificar esses valores?
Para isso é necessário definir mais argumentos:
limparDados <- function(dados, min, max, div){ dados <- as.numeric(dados) dados <- dados[!(dados < min | dados > max)] dados <- dados/div dados <- round(dados) return(dados) }
Agora você pode alterar os valores de min
, max
e div
ao aplicar a função.
precos3 <- c("0.02", "4560", "1234", "7894", "12000000") limparDados(precos3, min=0, max=5000, div=2)
## [1] 0 2280 617
limparDados(precos3, min=0, max=4000, div=4)
## [1] 0 308
limparDados(precos3, min=-Inf, max=Inf, div=1)
## [1] 0 4560 1234 7894 12000000
Veja que os argumentos são nomeados. Dessa forma, se você colocar os argumentos com seus respectivos nomes, a ordem dos argumentos não importa. Você também pode omitir os nomes dos argumentos, desde que os coloque na ordem correta.
# argumentos em ordem diferente limparDados(max=5000, div=2, min=0, dados=precos3)
## [1] 0 2280 617
# argumentos sem nomes (na ordem correta) limparDados(precos3, 0, 4000, 4)
## [1] 0 308
Argumentos Default
Colocar mais argumentos em uma função, contudo, causa um certo incômodo. Você passa a ter que especificar todos estes argumentos cada vez que for chamar a função. Ao se esquecer de especificar algum, ocorrerá um erro:
limparDados(precos3, max=5000, div=1)
## Error in limparDados(precos3, max = 5000, div = 1): argumento "min" ausente, sem padrão
Existe uma forma simples de solucionar isto: basta definir valores padrão (default):
# colocando valores padrnao para min, max e div limparDados <- function(dados, min=1, max=10000, div=1000){ dados <- as.numeric(dados) dados <- dados[!(dados < min | dados > max)] dados <- dados/div dados <- round(dados) return(dados) }
Agora podemos usar a função omitindo os argumentos que possuem default.
# usa o default para min limparDados(precos3, max=5000, div=1)
## [1] 4560 1234
# usa o default para min e div limparDados(precos3, max=Inf)
## [1] 5 1 8 12000
# usa o default para tudo limparDados(precos3)
## [1] 5 1 8
Funções também podem ser argumentos
Funções também podem ser passadas como argumentos de funções. Por exemplo, suponha que você não queira sempre usar o round()
para arredondamento. Você pode colocar a função que é aplicada a dados
como um dos argumentos de limparDados()
.
limparDados <- function(dados, min=1, max=10000, div=1000, funcao=round){ dados <- as.numeric(dados) dados <- dados[!(dados < min | dados > max)] dados <- dados/div dados <- funcao(dados) # função que será aplicada agora é um argumento return(dados) }
Se quisermos usar a função floor()
ao invés de round()
, basta trocar o argumento funcao
.
# usou os defaults limparDados(precos3)
## [1] 5 1 8
# usa floor ao invés de round limparDados(precos3, funcao=floor)
## [1] 4 1 7
# funcao anonima que pega x e retorna x (não faz nada com x) limparDados(precos3, funcao = function(x) x)
## [1] 4.560 1.234 7.894
Funções anônimas
Como vimos no final do exemplo anterior, você pode definir uma nova função no próprio argumento de limparDados()
. Estas funções são chamadas de anônimas.
limparDados(precos3, funcao = function(x) x) # não faz nada com os dados ao final
## [1] 4.560 1.234 7.894
limparDados(precos3, funcao = function(x) x^2) # eleva dados ao quadrado
## [1] 20.793600 1.522756 62.315236
limparDados(precos3, funcao = function(x) log(x+1)) # tira o log de (dados +1 )
## [1] 1.7155981 0.8037937 2.1853769
limparDados(precos3, funcao = function(x) { # reliaza diversas operações x <- round(x) x <- as.complex(x) x <- (-x)^(x/10) } )
## [1] 0.0000000-2.236068i 0.9510565-0.309017i -4.2700173-3.102349i
O …
O R tem ainda um argumento coringa os “três pontos” ...
.
O ...
permite repassar argumentos para outras funções dentro da sua função, sem necessariamente ter que elencar todas as possibilidades de antemão. Não ficou muito claro? Vejamos um exemplo.
A função round()
tem o argumento digits
. Ou a nossa função elevado_n()
tem o argumento n
. Muitas vezes vamos querer mudar esses arguementos, mas como incluir todos em nossa função? Não temos como prever exatamente que funções ou que argumentos vamos precisar. Mas não precisamos fazer isso, podemos repassar argumentos arbitrários para essas funções por meio do ...
.
limparDados <- function(dados, min=1, max=10000, div=1000, funcao=round, ...){ dados <- as.numeric(dados) dados <- dados[!(dados < min | dados > max)] dados <- dados/div dados <- funcao(dados, ...) # note os três pontos return(dados) }
Agora, tudo que for colocado em ...
é repassado para funcao(dados, ...)
.
limparDados(precos3)
## [1] 5 1 8
limparDados(precos3, digits=1) # passamos o argumento digits = 1 para a função round (default)
## [1] 4.6 1.2 7.9
limparDados(precos3, funcao=elevado_n, n=2) # passamos o argumento n = 2 para a função elevado_n
## [1] 20.793600 1.522756 62.315236
Operadores binários
Lembra que, nos primeiros capítulos, mostramos que o operador +
, no R, na verdade é uma função e pode ser chamado com a seguinte sintaxe: '+'(x,y)
? Funções deste tipo são chamadas de operadores binários. No R, você também pode definir seus próprios operadores binários com o auxílio do caracter especial %
.
Para ilustrar, façamos um operador binário que cole textos:
`%+%` <- function(x, y) paste(x, y)
Agora podemos colar textos usando %+%
:
"colando" %+% "textos" %+% "com nosso" %+% "operador"
## [1] "colando textos com nosso operador"
Vejamos outro exemplo:
`%depois%` <- function(x, fun) fun(x)
Olhe que interessante:
set.seed(10) x <- rnorm(100) sqrt(exp(mean(x)))
## [1] 0.9340041
x %depois% mean %depois% exp %depois% sqrt
## [1] 0.9340041
Ou seja, com esse simples operador, você mudou a sintaxe das operações. Ao invés de escrever sqrt(exp(mean(x)))
, que te força a pensar “de fora para dentro” (tirar a raiz quadrada do exponencial da média de x) você pode escrever na “ordem natural” das operações x %depois% mean %depois% exp %depois% sqrt
(pegue x, tire a média, exponencie e tire a raiz quadrada). Na verdade, este caso é uma versão super simplificada da lógica do operador %>%
do pacote magrittr
, muito usado no dplyr
, que veremos na seção de manipulação de data.frames
.
A imaginação é o limite.
Exercícios
Sua vez.
- Defina uma função que retorne o mínimo, a mediana e o máximo de um vetor. Faça com que a função lide com NA’s e que isso seja um argumento com default;
- Defina uma versão “operador binário” da função
rep
. Faça com que tenha seguinte sintaxe:x %rep% n
retorna o objeto x repetido n vezes. - Defina uma função que normalize/padronize um vetor (isto é, subtraia a média e divida pelo desvio-padrão). Faça com que a função tenha a opção de ignorar NA’s. Permita ao usuário escolher outros parâmetros para a média (Dica: use …);
- Dados um vetor y e uma matriz de variáveis explicativas X, defina uma função que retorne os parâmetros de uma regressão linear de x contra y, juntamente com os dados originais usados na regressão. (Dicas: use álgebra matricial. Use uma lista para retornar o resultado)
Soluções sugeridas (você pode fazer melhor!)
mmm <- function(x, na.rm=TRUE){ # calcula min, median, e max, guarda em resultado resultado <- c(min(x, na.rm = na.rm), median(x, na.rm = na.rm), max(x, na.rm = na.rm)) # nomeia o vetor para facilitar consulta names(resultado) <- c("min", "mediana", "max") #retorna vetor return(resultado) } mmm(c(1,2,3, NA))
## min mediana max ## 1 2 3
`%rep%` <- function(x, n) rep(x, n) 7 %rep% 5
## [1] 7 7 7 7 7
padronize <- function(x, na.rm=TRUE,...){ m <- mean(x,na.rm=na.rm, ...) # calcule a média dp <- sd(x, na.rm=na.rm) # calcule o dp pad <- (x-m)/dp # padronize os dados attr(pad, "media") <- m # guarda a média original p/ consulta attr(pad, "dp") <- dp # guarda o dp original p/ consulta return(pad) # retorna o vetor pad já com atributos } padronize(1:5)
## [1] -1.2649111 -0.6324555 0.0000000 0.6324555 1.2649111 ## attr(,"media") ## [1] 3 ## attr(,"dp") ## [1] 1.581139
ols <- function(X, y){ b <- solve(t(X)%*%X)%*%t(X)%*%y # ols ((X'X)^-1)X'Y # guarda resultados em lista nomeada resultado <- list(coef = b, X = X, y = y) # retorna resultado return(resultado) } # cria dados simulados set.seed(10) # para reproducibilidade X <- matrix(rnorm(300), ncol=3) # vetor X y <- X%*%c(3,6,9) + rnorm(100) # y = Xb + e, b=c(3, 6, 9), e~N(0,1) # vamos testar a formula resultado <- ols(X, y) str(resultado)
## List of 3 ## $ coef: num [1:3, 1] 3.01 6.01 9 ## $ X : num [1:100, 1:3] 0.0187 -0.1843 -1.3713 -0.5992 0.2945 ... ## $ y : num [1:100, 1] 7.93 5.53 1.53 11.11 -12.52 ...
resultado$coef
## [,1] ## [1,] 3.012419 ## [2,] 6.011090 ## [3,] 8.998595
*** falar sobre escopo e orientação a objetos ***
Introdução a Objetos e à Área de Trabalho
***
Parte do livro Introdução à análise de dados com R. Este trabalho está em andamento. Volte para ver atualizaçõ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.
***
Essa frase não vai fazer muito sentido agora, mas é bom você já começar a tê-la em mente: no R, praticamente tudo o que existe na sua área de trabalho é um “objeto”. E praticamente tudo o que acontece na sua área de trabalho é resultado de uma função.
Nesta seção veremos um pouco sobre o objeto mais básico do R, o vetor, e como gerenciar sua érea de trabalho. Aprenderemos, basicamente, algumas formas de criar e remover um objeto (no caso um vetor), como verificar suas propriedades e alterar seus elementos. Ao final veremos como salvar e carregar sua área de trabalho e/ou objetos específicos.
Criando objetos: assignment operators
Durante o uso do R, você irá criar e guardar objetos com um nome, por exemplo:
x1 <- 10 # atribui o valor 10 à variável x1 x1
## [1] 10
O operador <-
é conhecido como “assignment operator” e, no caso acima, atribuiu o valor 10
a um objeto de nome x1
(no caso, um vetor). Na maior parte das vezes, o operador =
é equivalente a <-
. Vejamos:
x2 = 20 # atribui o valor 20 à variável x2 x2
## [1] 20
Neste livro recomendaremos o uso do <-
pois ele funciona sempre como atribuição. O operador =
é usado para definir argumentos dentro de um função e, assim, seu comportamento pode ser diferente de uma atribuição em certos casos (veremos isso mais a frente). Contudo, na maior parte das vezes o uso de =
e <-
é indiferente, então desde que você seja consistente, escolha a forma que mais lhe agradar.
Estudaremos funções mais a fundo em outra seção, mas, é importante desde já ter a idéia de que o assignment operator <-
nada mais é do que uma função. Para se chamar uma função utiliza-se seu nome seguido dos argumentos entre parênteses, isto é, funcao(argumento1, argumento2, ...)
.
Dessa forma, poderíamos ter chamado o operado <-
com a sintaxe de uma função (usando os backticks para auxiliar). Isto é, o comando:
`<-`("x1", 10)
É equivalente a
x1 <- 10
Não se preocupe se você não estiver entendendo tudo agora, mais para frente esses detalhes passarão a fazer mais sentido.
Além do =
, outra função que é de certo modo equivalente a <-
é a função assign()
, que toma a forma assign("nomeObjeto", valorObjeto)
.
# cria a variável x3 com o valor 4 assign("x3", 4) x3
## [1] 4
# veja que é equivalente a x3 <- 4 x3 <- 4 x3
## [1] 4
Uma vez que você atribuiu uma variável a um nome, você pode utilizá-la em operações e funções utilizando seu nome.
x1 + x2 + x3 # soma x1,x2,x3
## [1] 34
x1/x2 # divide x1 por x2
## [1] 0.5
x1 * x2 # multiplica x1 por x2
## [1] 200
E você pode guardar os resultados dessas operações em outras variáveis:
y <- x1*x2 + x3 #cria y com o resultado de x1*x2 + x3 y
## [1] 204
Nomes de variáveis
O R é case sensitive – isto é, letras maiúsculas e minúsculas são diferenciadas – portanto x1
(com x minúsculo) e X1
(com x maiúsculo) são objetos diferentes.
X1 # O R não vai encontrar, pois não criamos X1 com X maiúsculo.
## Error in eval(expr, envir, enclos): objeto 'X1' não encontrado
x1 # Encontra normalmente
## [1] 10
Os nomes dos objetos no R podem conter combinações arbitrárias de números, textos, bem como ponto ( . ) e underscore ( _ ). Entretanto, os nomes não podem começar com números ou underscore.
a1_B2.c15 <- "variável com nome estranho" a1_B2.c15
## [1] "variável com nome estranho"
_x <- 1 # erro, pois começa com underscore 1var <- 1 # erro, pois começa com número
Existem alguns caracteres reservados que também não podem ser utilizados no início dos nomes (como operadores matemáricos +, -,), mas o R é bastante flexível, e todas essas regras podem ser “burladas” se você utilizar backticks ( ).
`_x` <- 1 # agora funciona `+variavel` <- 100 # funciona `1var` <- 1 # funciona
Concatenando valores
Até agora construimos vetores com apenas um elemento. Uma das formas de construir um vetor com mais elementos é concatenando uma quantidade arbitrária de objetos com a função c()
.
x3 <- c(x1, 2, 3, x2) # concatena x1, 2, 3 e x2. x3
## [1] 10 2 3 20
x4 <- c("a", "b","c") # concatena "a", "b" e "c" x4
## [1] "a" "b" "c"
Classes de vetores
No R
, a estrutura mais simples de dados é um vetor. Os vetores no R podem ser, entre outros, de classes: numeric (números de ponto flutuante), integer (número inteiro), complex (número complexo), character (texto), logical (lógicos, booleanos). Há também datas e fatores, que discutiremos mais a frente. Os objetos x1
e x2
, por exemplo, são vetores numéricos de tamanho 1
Criemos alguns vetores para cada uma dessas classes:
numero <- c(546.90, 10, 789) # note o L inteiro <- c(1L, 98L) # note o i complexo <- c(20i, 2+9i) # notem as aspas texto <- c("Um texto de exemplo", "outro texto", "mais texto") # sempre maiúsculo logico <- c(TRUE, FALSE, TRUE)
Note que inteiros são criados seguidos de um L
maiúsculo. Números complexos são seguidos de um i
minúsculo. Textos podem ser criados com aspas duplas ("texto"
) ou simples ('texto'
). Vetores lógicos são criados pelas palavras TRUE
ou FALSE
, sempre em maiúsculo (e podem ser abreviados para T
ou F
, mas não recomendamos).
A função class() é útil para identificar a classe de um determinado objeto. Verifiquemos as classes dos objetos que acabamos de criar:
class(numero)
## [1] "numeric"
class(inteiro)
## [1] "integer"
class(complexo)
## [1] "complex"
class(texto)
## [1] "character"
class(logico)
## [1] "logical"
Você pode testar se um vetor é de determinada classe com as funções is.xxx
(sendo “xxx” a classe). Por exemplo:
is.numeric(numero)
## [1] TRUE
is.character(numero)
## [1] FALSE
is.character(texto)
## [1] TRUE
is.logical(texto)
## [1] FALSE
E você também pode forçar a conversão de um vetor de uma classe para outra com as funções as.xxx
(sendo “xxx” a classe). Entretanto, nem sempre essa conversão faz sentido, e pode resultar em erros ou NA’s (veremos NA’s mais a frente). Por exemplo:
as.character(numero) # Vira texto
## [1] "546.9" "10" "789"
as.numeric(logico) # TRUE -> 1, FALSE -> 0
## [1] 1 0 1
as.numeric(texto) # Não faz sentido
## Warning: NAs introduzidos por coerção
## [1] NA NA NA
as.numeric("1012312") # Faz sentido
## [1] 1012312
Estrutura e tamanho de um objeto
Para ver a estrutura de um objeto, use a função str()
. Esta é uma função simples, mas talvez uma das mais úteis do R.
Vejamos um exemplo simples, a estrutura do objeto x3
str(x3)
## num [1:4] 10 2 3 20
Note que o resultado de str()
fornece várias informações: trata-se de um vetor numérico (num
), com 4 elementos ([1:4]
) e os primeiros elementos do vetor são (10 2 3 20
).
Se você estiver utilizando o RStudio, um resumo dessa mesma informação já estará aparcendo no seu canto superior direito.
Teste o resultado de str() em alguns dos outros objetos que criamos e repare nos resultados:
str(x1)
## num 10
str(x4)
## chr [1:3] "a" "b" "c"
str(numero)
## num [1:3] 547 10 789
str(inteiro)
## int [1:2] 1 98
str(complexo)
## cplx [1:2] 0+20i 2+9i
str(texto)
## chr [1:3] "Um texto de exemplo" "outro texto" "mais texto"
str(logico)
## logi [1:3] TRUE FALSE TRUE
Para obter o tamanho de um objeto, utilize a função length()
. Note que comandos no R podem ser colocados na mesma linha se separados por ponto-e-vírgula (;).
length(x1)
## [1] 1
length(x3)
## [1] 4
length(x4)
## [1] 3
length(numero); length(inteiro)
## [1] 3
## [1] 2
Elementos de um vetor
Você pode acessar elementos de um vetor por meio de colchetes [ ]
e sua posição.
numero[1] # apenas primeiro elemento do vetor número
## [1] 546.9
numero[c(1,2)] # elementos 1 e 2
## [1] 546.9 10.0
numero[c(1,3)] # elementos 1 e 3
## [1] 546.9 789.0
numero[c(3,1,2)] # troca de posição
## [1] 789.0 546.9 10.0
Índices negativos podem ser utilizados para selecionar todos os demais elementos de um vetor, exceto aquele que está no índice. Por exemplo:
# seleciona todos os elementos menos o primeiro numero[-1]
## [1] 10 789
numero[-c(1,2)] # todos menos 1 e 2
## [1] 789
numero[-c(1,3)] # todos menos 1 e 3
## [1] 10
numero[-3] # todos menos 3
## [1] 546.9 10.0
Nomes dos elementos
Objetos podem ter seus elementos nomeados. A função names()
nos dá os nomes desses elementos:
names(numero)
## NULL
Note que o resultado foi NULL
pois os elementos do vetor numero
ainda não foram nomeados. Façamos isso, portanto, utilizando a função names()<-
numero
## [1] 546.9 10.0 789.0
names(numero) <- c("numero1", "numero2", "numero3") numero
## numero1 numero2 numero3 ## 546.9 10.0 789.0
Agora, além de acessar o elemento do vetor pela posição, pode-se utilizar seu nome.
# seleciona o elemento de nome "numero1" numero["numero1"]
## numero1 ## 546.9
# seleciona o elemento de nome "numero2" numero["numero2"]
## numero2 ## 10
# seleciona o elemento de nome "numero3" numero["numero3"]
## numero3 ## 789
# seleciona os elementos de nome "numero1" e "numero3" numero[c("numero1", "numero3")]
## numero1 numero3 ## 546.9 789.0
Alterando elementos
Com o assignment operator e o colchetes, consegue-se alterar apeans alguns elementos específicos de um vetor.
Você pode fazer isso utilizando índices numéricos:
numero
## numero1 numero2 numero3 ## 546.9 10.0 789.0
numero[1] <- 100 # altera elemento 1 para 100 numero
## numero1 numero2 numero3 ## 100 10 789
numero[2:3] <- c(12.3, -10) # altera elementos 2 e 3 numero
## numero1 numero2 numero3 ## 100.0 12.3 -10.0
O que ocorre se você colocar um índice maior do que o tamanho do vetor? O R estende o vetor até o tamanho do índice, e preenche os valores restantes com NA (veremos mais sobre NA a frente):
numero[10] <- 50 # o vetor número não tem 10 elementos... numero # ao elemento 10 foi atribuido o valor 50 e o restante foi preenchido com NA
## numero1 numero2 numero3 ## 100.0 12.3 -10.0 NA NA NA NA NA NA ## ## 50.0
Como deletar um elemento de um vetor? Basta usar o índice negativo e sobrescrever o resultado:
logico # 3 elementos
## [1] TRUE FALSE TRUE
logico <- logico[-2] # deletamos o segundo elemento logico
## [1] TRUE TRUE
Você também pode modificar o vetor utilizando os nomes dos elementos:
numero["numero3"] <- 431 numero
## numero1 numero2 numero3 ## 100.0 12.3 431.0 NA NA NA NA NA NA ## ## 50.0
numero[c("numero1", "numero2")] <- c(-100, 100) numero
## numero1 numero2 numero3 ## -100 100 431 NA NA NA NA NA NA ## ## 50
Ordenando um vetor
A função order()
retorna um vetor com as posições para que um objeto fique em ordem crescente.
order(numero) # indices
## [1] 1 10 2 3 4 5 6 7 8 9
numero[order(numero)] # ordena numero
## numero1 numero2 numero3 ## -100 50 100 431 NA NA NA NA NA ## ## NA
A função sort()
retorna o vetor ordenado.
sort(numero)
## numero1 numero2 numero3 ## -100 50 100 431
As duas funções tem o parâmetro decreasing
que, quando TRUE
, retornam o vetor de em ordem decrescente.
Encontrando e removendo objetos
Para listar todos os objetos que estão na sua área de trabalho, você pode usar a função ls()
ou objects()
.
ls()
## [1] "_x" "+variavel" "1var" "a1_B2.c15" "complexo" ## [6] "inteiro" "logico" "numero" "texto" "x1" ## [11] "x2" "x3" "x4" "y"
objects()
## [1] "_x" "+variavel" "1var" "a1_B2.c15" "complexo" ## [6] "inteiro" "logico" "numero" "texto" "x1" ## [11] "x2" "x3" "x4" "y"
Note que apareceram todos os objetos que criamos.
A função rm(objeto)
remove um objeto da área de trabalho.
rm(x3) # remove o objeto x3 da área de trabalho x3 # não encontrará o objeto
## Error in eval(expr, envir, enclos): objeto 'x3' não encontrado
ls() # note que x3 não aparecerá na lista de objetos
## [1] "_x" "+variavel" "1var" "a1_B2.c15" "complexo" ## [6] "inteiro" "logico" "numero" "texto" "x1" ## [11] "x2" "x4" "y"
Voltando à função ls()
, note que o que ela retorna também é um objeto: é um vetor de tipo “texto”, ou, como vimos, na terminologia do R
, do tipo “character”. Este resultado pode ser atribuído a um objeto e armazenado na área de trabalho.
lista_obj <- ls() # guarda o resultado de ls() na variável lista_obj lista_obj
## [1] "_x" "+variavel" "1var" "a1_B2.c15" "complexo" ## [6] "inteiro" "logico" "numero" "texto" "x1" ## [11] "x2" "x4" "y"
ls()
## [1] "_x" "+variavel" "1var" "a1_B2.c15" "complexo" ## [6] "inteiro" "lista_obj" "logico" "numero" "texto" ## [11] "x1" "x2" "x4" "y"
Isto pode ser interessante pois a função rm()
aceita um parâmetro de texto (list
) para remover objetos. Por exemplo:
rm(list=lista_obj) # remove todos os objetos que estão na lista_obj ls() # note que sobrou apenas lista_obj
## [1] "lista_obj"
Desta forma, um atalho para remover todos os objetos da sua área de trabalho é rm(list = ls())
.
A função ls()
também aceita um parâmetro (pattern
) que define um padrão na busca dos objetos no ambiente de trabalho. O pattern
é bem flexível e inclusive aceita expressões regulares (veremos expressões regulares mais a frente). Por exemplo, o comando ls(pattern="y")
irá buscar todas as variáveis que contenham “y” no seu nome.
Buscando apenas as variáveis que contenham “y” no nome:
x1 <- 1:10 # x1 números de 1 a 10 x2 <- c(2, 4,9); y1 <- 50; y2 <- 10 # ; comandos na mesma linha ls() # lista tudo
## [1] "lista_obj" "x1" "x2" "y1" "y2"
ls(pattern="y") # lista somente y1 e y2
## [1] "y1" "y2"
Combinando este recurso do ls()
com o rm()
você pode remover apenas certos objetos.
rm(list=ls(pattern="y")) #remove todos os objetos que contenham "y". ls()
## [1] "lista_obj" "x1" "x2"
Salvando e carregando objetos
Para salvar uma cópia da sua área de trabalho você pode utilizar a função save.image()
:
# salva a área de trabalho no arquivo "aula_1.RData" save.image(file="aula_1.RData")
Agora você pode recuperar todos os objetos com load()
.
# vamos remover todos os objetos da área de trabalho rm(list=ls()) ls() # não encontra nada
## character(0)
load(file="aula_1.RData") ls() # note que os objetos foram carregados
## [1] "dados_2010_11_10" "dados_2013_11_10" "encoding" ## [4] "input" "novembro" "out" ## [7] "outubro" "publish" "shortcode" ## [10] "title"
Com a função save()
é possível salvar apenas um ou um conjunto de objetos.
# simula 100 obs de uma normal(10, 2) sim_normal <- rnorm(100, mean=10, sd=2) # salva no arquivo sim_normal.RData e remove da área de trabalho save(sim_normal, file="sim_normal.RData") rm(sim_normal) ls() # sim_normal não aparece
## [1] "dados_2010_11_10" "dados_2013_11_10" "encoding" ## [4] "input" "novembro" "out" ## [7] "outubro" "publish" "shortcode" ## [10] "title"
# carrega sim_normal.RData load(file="sim_normal.RData") ls() # sim_normal aparece
## [1] "dados_2010_11_10" "dados_2013_11_10" "encoding" ## [4] "input" "novembro" "out" ## [7] "outubro" "publish" "shortcode" ## [10] "sim_normal" "title"
Estas operações podem ser realizadas com o botão de salvar no canto direito do RStudio.
Outro conjunto de funções para salvar e ler objetos do R são saveRDS()
e readRDS()
. Uma das principais diferenças com relação a save()
e load()
é que, enquanto estas salvam e carregam os objetos com o seu nome original, as funções RDS permitem a você carregar o objeto com um nome diferente.
saveRDS(sim_normal, file="sim_normal.rds") rm(sim_normal) ### carrega sim_normal.rds em um objeto com nome diferente ### simulacao <- readRDS("sim_normal.rds") ls()
## [1] "dados_2010_11_10" "dados_2013_11_10" "encoding" ## [4] "input" "novembro" "out" ## [7] "outubro" "publish" "shortcode" ## [10] "simulacao" "title"
Exercícios
Agora é sua vez.
- Remova todos os objetos do ambiente de trabalho.
- Crie objetos com nomes
dados_2010_10_10
,dados_2010_11_10
,dados_2013_10_10
,dados_2013_11_10
. Faça com que os objetos sejam do tipo numérico, character, lógico e inteiro. Verifique a classe e a estrutura dos objetos criados. - Use
ls()
para listar apenas os dados de Novembro. E depois para listar apenas os dados de Outubro. Userm()
para remover apenas os dados de outubro (dica: você vai precisar do resultado dels()
). - Salve sua area de trabalho com o nome
exercicio_objetos.RData
. Salve apenasdados_2010_11_10
com o nomedados_2010_11_10.RData
.
Soluções
rm(list=ls()) # remove todos os objetos dados_2010_10_10 <- 10.5 dados_2010_11_10 <- "texto" dados_2013_10_10 <- TRUE dados_2013_11_10 <- 24L class(dados_2010_10_10) class(dados_2010_11_10) class(dados_2013_10_10) class(dados_2013_11_10) str(dados_2010_10_10) str(dados_2010_11_10) str(dados_2013_10_10) str(dados_2013_11_10) novembro <- ls(pattern="_11_") outubro <- ls(pattern="_10_") rm(list=outubro) save.image(file="exercicios_objetos.RData") save(dados_2010_11_10, file="dados_2010_11_10.RData")
R e RStudio
***
Parte do livro Introdução à análise de dados com R. Este trabalho está em andamento. Volte para ver atualizaçõ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.
***
R e Rstudio
Instalação
Instalar o R e o RStudio é bastante fácil, pois ambos já vêm com distribuições compiladas para Windows, Mac OS ou Linux. O R é gratuito e está disponível no site do CRAN (The Comprehensive R Archive Network). O RStudio tem uma versão desktop gratuita disponível em seu site. Esses são os dois principais softwares para acompanhar este livro.
Além disso, para ter um ambiente completo de desenvolvimento no R, você também precisará de uma distribuição de Latex (como o MikTex para Windows ou MacTex para Mac); e, caso você esteja utilizando o Windows, a versão mais recente do RTools (para criar pacotes e integrar o R com C++).
Se você ainda não tem esses softwares em seu computador, baixe agora as versões compatíveis com seu sistema operacional e siga as instruções de instalação.
Este não é um livro para ser apenas lido e sim para ser acompanhado digitando os códigos de exemplo – ou, em último caso, copiando e colando. Os capítulos apresentam códigos em R com o resultado esperado, conforme a figura abaixo.
Ao final da maior parte dos capítulos, faremos muitos exercícios para a consolidação do conteúdo. Todos os exercícios terão uma resposta sugerida. Todavia, recomendo que você tente resolver sozinho antes de olhar a resposta.
R Gui
A instalação padrão do R vem com uma interface gráfica para o usuário (Graphical User Interface – GUI). No Windows, você encontrará o R no menu iniciar e no Mac você verá o ícone do R entre seus aplicativos. Nós não vamos utilizar o R Gui durante o livro. Entretanto, faremos um brevíssimo tour antes de passarmos para o RStudio.
Abra a interface gráfica do R em seu computador.A primeira tela que você verá é a do console. Agora, abra, também, uma tela de editor de texto em “file” -> “new script”.
Escreva os seguintes comandos no editor de texto e aperte CTRL+R (ou CMD+ENTER no Mac).
1+1
O comando será enviado para o console e você verá o resultado. Você poderia ter digitado o comando diretamente no console, mas isso não é uma boa prática. Acostume-se a sempre escrever em seu script (script é como chamamos o documento com os códigos de R que você produz).
## [1] 2
Escreva os seguinte comandos no editor de texto e repita o procedimento (CTRL+R):
plot(1:10)
Uma nova tela será aberta com o gráfico.
Por enquanto é só isso. Saia do R Gui escrevendo q()
no console ou apertando ALT+F4. O R irá perguntar se você deseja salvar a sua área de trabalho e o script. Clique em não para os dois casos.
Estamos saindo do R Gui pois agora iremos trabalhar no RStudio.
RStudio
Apesar de o R vir com uma interface gráfica interessante, existe um Ambiente de Desenvolvimento Integrado (Integrated Development Environment- IDE) chamado RStudio, com várias funcionalidades e gratuito.
O RStudio possui algumas vantagens em relação ao R Gui:
- Highlight do código;
- Autocomplete;
- Match automático de parenteses e chaves;
- Interface intuitiva para objetos, gráficos e script;
- Criação de “projetos” com interface para controle de versão;
- Facilidade na criação de pacotes;
- Interação com HTML, entre outras.
Abra o RStudio em seu computador e inicie um novo Script em “File” -> “New File” -> “New RScript”. Você também pode fazer isso com CTRL + SHIFT + N ou acessando o botão abaixo.
Podemos dividir a tela do RStudio em quatro grande áreas:
- Script: A tela superior esquerda do RStudio é o editor de texto onde você vai escrever seus Scripts. Ele possui code highlighting entre outras funcionalidades.
- Console: No canto inferior esquerdo fica o console. O console nada mais é do que uma seção aberta de R, em que os comando são executados.
- Área de trabalho e histórico: Ficam no canto superior direito. Os objetos criados e o histórico dos comandos podem ser acessados ali.
- Arquivos, Gráficos, Pacotes, Ajuda: Ficam no canto inferior direito. Você pode explorar pastas e arquivos diretamente do RStudio na aba “Files”; os gráficos que forem feitos apareceram na aba “Plots”. Os pacotes instalados em sua máquina estão listados em “Packages”. As ajudas das funções aparecem em “Help”. E o “Viewer” serve para visualização de páginas em HTML e JavaScript.
Comandos pelo Script
Como já dito, acostume-se a escrever o código no Script ao invés de ficar escrevendo diretamente no console. Para começarmos a nos familizarizar com o RStudio, escreva o código abaixo no Script:
1+1
E aperte CTRL+ENTER (CMD+ENTER no mac). Isso envia o comando para o console e o resultado é exibido logo abaixo.
## [1] 2
Agora escreva o seguinte código no Script.
# Gráfico dos números de 1 a 10 plot(1:10)
O primeiro comando # Gráfico dos números de 1 a 10
é, na verdade, um comentário. Comentários nos scripts do R são seguidos do símbolo #
, e tudo que estiver após #
não será executado. É uma boa prática comentar seu código! Isso faz com que ele seja de fácil manutenção, tanto para você mesmo (acredite, depois de um tempo você não lembrará o que fez) quanto para seus colegas.
O segundo comando diz ao R para plotar um gráfico. Aperte CTRL+ENTER nas duas linhas. O gráfico aparecerá no canto inferior direito do RStudio.
Agora digite o seguinte comando no editor e aperte CTRL+ENTER:
# atribuindo o valor 15 a x x <- 15
Atribuímos o valor 15 à variável x. Note que isso aparece no canto superior direito do RStudio.
Autocomplete e documentação
O RStudio tem autocomplete. No começo do seu aprendizado isto será bastante útil. Escreva apenas plo
e aperte Tab. O RStudio sugerirá diversas possibilidades de comandos e objetos que se iniciam com plo
:
Isso também funciona dentro de uma função para sabermos alguns dos argumentos disponíveis. Escreva plot()
e aperte Tab. Note que os argumentos da função plot
como x
, y
, ou type
apareceram.
Além do autocomplete, outra forma de enteder uma função é por meio da documentação do R. Para acessar a ajuda de uma função, utilize o comando ?
ou help()
seguido do nome da função.
?mean help(mean) # equivalente a ?mean
Note que no cando direito do RStudio apareceu uma página de ajuda sobre a função mean()
. A documentação das funções no R seguem mais ou menos este mesmo padrão.
A primeira coisa que vemos é mean {base}
indicando que se trata da função mean()
do pacote base
. Em Description há uma breve descrição do que é a função. Logo abaixo, em Usage vemos como utilizar o comando e, em Arguments, os parâmetros disponíveis. A seção Value explica o que a função mean()
retorna. Em seguida temos algumas referências, funções relacionadas e os exemplos.
Honestamente, é provável que no início você tenha dificuldades de entender a documentação do R, pois você não saberá o significado de muitos termos. Mas, mesmo assim, não deixe de consultá-la. E, sempre que hover, brinque com os exemplos.
Às vezes você não saberá exatamente o nome da função. Por exemplo, suponha que você queira gerar números aleatórios de uma distribuição normal multivariada, mas não se recorda o comando. Nestes caso, é possível realizar uma busca por texto.
??"normal distribution" help.search("normal distribution") # equivalente a ??"normal distribution"
Note que, entre os diversos resultados, aparece a função do pacote MASS
, mvrnorm()
, justamente o que você buscava.
Teclas de atalho
O RStudio possui muitas teclas de atalho que facilitam sua vida. Você pode ver a lista completa em “Help” -> “Keyboard Shortcuts”. Além do CTRL + ENTER, algumas teclas de atalho bastante úteis, que valem a pena você aprender agora no começo são:
- CTRL + 1: Passa o cursor para o script;
- CTRL + 2: Passa o cursor para o console;
- SETA PARA CIMA (no console): acessa o histórico de comandos anteriores.
- CTRL + ALT + SETA PARA ESQUERDA OU DIREITA: Navega entre as abas de script abertas (abra um novo script antes para testar).
- CTRL + SHIFT + P: “Previous command”, roda o último comando executado;
- CTRL + SHIFT + ENTER: “Source”. Executa o Script inteiro;
- CTRL + S: Salva o Script;
Muitos desses atalhos podem ser acessados via mouse (mas tente se acostumar a utilizar o teclado).
Outros atalhos interessantes são:
- CTRL + L: Limpa o console;
- CTRL + F: Busca (e substituição). Aceita REGEX (veremos REGEX posteriormente);
- CTRL + SHIFT + K: Compila “Notebook” em PDF, HTML ou Word (para isso você precisa ter uma distribuição de Latex e alguns pacotes instalados);
- ALT + SHIFT + K: Veja a lista de atalhos.
Pacotes
A principal forma de distribuição de códigos no R é por meio de pacotes. Um pacote pode ser entendido como um conjunto de códigos auto-contido que adiciona funcionalidades ao R.
Em termos mais simples, pacotes são funções do R escritas pelos usuários para resolver vários problemas, como: (i) ler e salvar uma planilha de Excel; (ii) rodar um modelo de random forest; (iii) analisar redes sociais etc. Atualmente existem mais de 6.000 pacotes de R. Ou seja, há pelo menos um pacote para quase qualquer problema de análise de dados que você imaginar. Veja essa pequeno vídeo que o Roger Peng fez sobre pacotes no R.
Para carregar um pacote, use a função library()
.
Carregar um pacote permite que você chame estas funções diretamente. Por exemplo, a função mvrnorm
, que gera números aleatórios de uma normal multivariada, está no pacote MASS
. Se você tentar chamar a função sem carregar o pacote, o R não a encontrará.
Sigma <- matrix(c(10,3,3,2),nrow=2,ncol=2) # Matriz de Variância-Covariânccia mu <- c(1, 10) # Médias x <- mvrnorm(n=100, mu, Sigma) # Tenta gerar 100 obs, mas dá erro
## Error in eval(expr, envir, enclos): não foi possível encontrar a função "mvrnorm"
Após carragar o pacote, o comando funciona normalmente:
library(MASS) # Carrega pacote x <- mvrnorm(n=100, mu, Sigma) # Agora funciona
Para ver quais pacotes estão carregados, utilize a função search()
. Note que o pacote MASS esta lá.
search()
## [1] "GlobalEnv" "package:MASS" "package:knitr" ## [4] "package:RWordPress" "tools:rstudio" "package:stats" ## [7] "package:graphics" "package:grDevices" "package:utils" ## [10] "package:datasets" "package:methods" "Autoloads" ## [13] "package:base"
Para descarregar um pacote, utilize a função detach()
seguido de package:nome_do_pacote
.
detach(package:MASS)
Às vezes pacotes tem funções com o mesmo nome. Neste caso, se ambos forem carregados, a função que prevalece é a do pacote que foi carregado por último. Uma forma de resolver este confilto é chamar a função utilizando o nome do pacote e o operador ::
. Neste caso não haverá ambiguidade e o R saberá exatamente que função utilizar.
# estamos dizendo ao R para buscar a função no pacote MASS x <- MASS::mvrnorm(n=100, mu, Sigma)
Você também pode carregar ou descarregar pacotes pelo menu do canto inferior direito do RStudio, clicando na caixa ao lado do nome do pacote.
Para instalar um pacote, use a função install.packages()
.
Por exemplo, o pacote dplyr
é muito utilizado para manipulação de dados e iremos estudá-lo mais a frente. Para instalá-lo, digite o seguinte comando.
install.packages("dplyr")
Para deletar um pacote, utilize a função remove.packages()
e para atualizar um pacote, a função update.packages()
.
CRAN
Grande parte dos pacotes do R estão centralizados em um repositório chamado CRAN (The Comprehensive R Archive Network), com diversos espelhos ao redor do mundo.
Tire um tempo agora para explorar um pouco o site oficial do R, www.r-project.org, e do CRAN, cran.r-project.org. Preste atenção principalmente nos seguinte itens:
—- (detalhar) —-
—- Ajuda online —-
—- Exemplo mínimo de uma análise de dados —-