Ajuste de modelos lineares e mistos no ambiente R

09 e 10 de Outubro de 2014 - Piracicaba - SP
Prof. Dr. Walmes M. Zeviani
Escola Superior de Agricultura “Luiz de Queiroz” - USP
Lab. de Estatística e Geoinformação - LEG
Pós Graduação em Genética e Melhoramento de Plantas Departamento de Estatística - UFPR

Trabalhando com objetos

Sequências, repetições e grides

##-----------------------------------------------------------------------------
## Sequências regulares.

1:5
2*(1:5)-1
3*(1:5)-2

x <- seq(from=1, to=12, by=2); x
x <- seq(from=1, to=12, length.out=5); x
x <- seq(from=1, by=3, length.out=5); x
x <- seq(to=20, by=3, length.out=6); x

##-----------------------------------------------------------------------------
## Repetições regulares.

x <- rep(1, times=5); x

x <- rep(1:3, times=3); x
x <- rep(1:3, each=3); x

##-----------------------------------------------------------------------------
## Grides.

da <- expand.grid(x1=1:3, x2=1:3)
da

da <- expand.grid(trat=c("tratado","controle"),
                  bloco=c("I","II","III"))
da

Números aleatórios

##-----------------------------------------------------------------------------
## Números uniformes.

x <- runif(10); x

##-----------------------------------------------------------------------------
## Números da distribuição normal padrão.

x <- rnorm(10, mean=0, sd=1)

##-----------------------------------------------------------------------------
## Amostra aleatória de população discreta finita com e sem reposição.

u <- c("Superman","Batman","Aquaman","Flash","Green Lantern")
sample(u, size=3)

u <- c("Iron Man","Thor","Captain America","Hulk","Black Widow","Hawkeye")
sample(u, size=10, replace=TRUE)

Ordenar, inverter e aleatorizar

##-----------------------------------------------------------------------------
## Um vetor com número uniformes.

x <- runif(6)

## As posições do menor para o maior valor.
order(x)

## O vetor ordenado do menor para o maior.
sort(x, decreasing=FALSE)
x[order(x)]

## Os valores em ordem inversa.
rev(x)

## Ordenando um vetor por valores em outro.
u <- c("Iron Man","Thor","Captain America","Hulk","Black Widow","Hawkeye")
u[order(x)]

## O vetor com os elementos aleatorizados.
sample(u)

Estatísticas simples

##-----------------------------------------------------------------------------
## Um vetor com dados de precipitação.

precip
x <- precip

sum(x)
mean(x)
median(x)
min(x)
max(x)
range(x)
fivenum(x)
IQR(x)
quantile(x, probs=c(0.05, 0.95))
var(x)
sd(x)
mad(x)
diff(range(x))
100*sd(x)/mean(x)

require(fBasics)
## Loading required package: fBasics
## Loading required package: MASS
## Loading required package: methods
## Loading required package: timeDate
## Loading required package: timeSeries
## 
## Attaching package: 'fBasics'
## 
## The following object is masked from 'package:base':
## 
##     norm
skewness(x)
kurtosis(x)

require(EnvStats)
## Loading required package: EnvStats
## 
## Attaching package: 'EnvStats'
## 
## The following objects are masked from 'package:timeDate':
## 
##     kurtosis, skewness
## 
## The following object is masked from 'package:MASS':
## 
##     boxcox
## 
## The following object is masked from 'package:stats':
## 
##     predict.lm
## Algumas funções são substituídas.

skewness(x)
kurtosis(x)
cv(x)

summaryStats(x)
summaryFull(x)

Família apply

A família *apply e agregados representa um conjunto de funções destinadas à tarefas por estrato e/ou margem (índice). Tarefas assim foram recentemente batizadas de SAC (split-apply-combine). São essas funções do pacote básico do R que permiter obter médias por tratamento, coeficientes de variação por resposta (por coluna). Isoladamente cada uma delas têm seu papel e juntas resolvem uma série de problemas.

##-----------------------------------------------------------------------------
## Os membros da família *apply.

## De uso simples e frequente.
##  apply  : on Arrays margins (não é aaply para evitar cacofonia).
##  lapply : on Lists itens or vector elements or data.frame columns.
##  sapply : lapply that Simplifies when possible.
##  tapply : on a ragged array, return as Tabular format.

## De uso menos frequente.
##  mapply : lapply over Multiple list or vector arguments.
##  eapply : on Environments.
##  rapply : Recursive.
##  vapply : Vectorized.
##  dendrapply : related to dendrogramns.
##  kernapply : related kernel.

## Além destas, tem-se outras funções que são os agregados da família.
##  by(): divide de acordo com estrato e aplica algo.
##  aggragate(): divide por estrato e aplica por coluna.
##  sweep(): operações entre matrizes e vetores.

##-----------------------------------------------------------------------------
## tapply.

str(npk)

## Média de yield para cada nível de N.
r <- tapply(npk$yield, npk$N, mean)
r

class(r)

## Média de yield para combinando os níveis de N e P.
r <- tapply(npk$yield, list(npk$N, npk$P), mean)
r

## Melhor usa com with() para simplificar a declaração.
r <- with(npk, tapply(yield, list(N, P), mean))
r

## O mesmo considerando N, P e K.
r <- with(npk, tapply(yield, list(N, P, K), mean))
r

## Nomes na lista geram nomes para as dimensões do array.
r <- with(npk, tapply(yield, list(Nitro=N, Phos=P, Pot=K), mean))
r

##-----------------------------------------------------------------------------
## aggregate.

## A aggragate funciona com uso de formula, além de poder ser usada como a
## tapply(). O resultado é em data.frame.

s <- with(npk,
          aggregate(cbind(Y=yield), list(Nitro=N, Phos=P, Pot=K), mean))
s

## Será obtido o mesmo, mas usando uma fórmula para representar o que se
## deseja.

s <- aggregate(yield~N+P+K, data=npk, mean)
s

## Diferente da tapply, a aggregate pode ter mais de uma variáveis
## resposta. Por falta de outra variável resposta, será usando o log de
## yield.

s <- aggregate(cbind(y=yield, log.y=log(yield))~N+P+K, data=npk, mean)
s

##-----------------------------------------------------------------------------
## by.

by(data=npk, INDICES=with(npk, N), FUN=nrow)

r <- with(npk, by(yield, INDICES=N, FUN=mean)); r
str(r)
c(is.list(r), is.array(r))

r <- with(npk, by(yield, INDICES=list(N=N, P=P, K=K), FUN=mean)); r
str(r)
c(is.list(r), is.array(r))

class(r)   ## Como é de classe by ele é mostrado de forma diferente.
unclass(r) ## Se a classe é removida, então é mostrado como array comum.

Em resumo, as funções tapply, aggregate e by fazem tarefas por estrato. Em outras palavras, separam os valores em um (ou mais) vetores respeitando valores em outro (ou mais) e em seguida aplicam uma função. A diferença é como declarar e o que é retornado.

##-----------------------------------------------------------------------------
## apply.

Titanic
str(Titanic)
is.array(Titanic)
dimnames(Titanic)

sum(Titanic[ ,1, , ]) ## Total de homens.
sum(Titanic[ ,2, , ]) ## Total de mulheres.

apply(Titanic, MARGIN=2, sum) ## Totais das margens para Sex.
apply(Titanic, MARGIN=1, sum) ## Para Class.

apply(Titanic, MARGIN=c(1,2), sum) ## Class e Sex.
apply(Titanic, MARGIN=c(2,4), sum) ## Sex e Survived.
apply(Titanic, MARGIN=c(3,4), sum) ## Age e Survived.

str(HairEyeColor)
dimnames(HairEyeColor)

apply(HairEyeColor, MARGIN=1, sum) ## Por cor de cabelo.
apply(HairEyeColor, MARGIN=2, sum) ## Por cor de olhos.
apply(HairEyeColor, MARGIN=3, sum) ## Por cor de sexo.

##-----------------------------------------------------------------------------
## lapply e sapply.

is.list(rock)
str(rock) ## Todas as colunas tem conteúdo numérico.

lapply(rock, mean)  ## Média
lapply(rock, range) ## Extremos.

## Porque trata-se de um data.frame, dá pra usar apply também.
apply(rock, MARGIN=2, mean)
apply(rock, MARGIN=2, range)

sapply(rock, mean)  ## Foi possível simplificar para um vetor.
sapply(rock, range) ## Foi possível simplificar para uma matriz.

str(iris)
lapply(iris, is.numeric) ## Quais colunas tem conteúdo numérico?
lapply(iris, class)      ## Qual a classe?

## Também se pode usar apply pois iris é um data.frame.
apply(iris, MARGIN=2, is.numeric)

sapply(iris, class) ## Foi possível simplificar.

## Não foi possível simplificar.
sapply(iris, summary)

## Separar as colunas que são númericas e então pedir o summary.
i <- sapply(iris, is.numeric); i
sapply(iris[,i], summary) ## Simplificou.

Em resumo, as funções apply, lapply e sapply aplicam funções sobre índices, ou seja, em arranjos as operações são varrendo linhas, colunas, etc e em listas são varrendo os ítens. A diferença de lapply e sapply é que a última tenta simplificar o resultado acomodanto em um tipo de objeto mais simples que uma lista quando possível.

Funções

##-----------------------------------------------------------------------------
## Função para calcular a hipotenusa de um triângulo retângulo.

hipo <- function(a, b){ ## Argumentos.
    h <- sqrt(a^2+b^2)  ## Processo/procedimento.
    return(h)           ## Retorno.
}

## Explorando o objeto.
class(hipo)
mode(hipo)
args(hipo)
body(hipo)
str(hipo)

## Usando a função.
hipo(3, 4)
hipo(3, 4.6)
hipo(3, 3)

## Note que ela opera vetorialmente.
hipo(a=3, b=c(4, 4.6, 3))

##-----------------------------------------------------------------------------
## Abrindo algumas funções.

body(plot)                       ## Indica que é uma função genérica.
methods(generic.function="plot") ## As várias 'faces' da plot.

## Abrindo a função.
plot.default

plot.ecdf
## plot.ts

## As com asteriscos podem ser abertas assim.
getAnywhere(plot.histogram)
## getS3method(f="plot", class="histogram")

## Abrindo a função sequência.
methods(generic.function="seq")
getAnywhere(seq.default)

## Abrindo a matrix.
matrix

runif ## Chama uma função escrita em C.

##-----------------------------------------------------------------------------
## Incluindo o argumento ângulo.

hipo2 <- function(a, b, angle){
    h2 <- a^2+b^2-2*cos(angle)
    return(sqrt(h2))
}

hipo2(3, 4, angle=pi/2)
hipo(3, 4)

hipo2(3, 4, angle=pi/2+0.3)
hipo2(3, 4, angle=pi/2-0.3)

##-----------------------------------------------------------------------------
## Ângulo com valor default de 90 graus (pi/2 radianos).

hipo3 <- function(a, b, angle=pi/2){
    h2 <- a^2+b^2-2*cos(angle)
    return(sqrt(h2))
}

hipo3(3, 4)
hipo3(3, 4, angle=pi/2+0.5)

##-----------------------------------------------------------------------------
## Três implementações.

baskara1 <- function(a, b, c){
    x1 <- (-b-sqrt(b^2-4*a*c))/(2*a)
    x2 <- (-b+sqrt(b^2-4*a*c))/(2*a)
    return(c(x1, x2))
}

baskara2 <- function(a, b, c){
    s <- sqrt(b^2-4*a*c)
    d <- 2*a
    x1 <- (-b-s)/d
    x2 <- (-b+s)/d
    return(c(x1, x2))
}

baskara3 <- function(a, b, c){
    x <- (-b+c(-1,1)*sqrt(b^2-4*a*c))/(2*a)
    return(x)
}

a <- 2; b <- 1; c <- -3
curve(a*x^2+b*x+c, -3, 3)
abline(h=0, lty=2)

baskara1(a, b, c)
baskara2(a, b, c)
baskara3(a, b, c)

##-----------------------------------------------------------------------------
## Tempo para 50 mil excussões de cada uma.

system.time(replicate(50000, baskara1(a, b, c)))
system.time(replicate(50000, baskara2(a, b, c)))
system.time(replicate(50000, baskara3(a, b, c)))

## As implementação diferentes implicam em custos diferentes.

##-----------------------------------------------------------------------------
## Parábola sem raízes.

a <- 2; b <- 1; c <- 3
curve(a*x^2+b*x+c, -5, 5)
abline(h=0, lty=2)
baskara1(a, b, c)

##-----------------------------------------------------------------------------
## a==0, então não tem curvatura.

a <- 0; b <- 1; c <- 3
curve(a*x^2+b*x+c, -5, 5)
baskara1(a, b, c)

## Como notificar da origem desses erros?

##-----------------------------------------------------------------------------
## Colocando mensagens de erro para testes feitos nos argumentos.

baskara4 <- function(a, b, c){
    if (a==0){
        stop("O argumento `a` tem que ser diferente de zero.")
    }
    delta <- b^2-4*a*c
    if (delta<=0) {
        stop("Função sem raíz pois `delta` é não positivo.")
    }
    x <- (-b+c(-1,1)*sqrt(delta))/(2*a)
    return(x)
}

baskara4(2, 1, -3)
baskara4(0, 1, -3)
baskara4(2, 1, 3)

##-----------------------------------------------------------------------------
## Função que calcula as raízes da equação e ainda os valores no ponto
## crítico (x, y). O ponto crítico sempre existe se a!=0. As raízes
## podem não existir.

baskara5 <- function(a, b, c){
    if (a==0){
        stop("O argumento `a` tem que ser diferente de zero.")
    }
    d <- 2*a
    delta <- b^2-4*a*c
    if (delta<=0){
        warning("Função sem raíz pois `delta` é não positivo.")
        r <- c(NA, NA)
    } else {
        r <- (-b+c(-1,1)*sqrt(delta))/d
    }
    x <- -b/d
    y <- a*x^2+b*x+c
    L <- list(x=x, y=y, r=r)
    return(L)
}

a <- baskara5(2, 1, -3)
str(a)

curve(2*x^2+1*x-3, -2, 2)
abline(v=a$x, h=a$y, col=2, lty=2)
abline(v=a$r, h=0, col=3, lty=2)

##-----------------------------------------------------------------------------
## Argumentos como vetores, usa posição.

baskara6 <- function(abc){
    if (length(abc)==3L){
        x <- (-abc[2]+c(-1,1)*sqrt(abc[2]^2-4*abc[1]*abc[3]))/(2*abc[1])
        return(x)
    } else {
        stop("O vetor `abc` deve ter comprimento 3.")
    }
}

baskara6(c(2,1,-3))
baskara6(c(2,1,-3,500))
baskara6(c(2,1))

##-----------------------------------------------------------------------------
## Argumentos como vetores nomeados.

baskara7 <- function(abc){
    if (length(abc)==3L & all(names(abc)%in%c("a","b","c"))){
        x <- (-abc["b"]+c(-1,1)*
              sqrt(abc["b"]^2-4*abc["a"]*abc["c"]))/(2*abc["a"])
        return(x)
    } else {
        stop("O vetor `abc` deve ter comprimento 3 e ser nomeado.")
    }
}

baskara7(c(a=2, b=1, c=-3))
baskara7(c(b=1, a=2, c=-3))
baskara7(c(b=1, a=2, m=-3))

##-----------------------------------------------------------------------------
## Argumentos como vetores ou lista nomeados.

baskara8 <- function(abc){
    if (is.vector(abc)) abc <- as.list(abc)
    if (is.list(abc) & length(abc)==3L & all(names(abc)%in%c("a","b","c"))){
        x <- with(abc,
                  (-b+c(-1,1)*sqrt(b^2-4*a*c))/(2*a))
        return(x)
    } else {
        stop("O objeto `abc` deve ser vetor/lista nomeado de 3 elementos.")
    }
}

baskara8(c(a=2, b=1, c=-3))
baskara8(list(a=2, b=1, c=-3))
baskara8(data.frame(a=2, b=1, c=-3))

print(sessionInfo(), locale=FALSE)
## R version 3.1.1 (2014-07-10)
## Platform: x86_64-pc-linux-gnu (64-bit)
## 
## attached base packages:
## [1] methods   stats     graphics  grDevices utils     datasets  base     
## 
## other attached packages:
## [1] EnvStats_1.0.2     fBasics_3010.86    timeSeries_3010.97 timeDate_3010.98  
## [5] MASS_7.3-34        rmarkdown_0.2.68   knitr_1.6         
## 
## loaded via a namespace (and not attached):
## [1] digest_0.6.4     evaluate_0.5.5   formatR_1.0      htmltools_0.2.6  stabledist_0.6-6
## [6] stringr_0.6.2    tools_3.1.1
Sys.time()
## [1] "2014-10-07 14:52:37 BRT"