Competições de análise de dados: BoE e Kaggle


Quer mostrar suas habilidades de visualização de dados ou previsão? Seguem dois links:

Uma competição de visualização do Bank of England. Na verdade, a primeira competição deste tipo que o BoE lança. O prazo final é primeiro de maio. A final da competição ocorrerá em Londres e o BoE não pagará passagens para os finalistas (mas, se eu fosse você, tentaria chegar na final antes de decidir se isso será um problema). O prêmio é de 5.000 libras (mais de R$ 20.0000).

– Um site sobre o qual sempre quis falar mais detalhadamente por aqui, mas ainda não tive tempo, é o Kaggle. Resumidamente,  o Kaggle é um site de competições de modelagem preditiva em que as empresas colocam os problemas que gostariam de  solucionar (juntamente com um prêmio) e analistas de todo o mundo competem para produzir os melhores modelos. Atualmente há dois grandes prêmios sendo disputados:

  1. US$ 100.000,00 para quem criar o melhor modelo preditivo para sinais de retinopatia diabética com imagens do olho.
  2. US$ 30.000,00 para quem criar o melhor modelo preditivo para faturamento de restaurantes.

Além de outros prêmios de menor montante. Não somente isso, participantes do Kaggle que conseguem boas classificações também conseguem, em geral, bons empregos na área.

 

 

 

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 caso arg3 tem como default o valor default3). 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, o return() é 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 chamado dados.
  • dentro das chaves encontra-se o “corpo” da função, isto é, as operações que serão realizadas. Neste caso, transformamos dados em numeric, 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 vetor dados 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 ***

An Option Value Problem from Seinfeld


Para os fans de Seinfeld (e programação dinâmica), descobri recentemente este paper do Avinash Dixit.

Veja outros gag papers aqui.

Novo blog na área: Ben Bernanke 


Recém-saido do forno, blog do ex-presidente do FED, Ben Bernanke.

Dica do Danilo Freire.

Dilbert – economists and babble talk


 Dica do Douglas Araujo.

Focus – expectativas de mercado: inflação 8,12% e PIB -0.83%


  

Original aqui.

Quando um comentário de blog vira um post… e depois um paper.


Resumo da ópera:

1) Matthew Rognlie, estudante do MIT, postou um comentário no Marginal Revolution sobre um problema na obra de Piketty, O Capital no Século 21.

2) O argumento deu origem a alguns posts (I, II e outros) no próprio MR.  E obteve repercussão.

3) Isso acabou virando um artigo para o Brookings Papers on Economic Activity  comentado por economistas de peso, como, por exemplo, o Nobel Robert Solow.

Para uma versão maior da história,  há uma matéria bacana no Washington Post.

 

haven 0.1.0


Dados em SPSS, SAS e Stata? Novo pacote do Hadley chegou ao CRAN para facilitar a sua vida.

RStudio Blog

I’m pleased to announced that the new haven package is now available on CRAN. Haven makes it easy to read data from SAS, SPSS and Stata. Haven has the same goal as the foreign package, but it:

  • Can read binary SAS7BDAT files.
  • Can read Stata13 files.
  • Always returns a data frame.

(Haven also has experimental support for writing SPSS and Stata data. This still has some rough edges but please try it out and report any problems that you find.)

Haven is a binding to the excellent ReadStat C library by Evan Miller. Haven wouldn’t be possible without his hard work – thanks Evan! I’d also like to thank Matt Shotwell who spend a lot of time reverse engineering the SAS binary data format, and Dennis Fisher who tested the SAS code with thousands of SAS files.

Usage

Using haven is easy:

  • Install it, install.packages("haven"),
  • Load it, library(haven)

Ver o post original 416 mais palavras

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.

rstudio_str

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. Use rm() para remover apenas os dados de outubro (dica: você vai precisar do resultado de ls()).
  • Salve sua area de trabalho com o nome exercicio_objetos.RData. Salve apenas dados_2010_11_10 com o nome dados_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")

Fluxo de caixa descontado, O melhor jogo de tabuleiro do planeta, teoria dos jogos e casamentos.


Alguns links interessantes pós-carnaval. Hora de voltar ao ritmo.

– Damodaran fez um post bem bacana sobre fluxo de caixa descontado (FCD), mostrando que não é somente, digamos, um fluxo de caixa descontado. Vale a pena pela etimologia de FCDs mal-feitos e pelo checklist para saber se você está fazendo direito.

– Como fazer o melhor jogo de tabuleiro do planeta? War, Jogo da Vida e Banco Imobiliário estão entre os piores? Dois posts bacanas do 538 que queria ter compartilhado há algum tempo seguem agora aqui e aqui.

– Dollar auction na vida real, por  SMBC:

20141229