Preparando as fórmulas…

Apêndice BCálculos

Descrevemos brevemente dois pacotes computacionais que podem ser usados para todos os cálculos feitos no texto. Recomendamos que os estudantes se familiarizem com pelo menos um deles. A descrição do R é bastante completa, ao menos para os cálculos baseados no material deste texto, ao passo que é necessária outra referência para aprender o Minitab.

B.1 Usando o R

O R é um pacote estatístico gratuito que pode ser baixado e instalado no seu computador (veja http://cran.r-project.org/). Um manual gratuito também está disponível nesse site.

Depois de instalar o R no seu sistema, você pode iniciá-lo clicando no ícone correspondente (ou, em sistemas Unix, simplesmente digitando “R”). Aparece então uma janela, chamada R Console, que contém algum texto e um prompt “>”, depois do qual você digita os comandos. Os comandos são separados por novas linhas ou por “;”. A saída dos comandos também é exibida nessa janela, a menos que seja propositalmente direcionada para outro lugar. Para sair do R, digite q() depois do prompt. Para saber mais sobre qualquer coisa no R, um recurso conveniente é usar o Help da barra de menus, no alto da janela do R. Outra opção é digitar ?name depois do prompt (e pressionar Enter) para exibir informações sobre name; por exemplo, ?q abre uma página com informações sobre o comando de encerramento q.

Operações e Funções Básicas

Um comando básico avalia uma expressão, como

> 2+3
[1] 5

que soma 2 e 3 e produz a resposta 5. Outra possibilidade é atribuir o valor da expressão a uma variável, como em

> a <- 2

em que <- (sinal de menor seguido de sinal de menos) atribui o valor 2 a uma variável chamada a. Também se pode usar = na atribuição, como em a = 2, mas usaremos <-. Podemos então verificar essa atribuição simplesmente digitando a e apertando Enter, o que faz o valor de a ser impresso.

> a
[1] 2

Observe que o R diferencia maiúsculas de minúsculas, de modo que A seria uma variável diferente de a. Há algumas restrições na escolha de nomes para variáveis e vetores, mas você não errará se sempre começar o nome com uma letra.

Podemos atribuir os valores de um vetor usando a função de concatenação c(), como em

> b <- c(1,1,1,3,4,5)
> b
[1] 1 1 1 3 4 5

o que cria um vetor chamado b com seis valores. Podemos acessar a \(i\)-ésima entrada de um vetor b referindo-nos a ela como b[i]. Por exemplo,

> b[3]
[1] 1

imprime a terceira entrada de b, isto é, 1. Outra possibilidade é usar o comando scan para a entrada de dados. Por exemplo,

> b <- scan()
1:  1 1 1 3 4 5
7:
Read 6 items
> b
[1] 1 1 1 3 4 5

faz a mesma atribuição. Observe que, com o comando scan, simplesmente digitamos os dados e encerramos a entrada com uma linha em branco. Também podemos usar scan para ler dados de um arquivo; para isso, remetemos o leitor a ?scan.

Às vezes queremos vetores cujas entradas seguem algum padrão. Muitas vezes podemos usar a função rep para isso. Por exemplo, x <- rep(1,20) cria um vetor de 20 uns. Padrões mais complicados podem ser obtidos; para isso, remetemos o leitor a ?rep.

A aritmética básica pode ser feita com variáveis e vetores usando + (adição), - (subtração), * (multiplicação), / (divisão) e ^ (exponenciação). Essas operações são feitas componente a componente. Por exemplo, poderíamos multiplicar cada componente de b por ele mesmo com

> b*b
[1] 1 1 1 9 16 25

ou multiplicar cada elemento de b por 2, como em

> 2*b
[1] 2 2 2 6 8 10

o que realiza essa operação.

Há várias funções disponíveis no R, como abs(x) (calcula o valor absoluto de x), log(x) (calcula o logaritmo natural de x), exp(x) (calcula \(e\) elevado à potência x), sin(x), cos(x), tan(x) (que calculam as funções trigonométricas), sqrt(x) (que calcula a raiz quadrada de x), ceiling(x) e floor(x) (que calculam o teto e o piso de x). Quando uma dessas funções é aplicada a um vetor x, ela devolve um vetor de mesmo comprimento, com a função aplicada a cada elemento do vetor original. Há inúmeras funções especiais disponíveis no R, mas duas importantes são gamma(x), que devolve a função gama1 aplicada a x, e lgamma(x), que devolve o logaritmo natural da função gama.

Há também funções que devolvem um único valor quando aplicadas a um vetor. Por exemplo, min(x) e max(x) devolvem, respectivamente, o menor e o maior elemento de x; length(x) dá o número de elementos de x; e sum(x) dá a soma dos valores de x.

O R também opera com as quantidades lógicas TRUE (ou T, para verdadeiro) e FALSE (ou F, para falso). Valores lógicos são gerados por condições que são verdadeiras ou falsas. Por exemplo,

> a <- c(-3,4,2,-1,-5)
> b <- a>0
> b
[1] FALSE TRUE TRUE FALSE FALSE

compara cada elemento do vetor a com 0, devolvendo TRUE quando ele é maior que 0 e FALSE caso contrário, e esses valores lógicos são guardados no vetor b. Podem ser usados os seguintes operadores lógicos: <, <=, >=, >, == (igualdade), != (desigualdade), além de & (conjunção), | (disjunção) e ! (negação). Por exemplo, se criarmos um vetor lógico c assim:

> c <- c(T,T,T,T,T)
> b&c
[1] FALSE TRUE TRUE FALSE FALSE
> b|c
[1] TRUE TRUE TRUE TRUE TRUE

então um elemento de b&c é TRUE quando os dois elementos correspondentes de b e c são TRUE, enquanto um elemento de b|c é TRUE quando pelo menos um dos elementos correspondentes de b e c é TRUE.

Às vezes podemos ter variáveis que assumem valores de caractere. Embora sempre seja possível codificar esses valores como números, não há necessidade disso, pois o R também lida com variáveis de valores de caractere. Por exemplo, os comandos

> A <- c('a','b')
> A
[1] "a" "b"

criam um vetor de caracteres A, contendo dois valores, a e b, e depois imprimem esse vetor. Observe que pusemos os valores de caractere entre aspas simples ao fazer a atribuição.

Às vezes faltam valores nos dados, e eles são então listados como NA (not available, não disponível). Operações com valores faltantes criam valores faltantes. Além disso, uma operação impossível, como 0/0, produz NaN (not a number, não é um número).

Vários objetos podem ser criados durante uma sessão do R. Para ver os que foram criados até o momento na sua sessão, use o comando ls(). Você pode remover qualquer objeto da sua área de trabalho usando o comando rm. Por exemplo, rm(x) remove o vetor x.

Funções de Probabilidade

O R tem várias funções embutidas para calcular a fda, a fda inversa, a função densidade2 ou de probabilidade e para gerar amostras aleatórias das distribuições comuns que encontramos em probabilidade e estatística. Elas se distinguem por um prefixo e pelo nome da distribuição base. Alguns dos nomes de distribuições são dados na tabela a seguir.

DistribuiçãoNome no R e argumentos
betabeta(\(\cdot\),a,b)
binomialbinom(\(\cdot\),n,p)
qui-quadradochisq(\(\cdot\),df)
exponencialexp(\(\cdot\),lambda)
Ff(\(\cdot\),df1,df2)
gamagamma(\(\cdot\),alpha,lambda)
geométricageom(\(\cdot\),p)
hipergeométricahyper(\(\cdot\),N,M,n)
binomial negativanbinom(\(\cdot\),k,p)
normalnorm(\(\cdot\),mu,sigma)
Poissonpois(\(\cdot\),lambda)
tt(\(\cdot\),df)
uniformeunif(\(\cdot\),min,max)

Como sempre, é preciso tomar cuidado com a distribuição gama. O caminho mais seguro é incluir outro argumento junto com a distribuição para indicar se lambda é um parâmetro de taxa (a densidade é \((\Gamma(\alpha))^{-1}\lambda^{\alpha}x^{\alpha-1}e^{-\lambda x}\)) ou um parâmetro de escala (a densidade é \((\Gamma(\alpha))^{-1}\lambda^{-\alpha}x^{\alpha-1}e^{-x/\lambda}\)). Assim, gamma(\(\cdot\),alpha,rate=lambda) indica que lambda é um parâmetro de taxa, e gamma(\(\cdot\),alpha,scale=lambda) indica que ele é um parâmetro de escala.

O argumento indicado por \(\cdot\) é especificado de acordo com a finalidade do comando que usa o nome da distribuição. Para obter a fda de uma distribuição, ponha p antes do nome; então \(\cdot\) é o valor em que se quer calcular a fda. Para obter a fda inversa de uma distribuição, ponha q antes do nome; então \(\cdot\) é o valor em que se quer calcular a fda inversa. Para obter a função densidade ou de probabilidade, ponha d antes do nome; então \(\cdot\) é o valor em que se quer calcular a densidade ou a função de probabilidade3. Para obter amostras aleatórias, ponha r antes do nome; então \(\cdot\) é o tamanho da amostra4 aleatória que se quer gerar.

Por exemplo,

> x <- rnorm(4,1,2)
> x
[1] -0.2462307 2.7992913 4.7541085 3.3169241

gera uma amostra de tamanho 4 da distribuição \(N(1, 2^2)\) e a atribui ao vetor x. O comando

> dnorm(3.2,2,.5)
[1] 0.04478906

calcula a densidade \(N(2; 0{,}25)\) em 3,2, enquanto

> pnorm(3.2,2,.5)
[1] 0.9918025

calcula a fda \(N(2; 0{,}25)\) em 3,2, e

> qnorm(.025,2,.5)
[1] 1.020018

dá o quantil 0,025 da distribuição \(N(2; 0{,}25)\).

Se temos dados guardados num vetor x, podemos amostrar valores de x, com ou sem reposição, usando a função sample. Por exemplo, sample(x,n,T) gera uma amostra de tamanho n de x com reposição, enquanto sample(x,n,F) gera uma amostra de tamanho n de x sem reposição (observe que, neste último caso, n não pode ser maior que length(x)).

Às vezes é conveniente poder repetir uma simulação de modo que os mesmos valores aleatórios sejam gerados. Para isso, pode-se usar o comando set.seed. Por exemplo, set.seed(12345) fixa a semente em 12345.

Tabulação de Dados

O comando table está disponível para tabular dados. Por exemplo, table(x) devolve uma tabela com a lista dos valores distintos encontrados em x e suas frequências de ocorrência em x. Essa tabela pode ser atribuída a uma variável com

y <- table(x)

para análise posterior (veja o trecho O Teste Qui-Quadrado, mais adiante).

Se x e y são vetores de mesmo comprimento, então table(x,y) produz uma tabulação cruzada, isto é, conta o número de vezes em que se obtém cada valor possível de \((x, y)\), em que \(x\) pode ser qualquer um dos valores assumidos em x e \(y\) pode ser qualquer um dos valores assumidos em y.

Gráficos de Dados

O R tem vários comandos disponíveis para fazer gráficos de dados. Por exemplo, suponha que temos uma amostra de tamanho \(n\) guardada no vetor x.

O comando hist(x) fornece um histograma de frequências dos dados, com os pontos de corte escolhidos automaticamente pelo R. Podemos acrescentar argumentos opcionais a hist. Seguem alguns dos argumentos disponíveis.

breaks — Um vetor que contém os pontos de corte.

freq — Uma variável lógica; quando freq=T (o padrão), obtém-se um histograma de frequências e, quando freq=F, obtém-se um histograma de densidade.

Por exemplo, hist(x,breaks=c(-10,-5,-2,0,2,5,10),freq=F) faz o gráfico de um histograma de densidade com pontos de corte \(-10, -5, -2, 0, 2, 5, 10\), em que tivemos o cuidado de garantir que min(x) \(> -10\) e max(x) \(< 10\).

Se y é outro vetor de mesmo comprimento que x, podemos produzir um diagrama de dispersão5 de y contra x com o comando plot(x,y). O comando plot(x,y,type="l") fornece um diagrama de dispersão de y contra x, mas agora com os pontos ligados por linhas. O comando plot(x) faz o gráfico dos valores de x contra seus índices. O comando plot(ecdf(x)) faz o gráfico da fda empírica dos dados de x.

Um boxplot dos dados de x é obtido com o comando boxplot(x). Boxplots lado a lado dos dados de x, y, z etc. podem ser obtidos com boxplot(x,y,z).

Um gráfico de probabilidade normal6 dos valores de x pode ser obtido com o comando qqnorm(x).

Um gráfico de barras pode ser obtido com o comando barplot. Por exemplo,

> h <- c(1,2,3)
> barplot(h)

produz um gráfico de barras com 3 barras de alturas 1, 2 e 3.

Há muitos outros aspectos dos gráficos no R que dão ao usuário um controle considerável sobre a aparência dos gráficos. Remetemos o leitor ao manual para uma discussão mais ampla sobre eles.

Inferência Estatística

O R tem uma abordagem poderosa para ajustar modelos e fazer inferência sobre eles. Os modelos são especificados pelo símbolo ~. Não discutimos isso por completo aqui; apenas indicamos como usá-lo para tratar os modelos de regressão linear simples e múltipla (em que a resposta e os preditores são todos quantitativos), os modelos com um e com dois fatores (em que a resposta é quantitativa, mas os preditores são categóricos) e o modelo de regressão logística7 (em que a resposta é categórica, mas os preditores são quantitativos). Suponha, então, que temos um vetor y com os valores da resposta.

Estatísticas Básicas

A função mean(y) devolve a média dos valores de y, var(y) devolve a variância8 amostral dos valores de y, e sd(y) dá o desvio padrão9 amostral. O comando median(y) devolve a mediana de y, enquanto quantile(y,p) devolve os quantis amostrais especificados no vetor de probabilidades p. Por exemplo, quantile(y,c(.25,.5,.75)) devolve a mediana e o primeiro e o terceiro quartis. A função sort(y) devolve um vetor com os valores de y ordenados do menor para o maior, e rank(y) dá os postos dos valores de y.

O Teste \(t\)

Para os dados em y, podemos usar o comando

> t.test(y,mu=1,alternative="two.sided",conf.level=.95)

para fazer um teste \(t\). Ele calcula o valor-p do teste de \(H_0: \mu = 1\) e forma um intervalo de confiança10 0,95 para \(\mu\).

O Teste Qui-Quadrado

Suponha que y contenha um vetor de contagens para k caselas e que prob contenha as probabilidades hipotéticas dessas caselas. Então o comando

> chisq.test(y,p=prob)

faz o teste qui-quadrado para avaliar essa hipótese. Observe que y também poderia corresponder a uma tabela unidimensional.

Se x e y são dois vetores de mesmo comprimento, então chisq.test(x,y) faz um teste qui-quadrado de independência na tabela formada pela tabulação cruzada das entradas de x e y. Se primeiro criarmos essa tabulação cruzada na tabela t usando a função table, então chisq.test(t) faz esse teste.

Regressão Linear Simples

Suponha que temos um único preditor11, com valores no vetor x. O modelo de regressão linear simples12 \(E(y \mid x) = \beta_1 + \beta_2 x\) é então especificado no R por y~x. Chamamos y~x de fórmula do modelo e a lemos como “y é modelado como um modelo linear envolvendo x”. Para fazer o ajuste (o que fizemos aqui para um conjunto específico de dados), usamos o comando de ajuste de modelos lineares lm, como segue. O comando

> regexamp <- lm(y~x)

faz os cálculos de ajuste e de inferência sobre esse modelo e atribui o resultado a uma estrutura chamada regexamp. Qualquer outro nome válido poderia ter sido usado para essa estrutura. Podemos agora usar várias funções do R para extrair vários itens de interesse. Por exemplo,

> summary(regexamp)
Call:
lm(formula = y~x)
Residuals:
  Min      1Q    Median 3Q     Max
-4.2211 -2.1163 0.3248 1.7255 4.3323
Coefficients:
 Estimate          Std.  Error  t value Pr(>|t|)
(Intercept) 6.5228   1.2176     5.357   4.31e-05 ***
    x       1.7531   0.1016    17.248   1.22e-12 ***
--
Signif.  codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’
0.1 ‘ ’ 1
Residual standard error:  2.621 on 18 degrees of freedom
Multiple R-squared:  0.9429, Adjusted R-squared:  0.9398

F-statistic:  297.5 on 1 and 18 DF, p-value:  1.219e-12

usa a função summary para nos dar todas as informações de que precisamos. Por exemplo, a reta ajustada é dada por \(6{,}5228 + 1{,}7531x\). O teste de \(H_0: \beta_2 = 0\) tem valor-p de \(1{,}22 \times 10^{-12}\), de modo que temos forte evidência contra \(H_0\). Além disso, o \(R^2\) é dado por 94,29%. Itens individuais podem ser acessados por várias funções do R; para isso, remetemos o leitor a ?lm.

Regressão Linear Múltipla

Se temos dois preditores quantitativos nos vetores x1 e x2, podemos proceder exatamente como na regressão linear simples para ajustar o modelo de regressão linear \(E(y \mid x_1, x_2)\) \({}= \beta_1 + \beta_2 x_1\) \({}+ \beta_2 x_2\).13 Por exemplo, os comandos

> regex <- lm(y~x1+x2)
> summary(regex)

ajustam o modelo linear acima, atribuem os resultados à estrutura regex, e então a função summary imprime (omitido aqui) todas as quantidades relevantes. Lemos y~x1+x2 como “y é modelado como um modelo linear envolvendo x1 e x2”. Em particular, obtêm-se a estatística \(F\) e o valor-p associado a ela para o teste de \(H_0: \beta_2 = \beta_3 = 0\).

Isso se generaliza imediatamente para modelos de regressão linear com \(k\) preditores quantitativos \(x_1, \ldots, x_k\). Além disso, suponha que queremos testar se o modelo envolve apenas \(x_1, \ldots, x_l\), para \(l < k\). Usamos lm para ajustar o modelo com todos os \(k\) preditores e atribuímos isso a regex, e também usamos lm para ajustar o modelo que envolve só \(l\) preditores e atribuímos isso a regex1. Então o comando anova(regex,regex1) fornece a estatística \(F\) e seu valor-p para o teste de \(H_0: \beta_{l+1} = \cdots = \beta_k = 0\).

ANOVA com Um e com Dois Fatores

Suponha agora que \(A\) denota um preditor categórico que assume dois níveis, \(a_1\) e \(a_2\). Observe que os valores de \(A\) podem ser de caractere em vez de numéricos; por exemplo, x é um vetor de caracteres contendo os valores a1 e a2, usados para indicar em que nível o valor correspondente de y foi observado. Em qualquer caso, precisamos transformar isso num fator A, com o comando

> A <- factor(x)

para que A possa ser usado na análise. Então o comando

> aov(y~A)

produz a tabela de ANOVA com um fator. Naturalmente, aov também trata fatores com mais de dois níveis. Para obter as médias das caselas, use o comando tapply(y,A,mean).

Suponha que exista um segundo fator \(B\), com 5 níveis \(b_1, \ldots, b_5\). Se esse é o fator B no R, então o comando

> aov(y~A+B+A:B)

produz a ANOVA com dois fatores para testar interações entre os fatores A e B. Para obter as médias das caselas, use o comando tapply(y,list(A,B),mean). O comando aov(y~A+B) produz a tabela de ANOVA supondo que não há interações.

Regressão Logística

Suponha que temos dados binários guardados no vetor y e que x contém os valores correspondentes de um preditor quantitativo. Então podemos usar o comando de modelo linear generalizado glm para ajustar o modelo de regressão logística \(P(Y = 1 \mid x)\) \({}= \exp\{\beta_1\) \({}+ \beta_2 x\}/(1 + \exp\{\beta_1 + \beta_2 x\})\). Os comandos

> logreg <- glm(y~x,family=binomial)
> summary(logreg)

ajustam o modelo de regressão logística, atribuem os resultados a logreg, e então o comando summary imprime esse material. Isso nos dá as estimativas dos \(\beta_i\), seus erros padrão e os valores-p para testar que \(\beta_i = 0\).

Comandos de Controle e Programas em R

Um comando de controle básico tem a forma if (expr1) expr2 else expr3, em que expr1 assume um valor lógico, expr2 é executado se expr1 é T, e expr3 é executado se expr1 é F. Por exemplo, se x é uma variável que assume o valor \(-2\), então

> if (x<0) {y <- -1} else {y <- 1}

faz com que seja atribuído a y o valor \(-1\). Observe que a parte else do comando pode ser omitida.

O comando for (name in expr) expr2 executa expr2 para cada valor de name em expr1.14 Por exemplo,

> for (i in 1:10) print(i)

imprime o valor da variável i à medida que são atribuídos a i, sucessivamente, os valores de \(\{1, 2, \ldots, 10\}\). Observe que m:n é, no R, uma abreviação da sequência \((m, m + 1, \ldots, n)\). Outro exemplo:

> for (i in 1:20) y[i] <- 2^i

cria um vetor y com 20 entradas, em que o \(i\)-ésimo elemento de y é igual a \(2^i\).

O break encerra um laço, possivelmente com base em alguma condição que se verifique, enquanto next interrompe o processamento da iteração atual e avança o índice do laço. Tanto break quanto next valem apenas para o mais interno de laços aninhados.

Comandos no R podem ser agrupados colocando-os entre chaves, {expr1; expr2; ...}. Os comandos dentro das chaves são executados como uma unidade. Por exemplo,

> for (i in 1:20) {print(i); y[i] <- 2^i}; print(y[i])}

faz com que i seja impresso, y[i] seja atribuído e y[i] seja impresso, tudo dentro de um laço for.15

Muitas vezes, quando um cálculo é complicado, como um que envolve laços, é melhor pôr todos os comandos do R num único arquivo e executar o arquivo em modo de lote. Por exemplo, suponha que você tem um arquivo prog.R contendo código R. Então o comando source("pathname/prog.R") faz com que todos os comandos do arquivo sejam executados.

Muitas vezes é conveniente pôr comentários nos programas em R para explicar o que as linhas de código fazem. Uma linha de comentário é precedida por # e, claro, não é executada.

Funções Definidas pelo Usuário

O R também permite funções definidas pelo usuário. A sintaxe da definição de uma função é a seguinte.

nome da função <- function(argumentos) {
corpo da função;
return(valor de retorno);
}

Por exemplo, a função a seguir calcula o coeficiente de variação amostral dos dados x.

coef_var <- function(x) {
    result <- sd(x)/mean(x);
    return(result);
}

Então, se depois quisermos calcular o coeficiente de variação dos dados y, basta digitar coef_var(y).

Arranjos e Listas

Um vetor de comprimento \(m\) também pode ser visto como um arranjo unidimensional de comprimento \(m\). O R pode lidar com arranjos multidimensionais, por exemplo, arranjos \(m \times n\), \(m \times n \times p\) etc. Se a é um arranjo tridimensional, então a[i,j,k] se refere à entrada na posição \((i, j, k)\) do arranjo. Há várias operações que podem ser feitas com arranjos; para elas, remetemos o leitor ao manual. Mais adiante neste manual, discutiremos o caso especial dos arranjos bidimensionais, também conhecidos como matrizes. Por ora, pensamos nos arranjos apenas como objetos em que guardamos dados.

Uma estrutura de dados muito geral no R é dada por uma lista. Uma lista é parecida com um arranjo, com várias diferenças importantes.

  1. Qualquer entrada de um arranjo é referida pelo seu índice. Já qualquer entrada de uma lista pode ser referida por um nome de caracteres. Por exemplo, os coeficientes da regressão ajustada são referidos por regex$coefficients depois do ajuste do modelo linear regex <- lm(y ~ x1 + x2). O cifrão ($) é o operador de referência a entradas, isto é, varname$entname indica a entrada “entname” da lista “varname”.
  2. Enquanto um arranjo guarda dados de um só tipo, uma lista pode guardar quaisquer objetos do R. Por exemplo, a entrada coefficients de um objeto de regressão linear é um vetor numérico, e a entrada model é uma lista.
  3. Os operadores de referência são diferentes: arr[i] se refere à \(i\)-ésima entrada do arranjo arr, e lst[[i]] se refere à \(i\)-ésima entrada da lista lst. Observe que \(i\) pode ser o nome da entrada, isto é, lst$entname e lst[['entname']] se referem aos mesmos dados.

Exemplos

Consideramos agora alguns exemplos relativos a seções ou exemplos específicos do texto principal. Para executar qualquer um destes códigos, é preciso primeiro definir as funções. Para isso, carregue o código com o comando source. Depois, é preciso especificar os argumentos das funções. Observe que as linhas das listagens podem estar quebradas de modo pouco natural e continuar na linha seguinte.

Exemplo B.1.1 Bootstrap16 no Exemplo 6.4.2

O código R a seguir gera amostras bootstrap e calcula a mediana de cada uma delas. Para executar este código, digite y <- bootstrap_median(m,x), em que m é o número de amostras bootstrap, x contém a amostra original e as medianas das reamostras são guardadas em y. A estatística a que se aplica o bootstrap pode ser trocada substituindo median no código.

#   Example B.1.1
#   function name: bootstrap_median
#   parameters:
#       m   resample size
#       x   original data
#   return value:
#       a vector of resampled medians
#   description: resamples and stores its median
  bootstrap_median <- function(m,x) {
      n <- length(x);
      result <- rep(0,m);
      for(i in 1:m) result[i] <- median(sample(x,n,T));
   return(result);
  }
Exemplo B.1.2 Amostragem da Distribuição a Posteriori17 no Exemplo 7.3.1

O código R a seguir gera uma amostra de da distribuição a posteriori conjunta no Exemplo 7.3.1.18 Para executar uma simulação, digite

post <- post_normal(m,x,alpha0,beta0,mu0,tau0square)

em que m é o tamanho da amostra de Monte Carlo e os demais argumentos são os hiperparâmetros da priori. O resultado é uma lista chamada (neste caso) post, em que post$mu e post$sigmasq contêm os valores gerados de \(\mu\) e \(\sigma^2\), respectivamente. Por exemplo,

> x <- c(11.6714, 1.8957, 2.1228, 2.1286, 1.0751, 8.1631,
1.8236, 4.0362, 6.8513, 7.6461, 1.9020, 7.4899, 4.9233,
8.3223, 7.9486);
> post <- post_normal(10**4,x,2,1,4,2)
> z <- sqrt(post$sigmasq)/post$mu

executa uma simulação como no Exemplo 7.3.1, com \(N = 10^4\).

#   Example B.1.2
#   function name: post_normal
#   parameters:
#       m       sample size
#       x       data
#       alpha0  shape parameter for 1/sigma^2
#       beta0   rate parameter for 1/sigma^2
#       mu0     location parameter for mu
#       tau0square  variance ratio parameter for mu
#   returned values:
#       mu      sampled mu
#       sigmasq sampled sigmasquare
#   description: samples from the posterior distribution
#   in Example 7.3.1
#
post_normal<-function(m,x,alpha0,beta0,mu0,tau0square){
# set the length of the data
n <- length(x);
# the shape and rate parameters of the posterior dist.
# alpha_x = first parameter of the gamma dist.
#         = (alpha0 + n/2)
alpha_x <- alpha0 + n/2
# beta_x  = the rate parameter of the gamma dist.
beta_x  <- beta0 + (n-1)/2 * var(x) + n*(mean(x)-mu0)**2/
           2/(1+n*tau0square);
# mu_x    = the mean parameter of the normal dist.
mu_x    <- (mu0/tau0square+n*mean(x))/(n+1/tau0square);
# tausq_x = the variance ratio parameter of the normal
#           distribution
tausq_x <- 1/(n+1/tau0square);
# initialize the result
result  <- list();
result$sigmasq <- 1/rgamma(m,alpha_x,rate=beta_x);
result$mu      <- rnorm(m,mu_x,sqrt(tausq_x *
                      result$sigmasq));
return(result);
}
Exemplo B.1.3 Cálculo das Estimativas e dos Erros Padrão no Exemplo 7.3.1

Uma vez que temos uma amostra de valores da distribuição a posteriori de \(\psi\) guardada em psi, podemos calcular o intervalo dado pelo valor médio19 de psi mais ou menos 3 desvios padrão como medida da precisão da estimação20.

# Example B.1.3
# set the data
x <- c(11.6714, 1.8957, 2.1228, 2.1286, 1.0751, 8.1631,
  1.8236, 4.0362, 6.8513, 7.6461, 1.9020, 7.4899,
  4.9233, 8.3223, 7.9486);
post <- post_normal(10**4,x,2,1,4,2);
# compute the coefficient of variation
psi <- sqrt(post$sigmasq)/post$mu;
psi_hat <- mean(psi <= .5);
psi_se  <- sqrt(psi_hat * (1-psi_hat))/sqrt(length(psi));
# the interval
cq <- 3
cat("The three times s.e. interval is ",
  "[",psi_hat-cq*psi_se, ", ", psi_hat+cq*psi_se,"]\n");
Exemplo B.1.4 Uso do Amostrador de Gibbs21 no Exemplo 7.3.2

Para executar esta função, digite

post<-gibbs_normal(m,x,alpha0,beta0,lambda,mu0,
tau0sq,burnin=0)

pois isso cria uma lista chamada post, em que post$mu e post$sigmasq contêm os valores gerados de \(\mu\) e \(\sigma^2\), respectivamente. Observe que o argumento burnin recebe um inteiro não negativo22 e indica que queremos descartar os primeiros burnin valores de \(\mu\) e \(\sigma^2\) e reter os últimos m. O valor padrão é burnin=0.

# Example B.1.4
#   function name: gibbs_normal
#   parameters
#     m         the size of posterior sample
#     x         data
#     alpha0    shape parameter for 1/sigma^2
#     beta0     rate parameter for 1/sigma^2
#     lambda    degree of freedom of Student's t-dist.
#     mu0       location parameter for mu
#     tau0sq    scale parameter for mu
#     burnin    size of burn in. the default value is 0.
#
#   returnrd values
#       mu       sampled mu's
#       sigmasq  sampled sigma^2's
#   description: samples from the posterior in Ex. 7.3.2
#
gibbs_normal <- function(m,x,alpha0,beta0,lambda,mu0,
                         tau0sq,burnin=0) {
  # initialize the result
  result <- list();
  result$sigmasq <- result$mu <- rep(0,m);
  # set the initial parameter
  mu      <- mean(x);
  sigmasq <- var(x);
  n       <- length(x);

  # set parameters
  alpha_x <- n/2 + alpha0 + 1/2;
  # loop
  for(i in (1-burnin):m) {
   # update v_i's
   v       <- rgamma(n,(lambda+1)/2,rate=((x-mu)**2/
                          sigmasq/lambda+1)/2);
   # update sigma-square
   beta_x <-(sum(v*(x-mu)**2)/lambda+(mu-mu0)**2/
                               tau0sq)/2+beta0;
   sigmasq<- 1/rgamma(1,alpha_x,rate=beta_x);
   # update mu
   r       <- 1/(sum(v)/lambda+1/tau0sq);
   mu      <- rnorm(1,r*(sum(v*x)/lambda+mu0/tau0sq),
                       sqrt(r*sigmasq));
   # burnin check
   if(i < 1) next;
   result$mu[i]      <- mu;
   result$sigmasq[i] <- sigmasq;
  }
  result$psi <- sqrt(result$sigmasq)/result$mu;
  return(result);
}
Exemplo B.1.5 Formação de Lotes no Exemplo 7.3.2

O código R a seguir divide uma série de dados em lotes e calcula as médias dos lotes. Para executar o código, digite y<-batching(k,x) para pôr no vetor y as médias dos lotes consecutivos de tamanho k dos dados do vetor x.

#   Example B.1.5
#   function name: batching
#   parameters:
#       k   size of each batch
#       x   data
#   return value:
#       an array of the averages of each batch
#   description: this function separates the data x into
#   floor(length(x)/k) batches and returns the array of
#   the averages of each batch
batching <- function(k,x) {
    m <- floor(length(x)/k);
    result <- rep(0,m);
    for(i in 1:m) result[i] <- mean(x[(i-1)*k+(1:k)]);
    return(result);
}
Exemplo B.1.6 Simulação de uma Amostra da Distribuição da Estatística de Discrepância23 no Exemplo 9.1.2

O código R a seguir gera uma amostra da estatística de discrepância especificada no Exemplo 9.1.2. Para gerar a amostra, digite y<-discrepancy(m,n) para pôr em y uma amostra de tamanho m, em que n é o tamanho do conjunto de dados original. Este código pode ser facilmente modificado para gerar amostras de outras estatísticas de discrepância.

#   Example B.1.6
#   function name: discrepancy
#   parameters:
#       m   resample size
#       n   size of data
#   return value:
#       an array of m discrepancies
#   description: this function generates m discrepancies
#   when the data size is n
discrepancy <- function(m,n) {
    result <- rep(0,m);
    for(i in 1:m) {
        x    <- rnorm(n);
        xbar <- mean(x);
        r    <- (x-xbar)/sqrt((sum((x-xbar)**2)));
        result[i] <- -sum(log(r**2));
    }
    return(result/n);
}
Exemplo B.1.7 Geração a partir de uma Distribuição Dirichlet24 no Exemplo 10.2.3

O código R a seguir gera uma amostra de uma distribuição Dirichlet\((\alpha_1, \alpha_2, \alpha_3, \alpha_4)\). Para gerar dessa distribuição, primeiro atribua valores ao vetor alpha e depois digite ddirichlet(n,alpha), em que n é o tamanho da amostra.

#   Example B.1.7
#   function name: ddirichlet
#   parameters:
#       n      sample size
#       alpha  vector(alpha1,...,alphak)
#   return value:
#       a (n x k) matrix. rows are i.i.d. samples
#   description: this function generates n random samples
#   from Dirichlet(alpha1,...,alphak) distribution
ddirichlet <- function(n,alpha) {
    k <- length(alpha);
    result <- matrix(0,n,k);
    for(i in 1:k) result[,i] <- rgamma(n,alpha[i]);
    for(i in 1:n) result[i,] <- result[i,] /
                                     sum(result[i,]);
    return(result);
}

Matrizes

Uma matriz pode ser vista como uma coleção de valores de dados com dois índices ou como um arranjo retangular de dados. Assim, se a é uma matriz, então a[i,j] é o elemento \((i, j)\) de a. Observe que a[i,] se refere à \(i\)-ésima linha de a e a[,j] se refere à \(j\)-ésima coluna de a. Se uma matriz tem \(m\) linhas e \(n\) colunas, ela é uma matriz \(m \times n\), e \(m\) e \(n\) são chamados de dimensões da matriz.

Talvez a maneira mais simples de criar matrizes seja com os comandos cbind e rbind. Por exemplo,

> x<-c(1,2,3)
> y<-c(4,5,6)
> a<-cbind(x,y)
> a
 x y
[1,] 1 4
[2,] 2 5
[3,] 3 6

cria os vetores x e y, e o comando cbind toma x como primeira coluna e y como segunda coluna da matriz \(3 \times 2\) recém-criada a. Observe que, na impressão de a, as colunas continuam rotuladas x e y, embora ainda possamos nos referir a elas como a[,1] e a[,2]. Podemos remover esses nomes de colunas com o comando colnames(a)<-NULL. Do mesmo modo, o comando rbind trata os vetores dados como argumentos como as linhas de uma matriz. Para determinar o número de linhas e de colunas de uma matriz a, podemos usar os comandos nrow(a) e ncol(a). Também podemos criar uma matriz diagonal usando o comando diag. Se x é um vetor \(n\)-dimensional, então diag(x) é uma matriz \(n \times n\) com as entradas de x na diagonal e 0 nas demais posições. Se a é uma matriz \(m \times n\), então diag(a) é o vetor com as entradas tiradas da diagonal principal de a. Para criar uma matriz identidade \(n \times n\), use diag(n).

Há várias operações que podem ser feitas com matrizes. Se as matrizes a e b são \(m \times n\), então a+b é a matriz \(m \times n\) formada pela soma das matrizes componente a componente. A transposta de a é a matriz \(n \times m\) t(a), cuja \(i\)-ésima linha é igual à \(i\)-ésima coluna de a. Se c é um número, então c*a é a matriz \(m \times n\) formada pela multiplicação de cada elemento de a por c. Se a é \(m \times n\) e b é \(n \times p\), então a%*%b é a matriz \(m \times p\) produto (Apêndice A.4) de a e b. Um vetor numérico é tratado como vetor coluna na multiplicação de matrizes. Observe que a*b também está definido quando a e b têm a mesma dimensão, mas esse é o produto componente a componente das duas matrizes, bem diferente do produto de matrizes.

Se a é uma matriz \(m \times m\), a inversa de a é obtida como solve(a). O comando solve devolve um erro se a matriz não tiver inversa. Se a é uma matriz quadrada, então det(a) calcula o determinante de a.

Consideramos agora uma aplicação importante.

Exemplo B.1.8 Ajuste de Modelos de Regressão

Suponha que o vetor \(n\)-dimensional y corresponda ao vetor de respostas e que a matriz \(n \times k\) V corresponda à matriz de planejamento quando ajustamos um modelo de regressão linear dado por \(E(y \mid V) = V\beta\). A estimativa de mínimos quadrados25 de \(\beta\) é dada por b, calculada em

b<-solve(t(V)%*%V)%*%t(V)%*%y

com o vetor de valores preditos p e os resíduos r dados por

> p<-V%*%b
> r<-y-p

com comprimentos ao quadrado

> slp<-t(p)%*%p
> slr<-t(r)%*%r

em que slp é o comprimento ao quadrado de p e slr é o comprimento ao quadrado de r. Observe que a matriz solve(t(V)%*%V) é usada para formar intervalos de confiança e testes para os \(\beta_i\) individuais. Praticamente todos os cálculos envolvidos no ajuste e na inferência para o modelo de regressão linear podem ser feitos com cálculos matriciais no R como os que ilustramos.26

Pacotes

Há muitos pacotes escritos para estender a capacidade do R básico. É muito provável que, se você tiver uma necessidade de análise de dados que não possa ser atendida pelo R, encontre um pacote disponível gratuitamente para acrescentar. Remetemos o leitor a ?install.packages e ?library para saber mais sobre isso.

B.2 Usando o Minitab

Todos os cálculos encontrados neste texto foram feitos com o Minitab. Esse pacote de software estatístico é muito fácil de aprender e de usar. Outros pacotes, como o SAS ou o R (ver a Seção B.1), também poderiam ser usados com essa finalidade.

A maior parte dos cálculos foi feita usando o Minitab como uma calculadora, isto é, os dados eram digitados e então se recorria a vários comandos do Minitab para obter as quantidades desejadas. Esses cálculos não exigem nenhuma programação.

Houve alguns cálculos, porém, que envolveram um pouco de programação. Em geral, tratava-se de um cálculo em que muitas operações tinham de ser feitas repetidas vezes, e por isso convinha usar um laço. Em cada um desses casos, registramos aqui o código do Minitab que usamos nesses cálculos. Como mostram os exemplos a seguir, esses programas nunca foram muito complicados.

Os estudantes podem usar esses programas como modelos para escrever os próprios programas no Minitab. Na verdade, a linguagem é tão simples que achamos que qualquer pessoa que programe em outra linguagem consegue ler esses programas e usá-los como modelos do mesmo jeito. Basta pensar nos símbolos c1, c2 etc. como vetores (arrays), em que o \(i\)-ésimo elemento do vetor c1 é acessado por c1(i). Além disso, há as constantes k1, k2 etc.

Um programa do Minitab se chama macro e precisa começar com a instrução gmacro e terminar com a instrução endmacro. A primeira instrução depois de gmacro dá um nome ao programa. Comentários num programa, postos ali para explicar o código, começam com note.

Se o arquivo que contém o programa se chama prog.txt e está gravado no diretório raiz de uma unidade de disco chamada c, então o comando do Minitab

MTB> %c:/prog.txt

executa o programa. Qualquer saída será impressa na janela Session (se você tiver usado um comando print) ou guardada na planilha (worksheet) do Minitab.

Mais detalhes sobre o Minitab podem ser encontrados no Help do programa. A seguir, damos alguns exemplos de macros do Minitab usadas no texto.

Exemplo B.2.1 Bootstrap no Exemplo 6.4.2

O código do Minitab a seguir gera 1000 amostras bootstrap a partir dos dados em c1, calcula a mediana de cada uma dessas amostras e depois calcula a variância amostral dessas medianas.

gmacro
bootstrapping
base 34256734
note - original sample is stored in c1
note - bootstrap sample is placed in c2 with each one
note   overwritten
note - medians of bootstrap samples are stored in c3
note - k1 = size of data set (and bootstrap samples)
let k1=15
do k2=1:1000
sample 15 c1 c2;
replace.
let c3(k2)=median(c2)
enddo
note - k3 equals (6.4.5)
let k3=(stdev(c3))**2
print k3
endmacro
Exemplo B.2.2 Amostragem da Distribuição a Posteriori no Exemplo 7.3.1

O código do Minitab a seguir gera uma amostra de tamanho \(10^4\) da distribuição a posteriori conjunta do Exemplo 7.3.1. Observe que, no software Minitab, a densidade Gama\((\alpha, \beta)\) tem a forma \((\beta^{-\alpha}/\Gamma(\alpha))x^{\alpha-1}e^{-x/\beta}\). Assim, para gerar de uma distribuição Gama\((\alpha, \beta)\), como definida neste livro, precisamos tomar no Minitab o segundo parâmetro de forma igual a \(1/\beta\).

gmacro
normalpost
note - the base command sets the seed for the random
note   numbers
base 34256734
note - the parameters of the posterior
note - k1 = first parameter of the gamma distribution
note      = (alpha_0 + n/2)
let k1=9.5
note - k2 = 1/beta
let k2=1/77.578
note - k3 = posterior mean of mu
let k3=5.161
note - k4 = (n + 1/(tau_0 squared) )^(-1)
let k4=1/15.5
note - main loop
note - c3 contains generated value of sigma**2
note - c4 contains generated value of mu
note - c5 contains generated value of coefficient of
         variation
do k5=1:10000
random 1 c1;
gamma k1 k2.
let c3(k5)=1/c1(1)
let k6=sqrt(k4/c1(1))
random 1 c2;
normal k3 k6.
let c4(k5)=c2(1)
let c5(k5)=sqrt(c3(k5))/c4(k5)
enddo
endmacro
Exemplo B.2.3 Cálculo das Estimativas e dos Erros Padrão no Exemplo 7.3.1

Temos uma amostra de \(10^4\) valores da distribuição a posteriori de \(\psi\), guardada em C5. Os cálculos a seguir usam essa amostra para calcular uma estimativa27 da probabilidade a posteriori de que \(\psi \le 0{,}5\) (k1), e também o erro padrão28 dessa estimativa (k2), a estimativa menos três vezes o seu erro padrão (k3) e a estimativa mais três vezes o seu erro padrão (k4).

let c6=c5 le .5
let k1=mean(c6)
let k2=sqrt(k1*(1-k1))/sqrt(10000)
let k3=k1-3*k2
let k4=k1+3*k2
print k1 k2 k3 k4
Exemplo B.2.4 Uso do Amostrador de Gibbs no Exemplo 7.3.2

O código do Minitab a seguir gera uma cadeia de \(10^4\) valores com o amostrador de Gibbs descrito no Exemplo 7.3.2.

gmacro
gibbs
base 34256734
note - data sample is stored in c1
note - starting value for mu.
let k1=mean(c1)
note - starting value for sigma**2
let k2=stdev(c1)
let k2=k2**2
note - lambda
let k3=3
note - sample size
let k4=15
note - n/2 + alpha_0 + 1/2
let k5=k4/2 +2+.5
note - mu_0
let k6=4
note - tau_0**2
let k7=2
note - beta_0
let k8=1
let k9=(k3/2+.5)
note - main loop
do k100=1:10000
note - generate the nu_i in c10
do k111=1:15
let k10=.5*(((c1(k111)-k1)**2)/(k2*k3) +1)
let k10=1/k10
random 1 c2;
gamma k9 k10.
let c10(k111)=c2(1)
enddo
note - generate sigma**2 in c20
let c11=c10*((c1-k1)**2)
let k11=.5*sum(c11)/k3+.5*((k1-k6)**2)/k7 +k8
let k11=1/k11
random 1 c2;
gamma k5 k11.
let c20(k100)=1/c2(1)
let k2=1/c2(1)
note - generate mu in c21
let k13=1/(sum(c10)/k3 +1/k7)
let c11=c1*c10/k3
let k14=sum(c11)+k6/k7
let k14=k13*k14
let k13=sqrt(k13*k2)
random 1 c2;
normal k14 k13.
let c21(k100)=c2(1)
let k1=c2(1)
enddo
endmacro
Exemplo B.2.5 Divisão em Lotes no Exemplo 7.3.2

O código do Minitab a seguir divide em lotes a amostra gerada pelo código da amostragem de Gibbs29 do Exemplo 7.3.2 e calcula as médias dos lotes.

gmacro
batching
note - k2= batch size
let k2=40
note - k4 holds the batch sums
note - c1 contains the data to be batched (10000 data values)
note - c2 will contain the batch means (250 batch means)
do k10=1:10000/40
let k4=0
do k20=0:39
let k3=c1(k10+k20)
let k4=k4+k3
enddo
let k11=floor(k10/k2) +1
let c2(k11)=k4/k2
enddo
endmacro
Exemplo B.2.6 Simulação de uma Amostra da Distribuição da Estatística de Discrepância no Exemplo 9.1.2

O código a seguir gera uma amostra da estatística de discrepância especificada no Exemplo 9.1.2.

gmacro
goodnessoffit
base 34256734
note - generated sample is stored in c1
note - residuals are placed in c2
note - value of D(r) are placed in c3
note - k1 = size of data set
let k1=5
do k2=1:10000
random k1 c1
let k3=mean(c1)
let k4=sqrt(k1-1)*stdev(c1)
let c2=((c1-k3)/k4)**2
let c2=loge(c2)
let k5=-sum(c2)/k1
let c3(k2)=k5
enddo
endmacro
Exemplo B.2.7 Geração a Partir de uma Distribuição Dirichlet no Exemplo 10.2.3

O código a seguir gera uma amostra de uma distribuição Dirichlet\((\alpha_1, \alpha_2, \alpha_3, \alpha_4)\), em que \(\alpha_1 = 2\), \(\alpha_2 = 3\), \(\alpha_3 = 1\), \(\alpha_4 = 1{,}5\).

gmacro
dirichlet
note - the base command sets the seed for the random
note   number generator (so you can repeat a simulation).
base 34256734
note - here we provide the algorithm for generating from
note   a Dirichlet(k1,k2,k3,k4) distribution.
note - assign the values of the parameters.
let k1=2
let k2=3
let k3=1
let k4=1.5
let k5=K2+k3+k4
let k6=k3+k4
note - generate the sample with i-th sample in i-th row
note   of c2, c3, c4, c5, ....
do k10=1:5
random 1 c1;
beta k1 k5.
let c2(k10)=c1(1)
random 1 c1;
beta k2 k6.
let c3(k10)=(1-c2(k10))*c1(1)
random 1 c1;
beta k3 k4.
let c4(k10)=(1-c2(k10)-c3(k10))*c1(1)
let c5(k10)= 1-c2(k10)-c3(k10)-c4(k10)
enddo
endmacro

Notas do capítulo

  1. Termo função gama — no original, gamma function ↩
  2. Termo função densidade — no original, density function ↩
  3. Termo função de probabilidade — no original, probability function ↩
  4. Termo tamanho da amostra — no original, sample size ↩
  5. Termo diagrama de dispersão — no original, scatter plot ↩
  6. Termo gráfico de probabilidade normal — no original, normal probability plot ↩
  7. Termo regressão logística — no original, logistic regression ↩
  8. Termo variância — no original, variance ↩
  9. Termo desvio padrão — no original, standard deviation ↩
  10. Termo intervalo de confiança — no original, confidence interval ↩
  11. Termo preditor — no original, predictor ↩
  12. Termo modelo de regressão linear simples — no original, simple linear regression model ↩
  13. Nota do tradutor O original traz \(\beta_2 x_2\) no último termo; pelo teste de \(H_0: \beta_2 = \beta_3 = 0\) logo adiante, seria \(\beta_3 x_2\). ↩
  14. Nota do tradutor O original escreve expr no comando e expr1 logo depois; trata-se da mesma expressão. ↩
  15. Nota do tradutor O comando impresso no original tem uma chave a mais, depois de 2^i; pela descrição, seria {print(i); y[i] <- 2^i; print(y[i])}. ↩
  16. Termo bootstrap — no original, bootstrapping ↩
  17. Termo a posteriori — no original, posterior ↩
  18. Nota do tradutor Falta no original o que é amostrado (“a sample of from”); pelo Exemplo 7.3.1, são valores de \((\mu, \sigma^2)\). ↩
  19. Termo valor médio — no original, mean value ↩
  20. Termo estimação — no original, estimation ↩
  21. Termo amostrador de Gibbs — no original, Gibbs sampler ↩
  22. Termo não negativo — no original, nonnegative ↩
  23. Termo estatística de discrepância — no original, discrepancy statistic ↩
  24. Termo distribuição Dirichlet — no original, Dirichlet distribution ↩
  25. Termo estimativa de mínimos quadrados — no original, least-squares estimate ↩
  26. Nota do tradutor O original diz “linear regression matrix” (matriz de regressão linear); pelo contexto, trata-se do modelo de regressão linear. ↩
  27. Termo estimativa — no original, estimate ↩
  28. Termo erro padrão — no original, standard error ↩
  29. Termo amostragem de Gibbs — no original, Gibbs sampling ↩