29 Agrupando comandos, execução condicional, controle de fluxo, "loops" e a "família" *apply

29.1 Agrupando comandos

O R é uma linguagem que interpreta expressões, o que implica que o único tipo de comando usado é uma expressão ou função que executa o processamento da requisição e retorna algum resultado. Nesta sessão vamos alguns formatos para facilitar/agilizar o uso de comandos.

É possível atribuir os mesmos valores a vários objetos de uma só vez utilizando atribuições múltiplas de valores.

  > a <- b <- 10
  > a

  [1] 10

  > b

  [1] 10

  > x <- y <- z <- numeric(5)
  > x

  [1] 0 0 0 0 0

  > y

  [1] 0 0 0 0 0

  > z

  [1] 0 0 0 0 0

Um grupo de comandos podem ser agrupado com "{  }" e separados por ";" para digitação em uma mesma linha. Em certas situações, como no "prompt"do R as chaves são opcionais.

  > {
  +     x <- 1:3
  +     y <- x + 4
  +     z <- y/x
  + }
  > x <- 1:3
  > y <- x + 4
  > z <- y/x
  > x

  [1] 1 2 3

  > y

  [1] 5 6 7

  > z

  [1] 5.000000 3.000000 2.333333

29.2 Execução condicional

Execuções condicionais são controladas por funções especiais que verificam se uma condição é satisfeita para permitir a execução de um comando. As seguintes funções e operadores podem ser usadas para controlar execução condicional.

A estrutura if() else é comumente usada, em especial dentro de funções. Quando aplicada diretamente na linha de comando, é uma prática recomendada colocar chaves marcando o início e fim dos comandos de execução condicional. Quando a expressão que segue o if() e/ou else tem uma única linha ela pode ser escrita diretamente, entretando, caso sigam-se mais de duas linhas deve-se novamente usar chaves, agora também depois destes de forma que todos os comandos da execução condicional fiquem contidos na chave, caso contrário apenas a primeira linha será considerada para execução condicional e todas as demais são processadas normalmente. Inspecione os comandos a seguir que ilustram os diferentes usos.

  > x <- 10
  > y <- 15
  > {
  +     if (x > 8)
  +         z <- 2 * x
  + }
  > z

  [1] 20

  > rm(x, y, z)
  > x <- 10
  > y <- 15
  > {
  +     if (x > 12)
  +         z <- 2 * x
  +     else z <- 5 * x
  + }
  > z

  [1] 50

  > rm(x, y, z)
  > x <- 10
  > y <- 15
  > {
  +     if (x > 8) {
  +         z <- 2 * x
  +         w <- z + y
  +     }
  +     else {
  +         z <- 5 * x
  +         w <- z - y
  +     }
  + }
  > z

  [1] 20

  > w

  [1] 35

  > rm(x, y, z, w)
  > x <- 10
  > y <- 15
  > {
  +     if (x > 8)
  +         z <- 2 * x
  +     w <- z + y
  +     if (x <= 8)
  +         z <- 5 * x
  +     w <- z - y
  + }
  > z

  [1] 20

  > w

  [1] 5

  > rm(x, y, z, w)

Um comando útil para manipulação de dados é o split() que permite separa dados por grupos. Por exemplo considere o conjunto de dados codemtcars, que possui várias variáveis relacionadas a características de veículos. Entre as variáveis estão as que indicam o consumo (mpg - miles per gallon) e o tipo de câmbio, manual ou automático (am). Para separar os dados da variável mpg para cada tipo de câmbio, podemos usar:

  > data(mtcars)
  > with(mtcars, split(mpg, am))

  $0
   [1] 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 21.5
  [16] 15.5 15.2 13.3 19.2
  
  $1
   [1] 21.0 21.0 22.8 32.4 30.4 33.9 27.3 26.0 30.4 15.8 19.7 15.0 21.4

Outro comando com funcionalidade similar é agregate().

29.3 Controle de fluxo

O controle de fluxo no R é implementado pelas funções for(), while() e repeat(). A escolha de qual usar vai depender do contexto e objetivo do código e em geral não existe solução única, sendo que uma mesma tarefa pode ser feita por uma ou outra.

Apenas para ilustração considere o seguinte exemplo resolvido de três formas diferentes com cada uma destas funções:
Dado um valor de n gerar amostrar de tamanho 1, 2,,n e para calcule a média de cada amostra, com 3 casas decimais.

Primeiro vamos implementar uma solução usando for().

  > f1 <- function(n) {
  +     medias <- numeric(n)
  +     for (i in 1:n) {
  +         am <- rnorm(i)
  +         medias[i] <- round(mean(am), dig = 3)
  +     }
  +     return(medias)
  + }
  > set.seed(283)
  > f1(10)

   [1]  1.007 -0.063 -0.392  1.546  0.341 -0.514 -0.086 -0.224  0.137  0.138

Agora vamos executar a mesma tarefa com while()

  > f2 <- function(n) {
  +     medias <- numeric(n)
  +     i <- 1
  +     while (i <= n) {
  +         am <- rnorm(i)
  +         medias[i] <- round(mean(am), dig = 3)
  +         i <- i + 1
  +     }
  +     return(medias)
  + }
  > set.seed(283)
  > f2(10)

   [1]  1.007 -0.063 -0.392  1.546  0.341 -0.514 -0.086 -0.224  0.137  0.138

E finalmente a mesma tarefa com repeat()

  > f3 <- function(n) {
  +     medias <- numeric(n)
  +     i <- 1
  +     repeat {
  +         am <- rnorm(i)
  +         medias[i] <- round(mean(am), dig = 3)
  +         if (i == n)
  +             break
  +         i <- i + 1
  +     }
  +     return(medias)
  + }
  > set.seed(283)
  > f3(10)

   [1]  1.007 -0.063 -0.392  1.546  0.341 -0.514 -0.086 -0.224  0.137  0.138

NOTA: as soluções acima são apenas ilustrativas e não representam a forma mais eficiente de efetuar tal operação o R. Na verdade, para este tipo de cálculo recomenda-se o uso de funções do tipo *apply que veremos no restante desta sessão.

29.4 Alguns comentários adicionais

Nas soluções acima as amostras foram usadas para calcular as médias e depois descartadas. Suponha agora que queremos preservar e retornar também os dados simulados. Para ilustrar vamos mostrar como fazer isto modificando um pouco a primeira função.

  > f1a <- function(n) {
  +     res <- list()
  +     res$amostras <- list()
  +     res$medias <- numeric(n)
  +     for (i in 1:n) {
  +         res$amostras[[i]] <- rnorm(i)
  +         res$medias[i] <- round(mean(res$amostras[[i]]), dig = 3)
  +     }
  +     return(res)
  + }
  > set.seed(283)
  > ap <- f1a(4)
  > names(ap)

  [1] "amostras" "medias"

  > ap

  $amostras
  $amostras[[1]]
  [1] 1.00687
  
  $amostras[[2]]
  [1]  0.2003886 -0.3257288
  
  $amostras[[3]]
  [1]  0.4913491 -1.0009700 -0.6665789
  
  $amostras[[4]]
  [1] 2.035963 1.174572 1.214059 1.761383
  
  
  $medias
  [1]  1.007 -0.063 -0.392  1.546

Vamos agora ver uma outra modificação. Nas funções acima geravamos amostras com tamanhos sequênciais com incremento de 1 elemento no tamanho da amostra. A função a seguir mostra como gerar amostras de tamanhos especificados pelo usuário e para isto toma como argumento um vetor de tamanhos de amostra.

  > f5 <- function(ns) {
  +     medias <- numeric(length(ns))
  +     j <- 1
  +     for (i in ns) {
  +         am <- rnorm(i)
  +         medias[j] <- round(mean(am), dig = 3)
  +         j <- j + 1
  +     }
  +     return(medias)
  + }
  > set.seed(231)
  > f5(c(2, 5, 8, 10))

  [1] -1.422 -0.177  0.056  0.158

29.5 Evitando "loops" — a "família" *apply

O R é uma linguagem vetorial e "loops"podem e devem ser substituídos por outras formas de cálculo sempre que possível. Usualmente usamos as funções apply(), sapply(), tapply() e lapply() para implementar cálculos de forma mais eficiente. Vejamos algums exemplos.

1.
Seja o problema mencionado no início desta sessão de gerar amostras de tamanhos sequenciais e calcular a média para cada uma delas. Uma alternativa aos códigos apresentados seria:
  > set.seed(283)
  > sapply(1:10, function(x) round(mean(rnorm(x)), dig = 3))

   [1]  1.007 -0.063 -0.392  1.546  0.341 -0.514 -0.086 -0.224  0.137  0.138
2.
Considere agora a modificação mencionado anteriormente de calcular médias de amostras com tamanho fornecidos pelo usuário
  > vec <- c(2, 5, 8, 10)
  > f6 <- function(n) round(mean(rnorm(n)), dig = 3)
  > set.seed(231)
  > sapply(vec, f6)

  [1] -1.422 -0.177  0.056  0.158
3.
No próximo exemplo consideramos uma função que simula dados e calcula medidas de posição e dispersão associadas utilizando para cada uma delas duas medidas alternativas. Inicialmente definimos a função:
  > proc <- function(...) {
  +     x <- rnorm(500)
  +     modA <- list(pos = mean(x), disp = sd(x))
  +     modB <- list(pos = mean(x, trim = 0.1), disp = mad(x))
  +     return(list(A = modA, B = modB))
  + }

Agora vamos rodar a função 10 vezes.

  > set.seed(126)
  > res <- lapply(1:10, proc)

O resultado está armazanado no objeto res, que neste caso é uma lista. Agora vamos extrair desta lista as médias aritméticas e depois ambas, média aritmética e aparada:

  > mediaA <- function(x) x$A$pos
  > mA <- sapply(res, mediaA)
  > mediaAB <- function(x) c(x$A$pos, x$B$pos)
  > mAB <- sapply(res, mediaAB)
  > rownames(mAB) <- paste("modelo", LETTERS[1:2], sep = "")
  > mAB

                [,1]        [,2]      [,3]       [,4]       [,5]       [,6]
  modeloA 0.02725767 -0.01017973 0.0958355 0.02058979 0.04582751 0.07898205
  modeloB 0.01706928 -0.02781770 0.1023454 0.02210935 0.06210404 0.05914628
                [,7]        [,8]         [,9]       [,10]
  modeloA 0.06122656 -0.05981805  0.006781871 -0.02798788
  modeloB 0.04085053 -0.05680834 -0.020411456 -0.02029610

Os comandos acima podem ser reescritos em versões simplificadas:

  > mA <- sapply(res, function(x) x$A$pos)
  > mA

   [1]  0.027257675 -0.010179733  0.095835502  0.020589788  0.045827513
   [6]  0.078982050  0.061226561 -0.059818054  0.006781871 -0.027987878

  > mAB <- sapply(res, function(x) sapply(x, function(y) y$pos))
  > mAB

          [,1]        [,2]      [,3]       [,4]       [,5]       [,6]       [,7]
  A 0.02725767 -0.01017973 0.0958355 0.02058979 0.04582751 0.07898205 0.06122656
  B 0.01706928 -0.02781770 0.1023454 0.02210935 0.06210404 0.05914628 0.04085053
           [,8]         [,9]       [,10]
  A -0.05981805  0.006781871 -0.02798788
  B -0.05680834 -0.020411456 -0.02029610

E para obter as médias das médias de cada medida:

  > apply(mAB, 1, mean)

           A          B
  0.02385153 0.01782913
4.
A função tapply() pode ser usada para calcular o resultado de uma operação sobre dados, para cada um dos níveis de uma segunda variável No primeiro exemplo consideramos novamente o conjunto de dados mtcars mencionado anteriormente. Os comandos abaixo calculam média, variância e coeficinte de variação do consumo para cada tipo de cambio.
  > with(mtcars, tapply(mpg, am, mean))

         0        1
  17.14737 24.39231

  > with(mtcars, tapply(mpg, am, var))

         0        1
  14.69930 38.02577

  > with(mtcars, tapply(mpg, am, function(x) 100 * sd(x)/mean(x)))

         0        1
  22.35892 25.28053

Vejamos ainda um outro exemplo onde definimos 50 dados divididos em 5 grupos.

  > x <- rnorm(50, mean = 50, sd = 10)
  > y <- rep(LETTERS[1:5], each = 10)
  > x

   [1] 55.66788 43.71391 42.78483 50.28745 40.77170 62.06800 60.53166 51.90432
   [9] 56.41214 65.46560 35.99390 42.67566 40.26776 47.61359 57.92209 60.69673
  [17] 48.80234 44.29422 44.48886 39.02277 60.93054 32.73959 39.37867 56.89312
  [25] 37.06637 61.45986 44.66166 50.60778 37.78913 39.13208 48.53931 43.29661
  [33] 66.03602 65.55652 58.05864 55.21829 45.90542 45.01864 37.73984 38.00313
  [41] 34.85114 34.24760 65.07629 49.01286 62.37572 38.36997 57.93003 39.72861
  [49] 66.62899 45.37572

  > y

   [1] "A" "A" "A" "A" "A" "A" "A" "A" "A" "A" "B" "B" "B" "B" "B" "B" "B" "B" "B"
  [20] "B" "C" "C" "C" "C" "C" "C" "C" "C" "C" "C" "D" "D" "D" "D" "D" "D" "D" "D"
  [39] "D" "D" "E" "E" "E" "E" "E" "E" "E" "E" "E" "E"

  > gM <- tapply(x, y, mean)
  > gM

         A        B        C        D        E
  52.96075 46.17779 46.06588 50.33724 49.35969

  > gCV <- tapply(x, y, function(z) 100 * sd(z)/mean(z))
  > gCV

         A        B        C        D        E
  16.19106 17.17599 23.08328 20.65681 25.77284

Para organizar os dados em um data-frame:

  > xy <- data.frame(x = rnorm(50, mean = 50, sd = 10), y = rep(LETTERS[1:5],
  +     each = 10))
  > gM <- with(xy, tapply(x, y, mean))
  > gM

         A        B        C        D        E
  49.91571 51.03091 45.26204 47.45439 47.25661

  > gCV <- with(xy, tapply(x, y, function(z) 100 * sd(z)/mean(z)))
  > gCV

         A        B        C        D        E
  16.13100 11.97707 17.35279 18.67300 16.03077
5.
Considere gerarmos uma matrix 1000 × 300 representando 1000 amostras de tamanho 300. O que desejamos é calcular a média de cada uma das amostras Os códigos a seguir mostras três formas alternativas de fazer isto. Encapsulamos os comandos com a função system.time() que compara os tempos de execução.
  > x <- matrix(rnorm(1000 * 300), nc = 300)
  > system.time({
  +     f <- function(x) {
  +         mx <- numeric(1000)
  +         for (i in 1:1000) mx[i] <- mean(x[i, ])
  +         mx
  +     }
  +     mx <- f(x)
  + })

     user  system elapsed
    0.076   0.008   0.085

  > system.time(mx <- apply(x, 1, mean))

     user  system elapsed
    0.100   0.000   0.103

  > system.time(mx <- rowMeans(x))

     user  system elapsed
    0.004   0.000   0.003

A função rowMeans() é substancialmente mais eficiente (menos tempo de execução. Outras funções simulares são colMeans(), rowSums() e colSums().

6.
Considere o seguinte problema:
Sejam li e ls vetores com os limites superiores e inferiores definindo intervalos. Inicialmente vamos simular estes valores.
  > li <- round(rnorm(500, m = 70, sd = 10))
  > ls <- li + rpois(li, lam = 5)

O que queremos montar um vetor com os valores únicos que definem estes intervalos, e testar a pertinência de cada elemento a cada um dos intervalos. Ao final teremos uma matrix indicando, para cada elemento do vetor de valores únicos, a pertinência a cada intervalo. Inicialmente vamos fazer um código usando "loops"guardando os resultados no objeto B.

  > system.time({
  +     aux <- sort(c(li, ls))
  +     m <- length(table(aux))
  +     all <- rep(min(aux), m)
  +     for (j in 1:(m - 1)) {
  +         all[j + 1] <- min(aux[aux > all[j]])
  +     }
  +     n <- length(li)
  +     aij <- matrix(0, nrow = n, ncol = m)
  +     for (i in 1:n) {
  +         for (j in 1:m) {
  +             aij[i, j] <- ifelse(all[j] >= li[i] & all[j] <= ls[i],
  +                 1, 0)
  +         }
  +         B <- aij
  +     }
  + })

     user  system elapsed
    2.536   0.032   2.790

Agora, usando a estrutura vetorial da linguagem R vamos reimplementar este código de maneira mais eficiente e adequada para a linguagem, usando sapply(), guardando os resultados no objeto A. Ao final usamos identical() para testar se os resultados numéricos são exatamente os mesmos. Note a diferença nos tempos de execução.

  > system.time({
  +     all <- sort(unique(c(li, ls)))
  +     interv1 <- function(x, inf, sup) ifelse(x >= inf & x <= sup,
  +         1, 0)
  +     A <- sapply(all, interv1, inf = li, sup = ls)
  + })

     user  system elapsed
    0.032   0.004   0.037

  > identical(A, B)

  [1] TRUE
7.
Considere agora uma extensão do problema anterior. Queremos montar o vetor com os valores únicos que definem estes intervalos como no caso anterior, e depois usar este vetor montar intervalos com pares de elementos consecutivos deste vetor e testar se cada um destes intervalos está contido em cada um dos intervalos originais. O resultado final é uma matrix indicando para cada intervalo obtido desta forma a sua pertinência a cada um dos intervalos originais. Da mesma forma que no caso anterior implementamos com um "loop"e depois usando a estrutura vetorial da linguagem, e testando a igualdade dos resultados com identical().
  > li <- round(rnorm(500, m = 70, sd = 10))
  > ls <- li + rpois(li, lam = 5)
  > system.time({
  +     aux <- sort(c(li, ls))
  +     m <- length(table(aux))
  +     all <- rep(min(aux), m)
  +     for (j in 1:(m - 1)) {
  +         all[j + 1] <- min(aux[aux > all[j]])
  +     }
  +     n <- length(li)
  +     aij <- matrix(0, nrow = n, ncol = m - 1)
  +     for (i in 1:n) {
  +         for (j in 1:m - 1) {
  +             aij[i, j] <- ifelse(all[j] >= li[i] & all[j + 1] <=
  +                 ls[i], 1, 0)
  +         }
  +         B <- aij
  +     }
  + })

     user  system elapsed
    2.892   0.040   3.150

  > system.time({
  +     all <- sort(unique(c(li, ls)))
  +     all12 <- cbind(all[-length(all)], all[-1])
  +     interv1 <- function(x, inf, sup) ifelse(x[1] >= inf & x[2] <=
  +         sup, 1, 0)
  +     A <- apply(all12, 1, interv1, inf = li, sup = ls)
  + })

     user  system elapsed
    0.032   0.000   0.050

  > identical(A, B)

  [1] TRUE

Uso da família *apply – outros exemplos Os exemplos a seguir foram retirados de mensagens enviada à lista R_STAT.

1.
adapdato de mensagem enviada por Silvano C Costa
Tenho uma pergunta onde pode haver mais de uma resposta, por exemplo:  
 
 Q1 - Qual Esporte você pratica:  
 1.()Futebol  2.()Volei  3.() Natação  4.()Atletismo  
 
 Q2 - Sexo:  
 1.Masculino()  2.Feminino()  
 
Então teria os dados dessa forma:  
 
Q1.1 Q1.2 Q1.3 Q1.4 Q2  
 1     0    1    0   1 => Homem Praticante de Futebol,Natacao  
 0     1    1    0   2 => Mulher praticante de Volei e Natação  
 0     0    0    1   2 => Mulher praticante de Atletismo  
 
Gostaria de criar uma tabela cruzada entre essas variáveis:  
            M    F  
 Futebol    21   10  
 Natação    13   20  
 Volei      5    2  
 Atletismo  10   10

Para mostrar como obter a solução, como não temos o questionário aqui vamos primeiro simular dados deste tipo como se tivéssemos 75 questionários.

  > esportes <- as.data.frame(matrix(sample(c(0, 1), 300, rep = TRUE),
  +     nc = 4))
  > names(esportes) <- c("Futebol", "Natacao", "Volei", "Atletismo")
  > esportes$S <- sample(c("M", "F"), 75, rep = TRUE)
  > dim(esportes)

  [1] 75  5

  > head(esportes)

    Futebol Natacao Volei Atletismo S
  1       1       1     0         0 F
  2       0       0     1         0 F
  3       1       1     1         0 M
  4       1       0     1         0 F
  5       1       1     1         0 F
  6       0       1     1         1 F

Solução 1: Para cada esporte podemos contar os praticantes de cada sexo em cada esporte, separadamente utilizando table() e verificando a segunda linha da tablea a seguir.

  > with(esportes, table(Futebol, S))

         S
  Futebol  F  M
        0 18 19
        1 19 19

Desta forma, podemos obter a tabela desejada combinando os resultados de tabelas para cada esporte.

  > with(esportes, rbind(table(Futebol, S)[2, ], table(Natacao, S)[2,
  +     ], table(Volei, S)[2, ], table(Atletismo, S)[2, ]))

        F  M
  [1,] 19 19
  [2,] 19 22
  [3,] 24 20
  [4,] 20 21

Solução 2: alternativamente, podemos usar sapply() para tomar cada esporte e, como os dados são codificados em 0/1, usar tapply() para somar os praticantes (1) de cada sexo.

  > sapply(esportes[, 1:4], function(x) tapply(x, esportes$S, sum))

    Futebol Natacao Volei Atletismo
  F      19      19    24        20
  M      19      22    20        21
2.
Adaptado de mensagem enviada por André
Queria fazer uma amostragem e tirar as informações. Tenho duas amostras.  
Aplico o teste t e tenho um P-valor.  
 
 a <-c(1,2,4,5,3,4,5,6,6,7,2)  
 b <-c(5,3,4,5,3,4,5,3,4,3,5)  
 
Eu gostaria de juntar estes dois vetores num mesmo vetor e fazer 1000  
reamostragens neste vetor de tamanho do vetor a e com reposição.  
 
 e <- c(5,3,4,5,3,4,5,3,4,3,5,1,2,4,5,3,4,5,6,6,7,2)  
 
Depois eu queria  ver aplicar o teste t(nas amostras) e ver como se  
comportam estes p-valores.

Inicialmente vamos entrar com os dados e obter o teste-t.

  > a <- c(1, 2, 4, 5, 3, 4, 5, 6, 6, 7, 2)
  > b <- c(5, 3, 4, 5, 3, 4, 5, 3, 4, 3, 5)
  > tt.ab <- t.test(a, b)
  > tt.ab

   Welch Two Sample t-test
  
  data:  a and b
  t = 0.1423, df = 14.14, p-value = 0.8889
  alternative hypothesis: true difference in means is not equal to 0
  95 percent confidence interval:
   -1.278239  1.460057
  sample estimates:
  mean of x mean of y
   4.090909  4.000000

Agora obtemos as 1000 reamostras deste vetor cada uma com 11 × 2 = 22 valores utilizando sample(). As reamostras serão arranjadas num array de dimensão 11 × 2 × 1000.

  > e <- c(5, 3, 4, 5, 3, 4, 5, 3, 4, 3, 5, 1, 2, 4, 5, 3, 4, 5,
  +     6, 6, 7, 2)
  > reamostras <- array(sample(e, length(e) * 1000, rep = T), dim = c(length(e)/2,
  +     2, 1000))

Portanto cada elemento da terceira dimensão corresponde a uma reamostra. Para fazer os testes-t nas 1000 reamostras utilizamos apply() que vai gerar uma lista de 100 elementos com resultados dos testes.

  > TT <- apply(reamostras, 3, function(x) t.test(x[, 1], x[, 2]))

Para ver o resultado do teste em uma das amostras selecionamos um elemento da lista.

  > TT[[1]]

   Welch Two Sample t-test
  
  data:  x[, 1] and x[, 2]
  t = -1.8448, df = 19.886, p-value = 0.08001
  alternative hypothesis: true difference in means is not equal to 0
  95 percent confidence interval:
   -1.7436506  0.1072869
  sample estimates:
  mean of x mean of y
   4.000000  4.818182

Finalmente pode-se extrair uma quantidade de interesse dos resultados, como no exemplo a seguir, extraímos os p-valores.

  > names(TT[[1]])

  [1] "statistic"   "parameter"   "p.value"     "conf.int"    "estimate"
  [6] "null.value"  "alternative" "method"      "data.name"

  > pvals <- sapply(TT, function(x) x$p.value)

Os gráficos no Figura 2 mostram valores obtidos an amostra, comparados aos valores obtidos na reamostragem. À esquerda é mostrado a estimativa da diferença de médias, e à direita os p-valores.

  > hist(sapply(TT, function(x) diff(x$est)), main = "Diferença de médias")
  > abline(v = diff(tt.ab$est), col = 2, lwd = 3)
  > hist(sapply(TT, function(x) x$p.val), main = "P-valor")
  > abline(v = tt.ab$p.val, col = 2)




PIC

Figura 77: Valores da diferença de médias (esquerda) e p-valor(direita) da amostra (linhas verticais) comparados aos histogramas dos valores obtinos nas reamostras .


OBS: note que estão sendo usadas as opçõees default do teste-t para comparação de duas amostras dadas em t.test() (bilateral, não pareado, variâncias diferentes, etc). Para alterar algum argumento basta acrescentar o argumento desejados na chamada de apply().

  > TT <- apply(reamostras, 3, function(x, ...) t.test(x[, 1], x[,
  +     2], ...), var.equal = TRUE)

29.6 Extensões da família *apply

As funções da família *apply tem o propósito geral de aplicar uma função repetidamente a diversas partes de um conjunto de dados. Além das mencionadas acima várias outras tem sido implementadas. Notadamente se destacam as do pacote plyr (a_ply, d_ply, l_ply, r_ply, dentre váris outras).

Por exemplo considere a função l_ply que aplica uma função em elementos uma lista porém em situações onde estamos interessados apenas em um efeito colateral (gráfico, arquivo gravado em disco, etc) de função e não no resultado que ela retorna. Como exemplo considere com conjunto de dados trees, uma data-frame que possui três colunas com diâmetros, alturas e volumes de árvores. Supunha que desejamos fazer o histograma das três variáveis, e então uma possível forma seria utlizar o comando lapply().

  > data(trees)
  > par(mfrow = c(1, 3))
  > lapply(trees, hist)

Neste caso, além de produzir os gráficos as resultados dos cálculos do histograma são retornados na tela, o que pode ser indesejável e/ou desnecessário. A função l_ply() produz o mesmo resultado gráfico porém sem que os resultados dos cálculos do histograma sejam retornados.

  > require(plyr)
  > l_ply(trees, hist)

Para mais informações sobre o pacote plyr consulte as informações e documentaçÕes em http://had.co.nz/plyr/.