17 de março de 2023

Aula de Hoje

  • Classes de objetos: mais detalhes

    • Caracteres e Strings

    • Factors

    • Datas

  • Expressões simbólicas no R

  • Funções no R

    • Loops e Condições lógicas

Caracteres e Strings

Caracteres e Strings

  • Várias variáveis que encontramos em bancos de dados podem ser caracteres ou sequências de caracteres (strings).

  • Por isso, temos uma classe específica para esse tipo de dado.

cidade = "Belo Horizonte, MG"
class(cidade)
## [1] "character"
  • Vamos ver algumas funções úteis para manipular esse tipo de variável.

Caracteres e Strings

  • Por exemplo, se quisermos contar o número de caracteres em um string:
nchar(cidade)
## [1] 18

O espaço e a vírgula contam!

  • Ou extrair uma determinada parte do objeto:
substr(cidade, start=1, stop=4)
## [1] "Belo"

Caracteres e Strings

  • Para adicionar caracteres:
cidade = paste(cidade, ", Brasil", sep="")
cidade
## [1] "Belo Horizonte, MG, Brasil"
  • Dividir o string em uma lista de objetos:
strsplit(cidade, split=", ")    # retorna uma lista
## [[1]]
## [1] "Belo Horizonte" "MG"             "Brasil"

unlist(strsplit(cidade, split=", "))[3]
## [1] "Brasil"

Caracteres e Strings

  • E como estamos no R, é claro que podemos fazer isso usando vetores!
cidades = c("Belo Horizonte, MG", "São Paulo, SP", "Brasília, DF")
substr(cidades, nchar(cidades)-1, nchar(cidades))
## [1] "MG" "SP" "DF"
unlist(strsplit(cidades, ", "))[seq(2,6,by=2)]
## [1] "MG" "SP" "DF"

Caracteres e Strings

  • Em aplicações da Atuária, muitas vezes teremos caracteres e strings como input nos nossos códigos e modelos.

  • Mas também podemos precisar salvar caracteres como saída de uma função.

n_cid = length(cidades)
cat("Número de cidades: ",n_cid)
## Número de cidades:  3

Factors

Variáveis Categóricas

  • Em vários modelos estatísticos, informações armazenadas como caracteres podem ser incluídas como variáveis categóricas.

  • No R, podemos usar objetos da classe factor.

x = c( rep( letters[1:2], each=2), letters[3] )
x
## [1] "a" "a" "b" "b" "c"
x = factor(x)
x
## [1] a a b b c
## Levels: a b c

Factors

  • Factors são observações rotuladas de acordo com um conjunto pré-estabelecido de categorias.
unclass(x)
## [1] 1 1 2 2 3
## attr(,"levels")
## [1] "a" "b" "c"
  • Podemos mudar os rótulos facilmente:
x = factor(x, labels=c("Ativo", "Aposentado", "Pensionista"))
x
## [1] Ativo       Ativo       Aposentado  Aposentado  Pensionista
## Levels: Ativo Aposentado Pensionista

Factors

  • Se usarmos a variável x como covariável em um modelo de regressão, a categoria Ativo será a categoria de referência.

  • Para alterar a categoria de referência:

relevel(x, "Aposentado")
## [1] Ativo       Ativo       Aposentado  Aposentado  Pensionista
## Levels: Aposentado Ativo Pensionista
  • A variável categórica também pode ser ordenada:
factor(x, ordered=T)
## [1] Ativo       Ativo       Aposentado  Aposentado  Pensionista
## Levels: Ativo < Aposentado < Pensionista

Factors

  • Para criar matriz com variáveis dummy a partir das categorias:
model.matrix(~0+x)
##   xAtivo xAposentado xPensionista
## 1      1           0            0
## 2      1           0            0
## 3      0           1            0
## 4      0           1            0
## 5      0           0            1
## attr(,"assign")
## [1] 1 1 1
## attr(,"contrasts")
## attr(,"contrasts")$x
## [1] "contr.treatment"

Factors

  • Outra maneira de criar variáveis categóricas:
set.seed(1)
U = runif(10)
U
##  [1] 0.26550866 0.37212390 0.57285336 0.90820779 0.20168193 0.89838968
##  [7] 0.94467527 0.66079779 0.62911404 0.06178627
cut(U, breaks=3, labels=c("S","M","L"))
##  [1] S M M L S L L L M S
## Levels: S M L

Factors

  • Podemos fixar também os limites:
x = cut(U, breaks=c(0,.3,.8,1), labels=c("S","M","L"))
x
##  [1] S M M L S L L M M S
## Levels: S M L
  • E para acessar a frequência das categorias:
table(x)
## x
## S M L 
## 3 4 3

Factors

  • Também podemos gerar fatores com a função gl:
gl(n=3, k=2, labels=c("S","M","L"), ordered=T)
## [1] S S M M L L
## Levels: S < M < L

Datas

Datas

  • Datas no R podem estar armazenadas em objetos da classe POSIXlt ou POSIXct, ou na classe Date.

  • Existem algumas funções para criar e manipular datas no R.

datas = as.Date(c("16/10/12", "19/11/12"), format="%d/%m/%y")
class(datas)
## [1] "Date"
datas
## [1] "2012-10-16" "2012-11-19"

Datas

  • Diferença entre datas:
diff(datas)
## Time difference of 34 days
difftime(datas[2], datas[1], units="weeks")
## Time difference of 4.857143 weeks

Datas

  • Algumas funções que já conhecemos irão funcionar diferentemente para objetos do tipo Date.
seq.datas = seq(from=datas[1], to=datas[2], by=7)
seq.datas
## [1] "2012-10-16" "2012-10-23" "2012-10-30" "2012-11-06" "2012-11-13"
  • E podemos alterar o formato das datas:
format(seq.datas, "%b")     # mês em formato abreviado
## [1] "out" "out" "out" "nov" "nov"

Datas

  • Para saber o dia da semana ou o mês:
weekdays(seq.datas)
## [1] "terça-feira" "terça-feira" "terça-feira" "terça-feira" "terça-feira"
weekdays(datas[1]+1:4)
## [1] "quarta-feira" "quinta-feira" "sexta-feira"  "sábado"
months(seq.datas)
## [1] "outubro"  "outubro"  "outubro"  "novembro" "novembro"

Datas

  • Para extrair o dia do mês ou o ano:
as.POSIXct(seq.datas)
## [1] "2012-10-15 21:00:00 -03" "2012-10-22 22:00:00 -02"
## [3] "2012-10-29 22:00:00 -02" "2012-11-05 22:00:00 -02"
## [5] "2012-11-12 22:00:00 -02"
substr( as.POSIXct(seq.datas), start=1, stop=4 )
## [1] "2012" "2012" "2012" "2012" "2012"
strftime(seq.datas ,"%Y")  # mais rápido
## [1] "2012" "2012" "2012" "2012" "2012"

Datas

  • Os dias das semana e os meses serão impressos de acordo com a linguagem que o R está usando.
temp = Sys.setlocale("LC_TIME")
temp
## [1] "Portuguese_Brazil.1252"
  • Para mudar para inglês, por exemplo:
Sys.setlocale("LC_TIME", "english" )  # CUIDADO!
## [1] "English_United States.1252"

Datas

weekdays(seq.datas)
## [1] "Tuesday" "Tuesday" "Tuesday" "Tuesday" "Tuesday"
months(seq.datas)
## [1] "October"  "October"  "October"  "November" "November"
Sys.setlocale("LC_TIME", temp)  # voltar para a configuração original
## [1] "Portuguese_Brazil.1252"

Expressões Simbólicas

Expressões Simbólicas

  • Em alguns casos, precisamos escrever expressões simbólicas no R usando notação específica.

  • Por exemplo, ao ajustar uma regressão precisamos especificar a formula.

  • Ao ajustar uma regressão com o código lm(y ~ x1 + x2 + x3), estamos considerando o modelo:

\[Y_i = \beta_0 + \beta_1 \, X_{1,i} + \beta_2 \, X_{2,i} + \beta_3 \, X_{3,i} + \epsilon_i \]

Expressões Simbólicas

  • Em uma fórmula, o símbolo + significa inclusão (e não adição), e o símbolo - significa exclusão.

  • Se quisermos ajustar um modelo com as covariáveis \(X_1\) e \((X_2 + X_3)\):

lm(y ~ x1 + I(x2+x3) )
  • Para incluir a interação entre variáveis categóricas \(X_1\) e \(X_2\), podemos usar as expressões x1:x2 ou x1*x2.

Expressões Simbólicas - Exemplo

  • Primeiro vamos criar um banco de dados simples:
## Exemplo expressões simbólicas
set.seed(123)
df = data.frame( Y=rnorm(50), X1=as.factor(sample(LETTERS[1:4],size=50,replace=TRUE)), 
                 X2=as.factor(sample(1:3,size=50,replace=TRUE)) )
tail(df)
##              Y X1 X2
## 45  1.20796200  B  2
## 46 -1.12310858  B  1
## 47 -0.40288484  B  2
## 48 -0.46665535  C  3
## 49  0.77996512  D  3
## 50 -0.08336907  B  1

Exercício: Verifique a distribuição das variáveis Y, X1 e X2 geradas acima (estatísticas descritivas, histograma, tabela de frequência).

Expressões Simbólicas

  • Vamos ajustar o modelo de regressão mais básico:
reg = lm( Y ~ X1 + X2, data=df)
model.matrix(reg)[45:50,]
##    (Intercept) X1B X1C X1D X22 X23
## 45           1   1   0   0   1   0
## 46           1   1   0   0   0   0
## 47           1   1   0   0   1   0
## 48           1   0   1   0   0   1
## 49           1   0   0   1   0   1
## 50           1   1   0   0   0   0

Expressões Simbólicas

  • E se adicionarmos X1:X2 no modelo?
reg = lm( Y ~ X1 + X2 + X1:X2, data=df)
model.matrix(reg)[45:50,]
##    (Intercept) X1B X1C X1D X22 X23 X1B:X22 X1C:X22 X1D:X22 X1B:X23 X1C:X23
## 45           1   1   0   0   1   0       1       0       0       0       0
## 46           1   1   0   0   0   0       0       0       0       0       0
## 47           1   1   0   0   1   0       1       0       0       0       0
## 48           1   0   1   0   0   1       0       0       0       0       1
## 49           1   0   0   1   0   1       0       0       0       0       0
## 50           1   1   0   0   0   0       0       0       0       0       0
##    X1D:X23
## 45       0
## 46       0
## 47       0
## 48       0
## 49       1
## 50       0

Funções no R

Funções no R

  • Como o R é open-source, podemos ver o código fonte de todas as funções.

  • Por exemplo, a função factorial para computar o fatorial de um número:

factorial
## function (x) 
## gamma(x + 1)
## <bytecode: 0x00000000156d8900>
## <environment: namespace:base>
gamma
## function (x)  .Primitive("gamma")

Primitive é uma função internamente implementada.

Funções no R

  • Funções estatísticas básicas já estão implementadas no R, como sum(), mean(), var(), sd().
x = c(1,4,6,6,10,5)
var(x)
## [1] 8.666667
sum( (x-mean(x))^2 ) / (length(x) - 1)
## [1] 8.666667

Funções no R

  • Essas funções também funcionam para matrizes.
m = matrix(x,3,2)
m
##      [,1] [,2]
## [1,]    1    6
## [2,]    4   10
## [3,]    6    5
mean(m)
## [1] 5.333333

Funções no R

  • Para calcular média por linha ou coluna, usar a função apply():
apply(m, MARGIN=1, FUN=mean) # por linha
## [1] 3.5 7.0 5.5

apply(m, MARGIN=2, FUN=mean) # por coluna
## [1] 3.666667 7.000000
  • Para calcular soma por linha ou coluna, as funções rowSums() e colSums() podem ser mais rápidas que a função apply.

Funções no R

  • Variações da função apply:
g = c("M","F","F","M","M","M")
base = data.frame(x,g)
base
##    x g
## 1  1 M
## 2  4 F
## 3  6 F
## 4  6 M
## 5 10 M
## 6  5 M
tapply(x, g, mean) # calcula média de acordo com as categorias da var. g
##   F   M 
## 5.0 5.5

Funções no R

  • Tabela de Contingência 2x2:
base$status = c("Ativo", "Ativo", "Aposentado", "Pensionista", "Pensionista", "Ativo")
table(base$g, base$status)
##    
##     Aposentado Ativo Pensionista
##   F          1     1           0
##   M          0     2           2
addmargins( table(base$g, base$status) )
##      
##       Aposentado Ativo Pensionista Sum
##   F            1     1           0   2
##   M            0     2           2   4
##   Sum          1     3           2   6

Funções no R

  • Vimos várias funções no R para fazer diversos cálculos (e nem falamos de funções de pacotes!).

Como lembrar de tantos detalhes? O que cada argumento significa?

  • Consultar a página de ajuda de cada função! O help contém uma descrição da função, detalhes sobre os argumentos, o que a função retorna, exemplos…
?quantile
  • O RStudio também pode ajudar com alguns argumentos com o recurso de auto-completar (tecla Tab).

Funções no R

  • Mas pode ser que não tenha uma função que faça exatamente o que precisamos. Para esses cálculos, precisamos escrever nossas próprias funções.

  • Antes, vamos ver alguns comandos interessantes para criar loops e repetições de cálculos.

  • Computadores são excelentes para repetir uma tarefa por um número determinado de vezes ou até que uma condição seja atingida. Isso pode ser feito com os comandos for() e while().

Loops

  • O comando for() executa uma série de comandos (que estão entre as chaves { }) para uma variável em uma determinada sequência.

  • O loop for( i in 1:4 ){ ... } irá executar os comandos em {...} quatro vezes, variando a variável i que irá assumir os valores 1, 2, 3, 4.

  • O comando while() executa os comandos (também entre chaves { }) até que uma condição não seja mais verdadeira.
  • O loop while(i<5){ ...; i=i+1 } irá executar os comandos em {...}, incluindo i=i+1 até que a condição i<5 não seja mais verdadeira.

Loops

  • Por exemplo, vamos gerar um processo de Poisson, isto é, uma sequência no tempo de observações independentes que tem as seguintes propriedades:

    • o número de pontos tem distribuição de Poisson com intensidade \(\lambda\);

    • o tempo entre as ocorrências/chegadas dos pontos tem distribuição exponencial com parâmetro \(\lambda\).

  • Suponha que queremos gerar os tempos até as ocorrências até que o tempo total seja igual a 10. Vamos assumir \(\lambda=1\).

Loops

Exemplo: Processo de Poisson

# loop - Exemplo Processo de Poisson
T = NULL
while( sum(T) <= 10 ){
  T = c( T, rexp(1) )
}
T
## [1] 0.37275016 3.46359489 1.27402772 1.08148515 0.29695916 0.08416073 2.95340092
## [8] 1.96825225
cumsum(T)
## [1]  0.3727502  3.8363451  5.1103728  6.1918579  6.4888171  6.5729778  9.5263787
## [8] 11.4946310

Loops

  • Cuidado ao usar while()! O loop precisa estar bem especificado, ou você pode acabar criando um loop infinito.

  • Loops podem ser dispendiosos e ineficientes! Confira se o cálculo que você quer fazer não pode ser feito com outra função, como apply().

Condições lógicas

  • Podemos fazer operações que dependem da avaliação de uma expressão lógica.
# Condições lógicas
set.seed(1)
u = runif(1)
u
## [1] 0.2655087

if(u> 0.5){
  ("maior que 50%")
}else{
  ("menor que 50%")
}
## [1] "menor que 50%"

Condições lógicas

  • Podemos fazer operações que dependem da avaliação de uma expressão lógica.
ifelse( u>0.5, ("maior que 50%"), ("menor que 50%")  )
## [1] "menor que 50%"
  • A diferença é que ifelse() é vetorizável, e o if() não.

Condições lógicas

u = runif(3)
u
## [1] 0.3721239 0.5728534 0.9082078
if(u> 0.5){
  ("maior que 50%")
}else{
  ("menor que 50%")
}
## Warning in if (u > 0.5) {: a condição tem comprimento > 1 e somente o primeiro
## elemento será usado
## [1] "menor que 50%"

Condições lógicas

  • A diferença é que ifelse() é vetorizável, e o if() não.
ifelse( u>0.5, ("maior que 50%"), ("menor que 50%") )
## [1] "menor que 50%" "maior que 50%" "maior que 50%"