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
04 de outubro de 2024
Classes de objetos: mais detalhes
Caracteres e Strings
Factors
Datas
Expressões simbólicas no R
Funções no R
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"
nchar(cidade)
## [1] 18
O espaço e a vírgula contam!
substr(cidade, start=1, stop=4)
## [1] "Belo"
cidade = paste(cidade, ", Brasil", sep="") cidade
## [1] "Belo Horizonte, MG, Brasil"
strsplit(cidade, split=", ") # retorna uma lista ## [[1]] ## [1] "Belo Horizonte" "MG" "Brasil" unlist(strsplit(cidade, split=", "))[3] ## [1] "Brasil"
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"
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
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
unclass(x) ## [1] 1 1 2 2 3 ## attr(,"levels") ## [1] "a" "b" "c"
x = factor(x, labels=c("Ativo", "Aposentado", "Pensionista")) x ## [1] Ativo Ativo Aposentado Aposentado Pensionista ## Levels: Ativo Aposentado Pensionista
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
factor(x, ordered=T) ## [1] Ativo Ativo Aposentado Aposentado Pensionista ## Levels: Ativo < Aposentado < Pensionista
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"
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
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
table(x)
## x ## S M L ## 3 4 3
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 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"
diff(datas)
## Time difference of 34 days
difftime(datas[2], datas[1], units="weeks")
## Time difference of 4.857143 weeks
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"
format(seq.datas, "%b") # mês em formato abreviado
## [1] "out" "out" "out" "nov" "nov"
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"
as.POSIXct(seq.datas)
## [1] "2012-10-16 UTC" "2012-10-23 UTC" "2012-10-30 UTC" "2012-11-06 UTC" ## [5] "2012-11-13 UTC"
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"
temp = Sys.setlocale("LC_TIME") temp
## [1] "Portuguese_Brazil.utf8"
Sys.setlocale("LC_TIME", "english" ) # CUIDADO!
## [1] "English_United States.1252"
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.utf8"
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 \]
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) )
x1:x2
ou x1*x2
.## 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).
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
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
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: 0x0000027e1a4bd370> ## <environment: namespace:base>
gamma ## function (x) .Primitive("gamma")
Primitive
é uma função internamente implementada.
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
m = matrix(x,3,2) m
## [,1] [,2] ## [1,] 1 6 ## [2,] 4 10 ## [3,] 6 5
mean(m)
## [1] 5.333333
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
rowSums()
e colSums()
podem ser mais rápidas que a função apply
.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
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
Como lembrar de tantos detalhes? O que cada argumento significa?
help
contém uma descrição da função, detalhes sobre os argumentos, o que a função retorna, exemplos…?quantile
Tab
).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()
.
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.
while()
executa os comandos (também entre chaves { }
) até que uma condição não seja mais verdadeira.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.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\).
# 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
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 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%"
ifelse( u>0.5, ("maior que 50%"), ("menor que 50%") )
## [1] "menor que 50%"
ifelse()
é vetorizável, e o if()
não.u = runif(3) u
## [1] 0.3721239 0.5728534 0.9082078
if(u> 0.5){ ("maior que 50%") }else{ ("menor que 50%") }
## Error in if (u > 0.5) {: the condition has length > 1
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%"