6.3 Iterações

Vocês usaram várias funções da família apply, especialmente apply() e tapply(), que são funções especiais que repetem uma mesma função FUN para cada objeto de um conjunto (vetores, matrizes, valores atômicos). Essas funções utilizam portanto a lógica de iterações (em inglês, loops), ou seja, fazem a mesma ação repetidas vezes; em outras palavras, fazem LOOPs, dão voltas, realizam o mesmo percurso várias vezes, percorrem um circuito.

As expressões for(){} e while(){} permitem fazer LOOPs, e LOOPs dentro de LOOPS com muita liberdade. Aprendê-las é o mesmo que aprender todas as funções da família apply juntas (apply(), tapply(), sapply(), lapply(), mapply() etc). Se você compreende os LOOPS, pode fazer o que essas funções fazem sem precisar delas (embora elas possam executar a tarefa mais rapidamente).

6.3.1 Iteração com for(){}

6.3.1.1 Exemplo 1

Um exemplo simples do que seria uma iteração com o comando for(){}:

# vamos imprimir na tela as letras do objeto LETTERS
for (let in 1:length(LETTERS)) {
  paraimprimir <- paste(LETTERS[let], " é a letra de índice ", let)
  print(paraimprimir)
}
## [1] "A  é a letra de índice  1"
## [1] "B  é a letra de índice  2"
## [1] "C  é a letra de índice  3"
## [1] "D  é a letra de índice  4"
## [1] "E  é a letra de índice  5"
## [1] "F  é a letra de índice  6"
## [1] "G  é a letra de índice  7"
## [1] "H  é a letra de índice  8"
## [1] "I  é a letra de índice  9"
## [1] "J  é a letra de índice  10"
## [1] "K  é a letra de índice  11"
## [1] "L  é a letra de índice  12"
## [1] "M  é a letra de índice  13"
## [1] "N  é a letra de índice  14"
## [1] "O  é a letra de índice  15"
## [1] "P  é a letra de índice  16"
## [1] "Q  é a letra de índice  17"
## [1] "R  é a letra de índice  18"
## [1] "S  é a letra de índice  19"
## [1] "T  é a letra de índice  20"
## [1] "U  é a letra de índice  21"
## [1] "V  é a letra de índice  22"
## [1] "W  é a letra de índice  23"
## [1] "X  é a letra de índice  24"
## [1] "Y  é a letra de índice  25"
## [1] "Z  é a letra de índice  26"

Ou seja, para cada elemento do objeto let, assumindo os valores na sequência do elemento 1 ao elemento corresponden ao comprimento (== length(LETTERS)) do objeto LETTERS, execute o que está dentro de {}.

6.3.1.2 Exemplo 2

# Fazendo um loop com for(){} replicando o que a função apply() faz
# criamos uma matriz
vetn <- rnorm(100, 30, 1)
mvetn <- matrix(vetn, ncol = 10, dimnames = list(paste("linha", 1:10), paste("coluna", 1:10)))
head(mvetn)
coluna 1 coluna 2 coluna 3 coluna 4 coluna 5 coluna 6 coluna 7 coluna 8 coluna 9 coluna 10
linha 1 29.83293 29.14018 29.23649 30.41905 30.94899 29.84389 29.97366 30.15412 29.34273 30.08479
linha 2 31.24129 31.05689 29.45685 30.92010 30.28868 30.51557 29.74122 30.46949 28.15604 30.88475
linha 3 30.29010 31.34928 29.17843 28.80200 30.94568 29.34699 29.88953 28.76698 29.47358 29.82502
linha 4 29.94628 30.14674 30.23371 28.56894 31.47962 32.13595 29.62404 28.93148 30.15042 31.61015
linha 5 30.07430 30.81179 29.26558 29.58111 29.59002 29.91044 32.09775 31.96293 27.54644 30.83061
linha 6 29.88561 28.47641 29.62197 30.23359 29.96315 28.71014 30.48448 31.47933 30.73691 31.11348
# Fazendo algo == apply(mvetn,2,mean)
# cria um objeto para salvar o resultado
resultado <- NULL
for (coluna in 1:ncol(mvetn)) {
  # pega a coluna
  cl <- mvetn[, coluna]
  # calcula a media
  mcl <- mean(cl)
  print(paste("Média da coluna", colnames(mvetn)[cl], "=", round(mcl, 2)))
  # salva o resultado com a media do item anterior
  resultado <- c(resultado, mcl)
}
##  [1] "Média da coluna NA = 30.02" "Média da coluna NA = 30.02"
##  [3] "Média da coluna NA = 30.02" "Média da coluna NA = 30.02"
##  [5] "Média da coluna NA = 30.02" "Média da coluna NA = 30.02"
##  [7] "Média da coluna NA = 30.02" "Média da coluna NA = 30.02"
##  [9] "Média da coluna NA = 30.02" "Média da coluna NA = 30.02"
##  [1] "Média da coluna NA = 29.77" "Média da coluna NA = 29.77"
##  [3] "Média da coluna NA = 29.77" "Média da coluna NA = 29.77"
##  [5] "Média da coluna NA = 29.77" "Média da coluna NA = 29.77"
##  [7] "Média da coluna NA = 29.77" "Média da coluna NA = 29.77"
##  [9] "Média da coluna NA = 29.77" "Média da coluna NA = 29.77"
##  [1] "Média da coluna NA = 29.92" "Média da coluna NA = 29.92"
##  [3] "Média da coluna NA = 29.92" "Média da coluna NA = 29.92"
##  [5] "Média da coluna NA = 29.92" "Média da coluna NA = 29.92"
##  [7] "Média da coluna NA = 29.92" "Média da coluna NA = 29.92"
##  [9] "Média da coluna NA = 29.92" "Média da coluna NA = 29.92"
##  [1] "Média da coluna NA = 29.8" "Média da coluna NA = 29.8"
##  [3] "Média da coluna NA = 29.8" "Média da coluna NA = 29.8"
##  [5] "Média da coluna NA = 29.8" "Média da coluna NA = 29.8"
##  [7] "Média da coluna NA = 29.8" "Média da coluna NA = 29.8"
##  [9] "Média da coluna NA = 29.8" "Média da coluna NA = 29.8"
##  [1] "Média da coluna NA = 30.21" "Média da coluna NA = 30.21"
##  [3] "Média da coluna NA = 30.21" "Média da coluna NA = 30.21"
##  [5] "Média da coluna NA = 30.21" "Média da coluna NA = 30.21"
##  [7] "Média da coluna NA = 30.21" "Média da coluna NA = 30.21"
##  [9] "Média da coluna NA = 30.21" "Média da coluna NA = 30.21"
##  [1] "Média da coluna NA = 29.85" "Média da coluna NA = 29.85"
##  [3] "Média da coluna NA = 29.85" "Média da coluna NA = 29.85"
##  [5] "Média da coluna NA = 29.85" "Média da coluna NA = 29.85"
##  [7] "Média da coluna NA = 29.85" "Média da coluna NA = 29.85"
##  [9] "Média da coluna NA = 29.85" "Média da coluna NA = 29.85"
##  [1] "Média da coluna NA = 30.34" "Média da coluna NA = 30.34"
##  [3] "Média da coluna NA = 30.34" "Média da coluna NA = 30.34"
##  [5] "Média da coluna NA = 30.34" "Média da coluna NA = 30.34"
##  [7] "Média da coluna NA = 30.34" "Média da coluna NA = 30.34"
##  [9] "Média da coluna NA = 30.34" "Média da coluna NA = 30.34"
##  [1] "Média da coluna NA = 30.33" "Média da coluna NA = 30.33"
##  [3] "Média da coluna NA = 30.33" "Média da coluna NA = 30.33"
##  [5] "Média da coluna NA = 30.33" "Média da coluna NA = 30.33"
##  [7] "Média da coluna NA = 30.33" "Média da coluna NA = 30.33"
##  [9] "Média da coluna NA = 30.33" "Média da coluna NA = 30.33"
##  [1] "Média da coluna NA = 29.95" "Média da coluna NA = 29.95"
##  [3] "Média da coluna NA = 29.95" "Média da coluna NA = 29.95"
##  [5] "Média da coluna NA = 29.95" "Média da coluna NA = 29.95"
##  [7] "Média da coluna NA = 29.95" "Média da coluna NA = 29.95"
##  [9] "Média da coluna NA = 29.95" "Média da coluna NA = 29.95"
##  [1] "Média da coluna NA = 30.69" "Média da coluna NA = 30.69"
##  [3] "Média da coluna NA = 30.69" "Média da coluna NA = 30.69"
##  [5] "Média da coluna NA = 30.69" "Média da coluna NA = 30.69"
##  [7] "Média da coluna NA = 30.69" "Média da coluna NA = 30.69"
##  [9] "Média da coluna NA = 30.69" "Média da coluna NA = 30.69"
# adicona o nome das colunas
names(resultado) <- colnames(mvetn)
# ver o resultado
resultado
##  coluna 1  coluna 2  coluna 3  coluna 4  coluna 5  coluna 6  coluna 7  coluna 8 
##  30.02231  29.76714  29.91783  29.79591  30.21034  29.85470  30.33654  30.32650 
##  coluna 9 coluna 10 
##  29.94533  30.69054
# identico ao apply, maior controle de como a média é aplicada
resultado == apply(mvetn, 2, mean)
##  coluna 1  coluna 2  coluna 3  coluna 4  coluna 5  coluna 6  coluna 7  coluna 8 
##      TRUE      TRUE      TRUE      TRUE      TRUE      TRUE      TRUE      TRUE 
##  coluna 9 coluna 10 
##      TRUE      TRUE

6.3.1.3 Exemplo 3

Agora usando for(){} para fazer algo como o tapply().

# Fazendo algo == tapply(mvetn[,2],mvetn$classe,sum)
# criamos uma matriz
vetn <- rnorm(100, 30, 1)
mvetn <- matrix(vetn, ncol = 10, dimnames = list(paste("linha", 1:10), paste("coluna", 1:10)))
# transformamos num data.frame adicionando uma coluna categorica
mvetn <- data.frame(classe = sample(paste("categ", 1:3, sep = ""), size = nrow(mvetn), replace = T), mvetn)
head(mvetn[, 1:5])
# cria um objeto para salvar o resultado
resultado <- NULL
# para cada categoria
for (ct in 1:length(levels(mvetn$classe))) {
  # pega a categoria
  cl <- levels(mvetn$classe)[ct]
  # filtra os dados (vetor logico)
  vl <- mvetn$classe == cl
  # calcula a soma dos dados da categoria
  soma <- sum(mvetn[vl, 2], na.rm = T)
  # imprime o passo
  print(paste("A soma da categoria", cl, " é igual a ", soma))
  # junta os resultados
  resultado <- c(resultado, soma)
}
# atribui nomes aos elementos do vetor de somas
names(resultado) <- levels(mvetn$classe)
# confere
resultado == tapply(mvetn[, 2], mvetn$classe, sum)

6.3.1.4 Exemplo 4

Calculando somas e médias de linhas, similar ao que podemos fazer com a função apply():

somas <- NULL # objeto vazio para salvar soma de cada linha
medias <- NULL # objeto vazio para salvar medias de cada linha
for (i in 1:nrow(X)) { # para cada linha
  somai <- sum(X[i, ]) # soma dos valores na linha i
  somas <- c(somas, somai) # junta a somai com o resto (que estará vazio na primeira vez)
  mediai <- mean(X[i, ]) # média  dos valores na linha i
  medias <- c(medias, mediai) # junta as medias
}
# como a matriz tem nomes, acrescenta esses nomes aos vetores com resultados
names(medias) <- rownames(X)
medias
## ln 1 ln 2 ln 3 ln 4 
##   17   18   19   20
names(somas) <- rownames(X)
somas
## ln 1 ln 2 ln 3 ln 4 
##  153  162  171  180

6.3.2 Iteração com while(){}

O comando while(){} funciona de forma parecida, mas faz algo ENQUANTO (em inglês, while) a condição em while(){} seja verdadeira. Um exemplo simples:

6.3.2.1 Exemplo 1

# cria um vetor de valores aleatorizados
vet <- sample(10:100)
# amostra um valor do vetor até que este valor seja 10
conta <- 1
valor <- 0
while (valor != 10) {
  valor <- sample(vet, 1)
  print(paste("o valor selecionado na iteração", conta, "foi de ", valor))
  conta <- conta + 1
}
## [1] "o valor selecionado na iteração 1 foi de  81"
## [1] "o valor selecionado na iteração 2 foi de  23"
## [1] "o valor selecionado na iteração 3 foi de  30"
## [1] "o valor selecionado na iteração 4 foi de  32"
## [1] "o valor selecionado na iteração 5 foi de  39"
## [1] "o valor selecionado na iteração 6 foi de  74"
## [1] "o valor selecionado na iteração 7 foi de  88"
## [1] "o valor selecionado na iteração 8 foi de  16"
## [1] "o valor selecionado na iteração 9 foi de  60"
## [1] "o valor selecionado na iteração 10 foi de  61"
## [1] "o valor selecionado na iteração 11 foi de  62"
## [1] "o valor selecionado na iteração 12 foi de  74"
## [1] "o valor selecionado na iteração 13 foi de  10"

6.3.3 Iteração com for(){} e a condicional if(){}

6.3.3.1 Exemplo 1

# cria um vetor de valores aleatorizados
vet <- sample(10:100, 60, replace = T)
# amostra um valor do vetor até que este valor seja 10
for (v in 1:10000) {
  valor <- sample(vet, 1)
  if (valor == 10) {
    # se o valor selecionado aleatoriamente for 10, ou seja se a expressão valor==10 for TRUE execute:
    # imprima isso
    print(paste("A primeira vez que o valor 10 foi selecionado aleatoriamente foi quando o objeto v assumiu o valor de", v))
    # interrompa (quebre) o loop
    break # note este argumento
  } else {
    # caso contrario, valor!=10, imprime o valor selecionado e continua o loop
    print(paste("O valor selecionado foi ", valor, "no indice", v))
  }
}

É possível que o script acima repita as 10000 vezes do for(){} sem encontrar o valor 10, até porque o 10 pode não estar em vet se não for amostrado.