Vimos no conceito Vectors que um vetor pode ser usado em uma expressão condicional, gerando um vetor lógico.
Isso, por sua vez, pode ser usado em funções como all() e any().
v <- c(4, 7, 10)
v >= 6
#> [1] FALSE TRUE TRUE
all(v > 6)
#> [1] FALSE # not all elements match this condition
any(v > 6)
#> [1] TRUE # at least one element matches
A técnica é muito mais poderosa do que isso.
Podemos extrair elementos selecionados de um vetor com um número de índice ou um vetor de índices:
v <- 5:10
v
#> [1] 5 6 7 8 9 10
v[3]
#> [1] 7
v[c(2, 4)]
#> [1] 6 8
Como alternativa, use um vetor lógico para filtrar o vetor original, retornando um subconjunto de entradas associadas a um valor TRUE:
v <- 1:3
bools <- c(FALSE, TRUE, TRUE)
v[bools]
#> [1] 2 3
A partir daí é um passo pequeno para gerar o vetor Boolean com uma expressão condicional:
bools <- v >= 2
bools
#> [1] FALSE TRUE TRUE
v[bools]
#> [1] 2 3
# simpler form
v[v >= 2]
#> [1] 2 3
Essas expressões condicionais podem ser arbitrariamente complexas, envolvendo vários vetores ou funções:
v <- 1:10
w <- 10:1
# pairwise comparison
v > w
#> [1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
# shorter form
v[v > w]
#> [1] 6 7 8 9 10
Chamamos este conceito de "Filtragem de Vetores", na esperança de que faça sentido para a maior variedade possível de programadores.
Na comunidade de R, o termo "Subsetting" provavelmente é mais comum.
Por simplicidade, os exemplos acima comparavam sempre vetores do mesmo comprimento. O que acontece se os comprimentos forem diferentes?
A resposta é algo poderoso se usado de forma deliberada, mas confuso se inesperado.
Um exemplo:
v <- 1:6
cond <- c(TRUE, FALSE)
v[cond]
#> [1] 1 3 5
O que aconteceu ali? Indexamos um vetor de comprimento 6 com um Boolean de comprimento 2, mas obtivemos um vetor de comprimento 3 como resultado.
Se um vetor for de alguma forma "curto demais" para a expressão em que é usado, o R vai repeti-lo até atingir o comprimento desejado: isso se chama "reciclagem".
Isso transformou nosso vetor c(TRUE, FALSE) em c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE), e v[cond] então retornou os valores TRUE de v: neste caso, os números ímpares.
Então o que está acontecendo no próximo exemplo?
v <- 1:3
0.5 * v
#> [1] 0.5 1.0 1.5
2 + v
#> [1] 3 4 5
À primeira vista, parece multiplicação escalar e (uma soma escalar um tanto estranha), mas não existem escalares no R.
Em vez disso, os números são reciclados para formar um vetor do mesmo comprimento de v, e então a operação aritmética é aplicada elemento a elemento usando c(0.5, 0.5, 0.5) ou c(2, 2, 2).
A reciclagem é muito, muito útil, mas verifique se é isso mesmo que você pretende.
Uma pequena diferença nos comprimentos dos vetores (por exemplo, 99 vs 100) pode causar bugs confusos.
Alguns autores recomendam que a reciclagem só seja usada quando um dos vetores tem comprimento 1.
A função which() recebe um argumento Boolean e retorna um vetor de índices que resultam em TRUE.
v
#> [1] 2 7 9
v[v > 5] # returns values
#> [1] 7 9
which(v > 5) # returns indices
#> [1] 2 3
As seções anteriores tratavam de encontrar entradas que atendem a algum critério.
Se você só precisa saber se o vetor contém um elemento específico, usa-se o operador %in%.
3 %in% 1:5
#> [1] TRUE
7 %in% 1:5
#> [1] FALSE
Isso é funcionalmente equivalente ao código a seguir, mas muito mais conveniente:
length(v[v == 3]) > 0
#> [1] TRUE
Também existe um operador %notin%, que dá o not lógico de %in%.