3 Indexação e seleção condicional
3.1 Indexação
Existem 6 maneiras diferentes de indexar valores no R. Podemos indexar usando:
- Inteiros positivos.
- Inteiros negativos.
- Zero.
- Espaço em branco.
- Nomes.
- Valores lógicos.
Existem três tipos de operadores que podem ser usados para indexar (e selecionar) sub-conjuntos (subsets) de objetos no R:
- O operador
[ ]
sempre retorna um objeto da mesma classe que o original. Pode ser usado para selecionar múltiplos elementos de um objeto. - O operador
[[ ]]
é usado para extrair elementos de uma lista ou data frame. Pode ser usado para extrair um único elemento, e a classe do objeto retornado não precisa necessariamente ser uma lista ou data frame. - O operador
$
é usado para extrair elementos nomeados de uma lista ou data frame. É similar ao operador[[ ]]
.
3.1.1 Indexação de vetores
Observe o seguinte vetor de contagens
<- c(8, 4, NA, 9, 6, 1, 7, 9)
cont
cont1] 8 4 NA 9 6 1 7 9 [
Para acessar o valor que está na posição 4, faça:
4]
cont[1] 9 [
Os colchetes [ ]
são utilizados para extração (seleção de um
intervalo de dados) ou substituição de elementos. O valor dentro
dos colchetes é chamado de índice.
Para acessar os valores nas posições 1, 4 e 8 é necessário o uso da
função c()
:
c(1, 4, 8)]
cont[1] 8 9 9 [
Ou:
<- c(1, 4, 8)
ind
cont[ind]1] 8 9 9 [
Note que os índices no R começam em 1, e não em 0, como em algumas outras linguagens.
Para selecionar todos os valores, excluindo aquele da posição 4, usamos um índice negativo
-4]
cont[1] 8 4 NA 6 1 7 9 [
Da mesma forma se quiséssemos todos os valores, menos aqueles das posições 1, 4 e 8:
-c(1, 4, 8)]
cont[1] 4 NA 6 1 7 [
Também é possível selecionar uma sequência de elementos (com qualquer uma das funções de gerar sequências que já vimos antes):
## Seleciona os elementos de 1 a 5
1:5]
cont[1] 8 4 NA 9 6
[## Seleciona os elementos nas posições ímpar
seq(1, 8, by = 2)]
cont[1] 8 NA 6 7 [
Mas note que para selecionar todos menos aqueles de uma sequência, precisamos colocá-la entre parênteses
-1:5]
cont[in cont[-1:5]: only 0's may be mixed with negative subscripts
Error cont[-(1:5)]
[1] 1 7 9
Para selecionar todos os elementos que sejam NA
, ou todos menos os
NA
s, precisamos usar a função is.na()
## Para selecionar os NAs
is.na(cont)]
cont[1] NA
[## Para selecionar todos menos os NAs
!is.na(cont)]
cont[1] 8 4 9 6 1 7 9 [
Para substituir os NA
s por algum valor (e.g. 0):
is.na(cont)] <- 0
cont[
cont1] 8 4 0 9 6 1 7 9 [
E para especificar NA
para algum valor
is.na(cont) <- 3
cont1] 8 4 NA 9 6 1 7 9
[## Mais seguro do que
# cont[3] <- NA
Note que se utilizarmos o operador de atribuição <-
em conjunto com
uma indexação, estaremos substituindo os valores selecionados
pelos valores do lado direito do operador de atribuição.
Podemos também utilizar mais duas formas de indexação no R: espaços em branco e zero:
0]
cont[numeric(0)
cont[]1] 8 4 NA 9 6 1 7 9 [
Note que o índice zero não existe no R, mas ao utilizá-lo é retornado um vetor “vazio”, ou um vetor de comprimento zero. Essa forma de indexação é raramente utilizada no R.
Ao deixar um espaço em branco, estamos simplesmente informando que queremos todos os valores daquele vetor. Essa forma de indexação será particularmente útil para objetos que possuem duas ou mais dimensões, como matrizes e data frames.
Exercícios
- Crie um vetor com os valores:
88, 5, 12, 13
. - Selecione o elemento na posição 3.
- Selecione o valor 88.
- Selecione os valores 13 e 5.
- Selecione todos os valores, menos o 88 e o 13.
- Insira o valor 168 entre os valores 12 e 13, criando um novo objeto.
3.1.1.1 Vetores nomeados
Quando vetores possuem seus componentes nomeados, a indexação pode ser realizada pelos nomes destes componentes.
## Atribui as letras "a", "b", ..., "h" para os componentes de cont
names(cont) <- letters[1:length(cont)]
## Acessando o quarto elemento
"d"]
cont[
d 9
## Acessando o sexto e o primeiro elemento
c("f", "a")]
cont[
f a 1 8
Dica: veja ?letters
3.1.2 Indexação de matrizes
Considere a seguinte matriz
<- matrix(1:9, nrow = 3)
mat
mat1] [,2] [,3]
[,1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9 [
Acesse o valor que está na linha 2 da coluna 3:
2, 3]
mat[1] 8 [
A indexação de matrizes sempre segue a ordem [linha, coluna]
Para acessar todas as linhas da coluna 1, deixamos o espaço em branco (que também é uma forma de seleção, como vimos) na posição das linhas e especificamos a coluna desejada
1]
mat[, 1] 1 2 3 [
Para acessar todas as colunas da linha 1, usamos a mesma lógica
1, ]
mat[1] 1 4 7 [
Note que o resultado destas extrações trazem os valores internos das
matrizes, mas com a dimensão reduzida (nestes casos para uma
dimensão). Se o objetivo for, por exemplo, extrair uma parte da matriz,
mas mantendo as duas dimensões, então precisamos usar o argumento drop
da “função” [
(sim, também é uma função; veja "?["
).
Veja as diferenças:
3, 2]
mat[1] 6
[3, 2, drop = FALSE]
mat[1]
[,1,] 6
[1, ]
mat[1] 1 4 7
[1, , drop = FALSE]
mat[1] [,2] [,3]
[,1,] 1 4 7 [
Para acessar as linhas 1 e 3 das colunas 2 e 3:
c(1, 3), c(2, 3)]
mat[1] [,2]
[,1,] 4 7
[2,] 6 9 [
E note que aqui a dimensão já é 2 pois naturalmente o resultado precisa ser representado em duas dimensões.
3.1.2.1 Matrizes nomeadas
Se as matrizes tiverem linhas e/ou colunas nomeadas, a indexação também pode ser feita com os nomes.
##----------------------------------------------------------------------
## Nomes das colunas
colnames(mat) <- LETTERS[1:3]
## Todas as linhas da coluna B
"B"]
mat[, 1] 4 5 6
[## Elemento da linha 1 e coluna C
1, "C"]
mat[
C 7
##----------------------------------------------------------------------
## Nomes das linhas
rownames(mat) <- LETTERS[24:26]
## Todas as colunas da linha X
"X", ]
mat[
A B C 1 4 7
## Elemento da linha Y e coluna A
"Y", "A"]
mat[1] 2 [
3.1.3 Indexação de listas
Considere a seguinte lista:
<- list(c(3, 8, 7, 4), mat, 5:0)
lis
lis1]]
[[1] 3 8 7 4
[
2]]
[[
A B C1 4 7
X 2 5 8
Y 3 6 9
Z
3]]
[[1] 5 4 3 2 1 0 [
Podemos acessar um componente da lista da maneira usual
1]
lis[1]]
[[1] 3 8 7 4 [
Mas note que esse objeto continua sendo uma lista
class(lis[1])
1] "list" [
Geralmente o que queremos é acessar os elementos que estão contidos
nos componentes da lista, e para isso precisamos usar [[
no lugar de
[
:
1]]
lis[[1] 3 8 7 4
[class(lis[[1]])
1] "numeric" [
Isso é importante, por exemplo, se quisessemos aplicar uma função qualquer a um componente da lista. No primeiro caso isso não é possível pois o conteúdo continua dentro de uma lista, enquanto que no segundo caso os valores retornados são os próprios números:
mean(lis[1])
in mean.default(lis[1]): argument is not numeric or logical: returning
Warning NA
1] NA
[mean(lis[[1]])
1] 5.5 [
Para acessar o segundo componente da lista:
2]]
lis[[
A B C1 4 7
X 2 5 8
Y 3 6 9 Z
Para acessar o terceiro valor do primeiro componente:
1]][3]
lis[[1] 7 [
Note que o segundo elemento da lista é uma matriz, portanto a indexação da matriz dentro da lista também segue o mesmo padrão
2]][2, 3]
lis[[1] 8 [
Se a lista tiver componentes nomeados, eles podem ser acessados com
o operador $
:
<- list(vetor1 = c(3, 8, 7, 4), mat = mat, vetor2 = 5:0)
lis ## Ou
## names(lis) <- c("vetor1", "mat", "vetor2")
lis$vetor1
1] 3 8 7 4
[
$mat
A B C1 4 7
X 2 5 8
Y 3 6 9
Z
$vetor2
1] 5 4 3 2 1 0 [
## Acesando o segundo componente
$mat
lis
A B C1 4 7
X 2 5 8
Y 3 6 9
Z ## Linha 2 e coluna 3
$mat[2, 3]
lis1] 8
[## Terceiro elemento do primeiro componente
$vetor1[3]
lis1] 7 [
Ou então
"mat"]]
lis[[
A B C1 4 7
X 2 5 8
Y 3 6 9
Z "vetor1"]][3]
lis[[1] 7 [
O símbolo $
é utilizado para acessar componentes nomeados de
listas ou data frames.
3.1.4 Indexação de data frames
Considere o seguinte data frame
<- data.frame(A = 4:1, B = c(2, NA, 5, 8))
da
da
A B1 4 2
2 3 NA
3 2 5
4 1 8
Para acessar o segundo elemento da primeira coluna (segue a mesma lógica da indexação de matrizes pois também possui duas dimensões):
2, 1]
da[1] 3 [
Acesse todas as linhas da coluna B:
2]
da[, 1] 2 NA 5 8 [
Ou usando o nome da coluna:
"B"]
da[,1] 2 NA 5 8 [
Todas as colunas da linha 1:
1, ]
da[
A B1 4 2
Ou usando o “nome” da linha:
"1", ]
da[
A B1 4 2
Note que o argumento drop=
também é válido se quiser manter a dimensão
do objeto
"B"]
da[, 1] 2 NA 5 8
["B", drop = FALSE]
da[,
B1 2
2 NA
3 5
4 8
Como o data frame é um caso particular de uma lista (onde todos os
componentes tem o mesmo comprimento), as colunas de um data frame também
podem ser acessadas com $
:
$A
da1] 4 3 2 1 [
Para acessar o terceiro elemento da coluna B:
$B[3]
da1] 5 [
Para acessar os elementos nas posições 2 e 4 da coluna B:
$B[c(2, 4)]
da1] NA 8 [
Assim como nas listas, podemos indexar um data frame usando apenas um índice, que nesse caso retorna a coluna (componente) do data frame:
1]
da[
A1 4
2 3
3 2
4 1
class(da[1])
1] "data.frame" [
Note que dessa forma a classe é mantida. Também podemos indexar os data
frames usando [[
da mesma forma como em listas
1]]
da[[1] 4 3 2 1
["A"]]
da[[1] 4 3 2 1
["A"]][2:3]
da[[1] 3 2 [
Para lidar com NA
s em data frames, podemos também usar a função
is.na()
is.na(da), ] # nao retorna o resultado esperado
da[
A BNA NA NA
## Deve ser feito por coluna
is.na(da$A), ]
da[1] A B
[<0 rows> (or 0-length row.names)
is.na(da$B), ]
da[
A B2 3 NA
## De maneira geral
is.na(da)
A B1,] FALSE FALSE
[2,] FALSE TRUE
[3,] FALSE FALSE
[4,] FALSE FALSE
[is.na(da$A)
1] FALSE FALSE FALSE FALSE
[is.na(da$B)
1] FALSE TRUE FALSE FALSE [
Para remover as linhas que possuem NA
, note que será necessário
remover todas as colunas daquela linha, pois data frames não podem ter
colunas de comprimentos diferentes
!is.na(da$B), ]
da[
A B1 4 2
3 2 5
4 1 8
A função complete.cases()
facilita esse processo. Veja o resultado
complete.cases(da)
1] TRUE FALSE TRUE TRUE
[complete.cases(da), ]
da[
A B1 4 2
3 2 5
4 1 8
3.1.4.1 A função with()
Para evitar fazer muitas indexações de um mesmo data frame, por exemplo,
podemos utilizar a função with()
with(da, A)
1] 4 3 2 1 [
é o mesmo que
$A
da1] 4 3 2 1 [
Também é útil para acessar elementos específicos dentro de data frames. Por exemplo, o terceiro elemento da coluna B
with(da, B[3])
1] 5 [
E também para aplicar funções nas colunas do data frame
with(da, mean(A))
1] 2.5 [
Exercícios
- Crie a seguinte matriz \[\left[ \begin{array}{ccc} 4 & 16 & 2 \\ 10 & 5 & 11 \\ 9 & 9 & 5 \\ 2 & 0 & NA \end{array} \right].\]
- Acesse o elemento na quarta linha e na segunda coluna.
- Acesse todos os elementos, com exceção da segunda coluna e da terceira linha.
- Crie uma lista (nomeada) com 3 componentes: um vetor numérico de comprimento 10, um vetor de caracteres de comprimento 7 e a matriz do exercício anterior.
- Acesse os elementos nas posições de 5 a 3 do primeiro componente da lista.
- Acesse os caracteres de todas as posições, menos da 2 e 6.
- Acesse todas as linhas da coluna 3 da matriz dentro desta lista.
- “Crie” um novo componente nessa lista (usando
$
), contendo 30 valores aleatórios de uma distribuição normal \(\text{N}(12, 4)\) (veja?rnorm
). - Crie um data frame que contenha duas colunas: a primeira com as
letras de “A” até “J”, e outra com o resultado de uma chamada da
função
runif(7, 1, 5)
. - Extraia as duas primeiras linhas desse data frame.
- Extraia as duas últimas linhas desse data frame.
- Qual é o valor que está na linha 6 e coluna 1?
- Qual é o valor que está na linha 4 da coluna 2?
- Como você faria para contar quantos valores perdidos (
NA
s) existem nesse data frame? - Elimine os
NA
s deste data frame. - Crie uma nova coluna neste data frame, com valores numéricos (quaisquer).
- Crie mais um componente na lista anterior, que será também uma lista
com dois componentes:
A
com os valores1:5
, eB
com as letras de “a” a “f”. - Acesse o número 4 de
A
. - Acesse a letra “c” de
B
.
3.2 Seleção condicional
3.2.1 Seleção condicional em vetores
A seleção condicional serve para extrair dados que satisfaçam algum critério, usando expressões condicionais e operadores lógicos.
Considere o seguinte vetor
<- c(5, 15, 42, 28, 79, 4, 7, 14) dados
Selecione apenas os valores maiores do que 15:
> 15]
dados[dados 1] 42 28 79 [
Selecione os valores maiores que 15 E menores ou iguais a 35:
> 15 & dados <= 35]
dados[dados 1] 28 [
Para entender como funciona a seleção condicional, observe apenas o resultado da condição dentro do colchetes:
## Usando & (e)
> 15 & dados <= 35
dados 1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[## Usando | (ou)
> 15 | dados <= 35
dados 1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE [
Os valores selecionados serão aqueles em que a condição for
TRUE
, no primeiro caso apenas o quarto elemento do vetor dados
.
A seleção condicional também é muito útil para selecionar elementos de um vetor, baseado em uma condição de outro vetor.
Considere o seguinte vetor de caracteres
<- letters[1:length(dados)] cara
Considere que de alguma forma, os objetos dados
e cara
possuem
alguma relação. Sendo assim, podemos selecionar elementos de dados
,
baseados em alguma condição de cara
## Elemento de dados onde cara é igual a "c"
== "c"]
dados[cara 1] 42 [
Se quisermos selecionar mais de um elemento de dados
, baseado em uma
condição de cara
?
## Elementos de dados onde cara é igual a "a" e "c"
== "a" & cara == "c" # porque não funciona?
cara 1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[== "a" | cara == "c"
cara 1] TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
[== "a" | cara == "c"]
dados[cara 1] 5 42 [
Uma solução melhor seria se pudessemos usar
== c("a", "c")]
dados[cara 1] 5 [
mas nesse caso só temos o primeiro elemento. Um operador muito útil
nestes casos é o %in%
%in% c("a", "c")]
dados[cara 1] 5 42
[%in% c("a", "c")
cara 1] TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE [
Veja a diferença
== c("a", "c")
cara 1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[%in% c("a", "c")
cara 1] TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE [
Também é possível fazer a seleção de cara
, baseado em uma condição em
dados
## Elemento de cara onde dados é igual a 15
== 15]
cara[dados 1] "b"
[## Elemento de cara onde dados for maior do que 30
> 30]
cara[dados 1] "c" "e"
[## Elemento de cara onde dados for igual a 4 ou 14
%in% c(4, 14)]
cara[dados 1] "f" "h" [
3.2.2 A função which()
Até agora vimos seleções condicionais que nos retornavam o resultado de uma expressão condicional em vetores. No entanto, muitas vezes estamos interessados em saber a posição do resultado de uma expressão condicional, ao invés do resultado em si.
A fução which()
retorna as posições dos elementos que retornarem
TRUE
em uma expressão condicional.
## Elementos maiores de 15
> 15]
dados[dados 1] 42 28 79
[which(dados > 15)
1] 3 4 5
[## Elementos maiores de 15 e menores ou iguais a 35
> 15 & dados <= 35]
dados[dados 1] 28
[which(dados > 15 & dados <= 35)
1] 4
[## Elementos de dados onde cara igual a "c"
== "c"]
dados[cara 1] 42
[which(cara == "c")
1] 3
[## Elementos de dados onde cara é igual a "a" ou "c"
%in% c("a", "c")]
dados[cara 1] 5 42
[which(cara %in% c("a", "c"))
1] 1 3 [
Exercícios
- Crie um vetor (
x
) com os valores 3, 8, 10, 4, 9, 7, 1, 9, 2, 4. - Selecione os elementos maiores ou iguais a 5.
- Selecione todos os elementos menos o 4.
- Selecione os elementos maiores que 4 e menores que 8.
- Crie um vetor (
a
) com as letras de A até J. - Selecione os elementos de x onde a for igual a “F”.
- Selecione os elementos de x onde a for igual a “B”, “D”, e “H”.
- Qual a posição do número 10 em x?
- Quais as posições dos valores maiores ou iguais a 8 e menores ou iguais a 10 em x?
- Quais as posições das letras “A”, “B”, “D” em a?
3.2.3 Seleção condicional em data frames
Considere o seguinte data frame
<- data.frame(ano = c(2001, 2002, 2003, 2004, 2005),
dados captura = c(26, 18, 25, 32, NA),
porto = c("SP", "RS", "SC", "SC", "RN"))
Extraia deste objeto apenas a linha correspondente ao ano 2004:
$ano == 2004, ]
dados[dados
ano captura porto4 2004 32 SC
Mostre as linhas apenas do porto “SC”:
$porto == "SC", ]
dados[dados
ano captura porto3 2003 25 SC
4 2004 32 SC
Observe as linhas onde a captura seja maior que 20, selecionando apenas
a coluna captura
:
$captura > 20, "captura"]
dados[dados1] 26 25 32 NA [
Também exclua as linhas com NA
s (agora com todas as colunas):
$captura > 20 & !is.na(dados$captura), ]
dados[dados
ano captura porto1 2001 26 SP
3 2003 25 SC
4 2004 32 SC
$captura > 20 & complete.cases(dados), ]
dados[dados
ano captura porto1 2001 26 SP
3 2003 25 SC
4 2004 32 SC
A condição pode ser feita com diferentes colunas:
$captura > 25 & dados$porto == "SP", ]
dados[dados
ano captura porto1 2001 26 SP
A função subset()
serve para os mesmos propósitos, e facilita todo o
processo de seleção condicional:
$porto == "SC", ]
dados[dados
ano captura porto3 2003 25 SC
4 2004 32 SC
subset(dados, porto == "SC")
ano captura porto3 2003 25 SC
4 2004 32 SC
$captura > 20, ]
dados[dados
ano captura porto1 2001 26 SP
3 2003 25 SC
4 2004 32 SC
NA NA NA <NA>
subset(dados, captura > 20)
ano captura porto1 2001 26 SP
3 2003 25 SC
4 2004 32 SC
$captura > 20 & !is.na(dados$captura), ]
dados[dados
ano captura porto1 2001 26 SP
3 2003 25 SC
4 2004 32 SC
$captura > 20, "captura"]
dados[dados1] 26 25 32 NA
[subset(dados, captura > 20, select = captura)
captura1 26
3 25
4 32
A grande vantagem é que a função subset()
já lida com os NA
s (se
isso for o que você precisa).
Exercícios
- Você contou 42 caranguejos na Joaquina, 34 no Campeche, 59 na Armação e 18 na Praia Mole. Crie um data frame para armazenar estas informações (número de caranguejos observados e local).
- Com o data frame criado no exercício anterior, mostre qual a praia onde foram coletadas menos de 30 caranguejos (usando seleção condicional!).
- Crie uma nova coluna (região) neste data frame indicando que Joaquina e Praia Mole estão localizadas no leste da ilha (leste) e Campeche e Armação estão no sul (sul).
- Selecione as praias de região leste que possuem menos de 20 caranguejos contados.
- Você está interessado em saber em qual das duas praias do sul, o número de caranguejos contados foi maior do que 40. Usando a seleção condicional, mostre essa informação na tela.
- Qual região possui praias com mais de 50 caranguejos contados?