3.10 Mais sobre data frames
Chegou a hora de usarmos tudo o que aprendemos na seção anterior para exploramos ao máximo o nosso objeto favorito: o data frame.
Na seção anterior, nós dissemos que data frames são listas. Isso é importante pois todas as propriedades de uma lista valem para um data frame.
A melhor forma de entender essa equivalência é ver um data frame representado como uma lista.
as.list(mtcars)
## $mpg
## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4
##
## $cyl
## [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
##
## $disp
## [1] 160.0 160.0 108.0 258.0 360.0 225.0 360.0 146.7 140.8 167.6 167.6 275.8
## [13] 275.8 275.8 472.0 460.0 440.0 78.7 75.7 71.1 120.1 318.0 304.0 350.0
## [25] 400.0 79.0 120.3 95.1 351.0 145.0 301.0 121.0
##
## $hp
## [1] 110 110 93 110 175 105 245 62 95 123 123 180 180 180 205 215 230 66 52
## [20] 65 97 150 150 245 175 66 91 113 264 175 335 109
##
## $drat
## [1] 3.90 3.90 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 3.92 3.07 3.07 3.07 2.93
## [16] 3.00 3.23 4.08 4.93 4.22 3.70 2.76 3.15 3.73 3.08 4.08 4.43 3.77 4.22 3.62
## [31] 3.54 4.11
##
## $wt
## [1] 2.620 2.875 2.320 3.215 3.440 3.460 3.570 3.190 3.150 3.440 3.440 4.070
## [13] 3.730 3.780 5.250 5.424 5.345 2.200 1.615 1.835 2.465 3.520 3.435 3.840
## [25] 3.845 1.935 2.140 1.513 3.170 2.770 3.570 2.780
##
## $qsec
## [1] 16.46 17.02 18.61 19.44 17.02 20.22 15.84 20.00 22.90 18.30 18.90 17.40
## [13] 17.60 18.00 17.98 17.82 17.42 19.47 18.52 19.90 20.01 16.87 17.30 15.41
## [25] 17.05 18.90 16.70 16.90 14.50 15.50 14.60 18.60
##
## $vs
## [1] 0 0 1 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1
##
## $am
## [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1
##
## $gear
## [1] 4 4 4 3 3 3 3 4 4 4 4 3 3 3 3 3 3 4 4 4 3 3 3 3 3 4 5 5 5 5 5 4
##
## $carb
## [1] 4 4 1 1 2 1 4 2 2 4 4 3 3 3 4 4 4 1 2 1 1 2 2 4 2 1 2 2 4 6 8 2O código acima nos permite ver o data frame mtcars representado como uma lista. Veja que cada coluna da base se transforma em um elemento da lista. E o nome de cada coluna vira o nome de cada posição. Isso é interessante, pois podemos usar nos data frames as mesmas operações que aprendemos para listas.
Por exemplo, podemos usar o operador $ para acessar cada elemento da lista, isto é, cada coluna do data frame.
mtcars$mpg
## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4E assim como cada elemento de uma lista também é uma lista, cada elemento (coluna) de um data frame também é um data frame.
mtcars[1]
## mpg
## Mazda RX4 21.0
## Mazda RX4 Wag 21.0
## Datsun 710 22.8
## Hornet 4 Drive 21.4
## Hornet Sportabout 18.7
## Valiant 18.1
## Duster 360 14.3
## Merc 240D 24.4
## Merc 230 22.8
## Merc 280 19.2
## Merc 280C 17.8
## Merc 450SE 16.4
## Merc 450SL 17.3
## Merc 450SLC 15.2
## Cadillac Fleetwood 10.4
## Lincoln Continental 10.4
## Chrysler Imperial 14.7
## Fiat 128 32.4
## Honda Civic 30.4
## Toyota Corolla 33.9
## Toyota Corona 21.5
## Dodge Challenger 15.5
## AMC Javelin 15.2
## Camaro Z28 13.3
## Pontiac Firebird 19.2
## Fiat X1-9 27.3
## Porsche 914-2 26.0
## Lotus Europa 30.4
## Ford Pantera L 15.8
## Ferrari Dino 19.7
## Maserati Bora 15.0
## Volvo 142E 21.4
class(mtcars[1])
## [1] "data.frame"Mas se data frames são listas, por que existe a classe data frame? Na verdade, data frames são um tipo especial de listas, que têm as seguintes propriedades:
Todos os seus elementos (colunas) precisam ter o mesmo comprimento (número de linhas).
Todos os seus elementos (colunas) precisam ser nomeados.
Data frames têm 2 dimensões.
As propriedades (1) e (2) se devem ao formato das bases de dados. Elas são retangulares8 — observamos as mesmas variáveis (colunas) para todas as unidades amostrais (linhas)9 —, e precisam ter algum nome especificando as colunas.
Da mesma forma que podemos ver um data frame como uma lista, também podemos fazer o inverso.
dados_cliente <- list(
cliente = c("Ana Silva", "Beto Pereira", "Carla Souza"),
idade = c(25, 30, 23),
estado_civil = c(NA, "Solteiro", "Casada")
)
dados_cliente
## $cliente
## [1] "Ana Silva" "Beto Pereira" "Carla Souza"
##
## $idade
## [1] 25 30 23
##
## $estado_civil
## [1] NA "Solteiro" "Casada"
as.data.frame(dados_cliente)
## cliente idade estado_civil
## 1 Ana Silva 25 <NA>
## 2 Beto Pereira 30 Solteiro
## 3 Carla Souza 23 CasadaQuando tivermos valores faltantes na nossa base (células vazias no Excel), eles serão representados por NA nos data frames.
Observe que não conseguimos transformar uma lista em data frame se os elementos da lista não tiverem o mesmo comprimento.
dados_cliente <- list(
cliente = c("Ana Silva", "Beto Pereira", "Carla Souza"),
idade = c(25, 30),
estado_civil = c(NA, "Solteiro", "Casada")
)
as.data.frame(dados_cliente)
## Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : arguments imply differing number of rows: 3, 2Transformar uma lista não nomeada em data frame é possível, mas o R cria nomes nada agradáveis para as colunas.
dados_cliente <- list(
c("Ana Silva", "Beto Pereira", "Carla Souza"),
c(25, 30, 23),
c(NA, "Solteiro", "Casada")
)
as.data.frame(dados_cliente)
## c..Ana.Silva....Beto.Pereira....Carla.Souza.. c.25..30..23.
## 1 Ana Silva 25
## 2 Beto Pereira 30
## 3 Carla Souza 23
## c.NA...Solteiro....Casada..
## 1 <NA>
## 2 Solteiro
## 3 CasadaA propriedade (3) é atribuída aos data frames para que possamos aproveitar melhor dessa estrutura retangular dentro do R. Na prática, essas duas dimensões representam nada mais que as linhas e as colunas da base. Essa é a maior diferença entre uma lista e um data frame.
class(mtcars)
## [1] "data.frame"
dim(mtcars)
## [1] 32 11O resultado do código dim(mtcars) nos dá as seguintes informações:
O data frame mtcars tem duas dimensões (como todo data frame).
A primeira dimensão tem comprimento 32 e a segunda dimensão tem comprimento 11. Em outras palavras: a base
mtcarstem 32 linhas e 11 colunas.
Veja a seguir que listas não têm dimensão.
mtcars_como_lista <- as.list(mtcars)
class(mtcars_como_lista)
## [1] "list"
dim(mtcars_como_lista)
## NULLTer duas dimensões significa que devemos usar dois índices para acessar os valores de um data frame (fazer subsetting). Para isso, ainda usamos o colchete, mas agora com dois argumentos: [linha, coluna].
mtcars[2, 3]
## [1] 160O código acima está nos devolvendo o valor presente na segunda linha da terceira coluna da base mtcars.
Também podemos pegar todas as linhas de uma coluna ou todas as colunas de uma linha deixando um dos argumentos vazio:
# Todas as linhas da coluna 1
mtcars[,1]
## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
## [31] 15.0 21.4
# Todas as colunas da linha 1
mtcars[1,]
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21 6 160 110 3.9 2.62 16.46 0 1 4 4Por fim, lembrando que dentro de cada coluna temos um vetor, podemos usar os testes lógicos para filtrar as linhas do nosso data frame conforme alguma regra.
mtcars$cyl == 4
## [1] FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE FALSE FALSE
## [25] FALSE TRUE TRUE TRUE FALSE FALSE FALSE TRUE
mtcars[mtcars$cyl == 4, ]
## mpg cyl disp hp drat wt qsec vs am gear carb
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2O código mtcars$cyl == 4 nos diz em quais linhas estão os carros com 4 cilindros. Quando usamos o vetor de TRUE e FALSE resultante dentro do subsetting das linhas em mtcars[mtcars$cyl == 4, ], o R nos devolve todos as colunas dos carros com 4 cilindros. A regra é simples: linha com TRUE é retornada, linha com FALSE não.
Encerramos aqui a nossa primeira conversa sobre data frames para falar de outra estrutura muito importante dentro do R: as funções.
Exercícios
1. Quais códigos abaixo retornam um vetor com a coluna mpg do data frame mtcars?
a.
mtcars$mpgb.
mtcars[ , 3]c.
mtcars("mpg")d.
mtcars[ , "mpg"]e.
mtcars.mpgf.
mtcars[ , 1]g.
mtcars[1, 1]h.
mpg$mtcars
2. Para que serve a função str(). Dê um exemplo do seu uso.
3. Para que serve a função names(). Dê um exemplo do seu uso.
4. Use o data frame airquality para responder às questões abaixo:
a. Quantas colunas
airqualitytem?b. Quantas linhas
airqualitytem?c. O que a função
head()retorna?d. Quais são os nomes das colunas?
e. Qual é a classe da coluna
Ozone?
5. Desafio. Calculando desvio-padrão no R. Use o data frame airquality para responder às questões abaixo:
a. Tire a média da coluna Ozone e guarde em um objeto.
b. Guarde em um objeto o vetor correspondente à coluna Ozone subtraída da sua própria média (calculada em no item a).
c. Eleve o vetor calculado em (b) ao quadrado. Salve o resultado em um novo objeto.
d. Tire a média do vetor calculado em (c) e salve o resultado em um objeto chamado
variancia. Em seguida, calcule a raiz quadrada desse valor e salve em um objeto chamadodesvio_padrao.e. Compare o valor de
desvio_padraocomsd(airquality$Ozone, na.rm=TRUE)e pesquise por que os valores não são iguais. Dica: veja a documentação da funçãosd().
6. Use o data frame airquality para responder às questões abaixo.
a. Conte quantos
NAstem na colunaSolar.R.b. Filtre a tabela
airqualitycom apenas linhas em queSolar.RéNA.c. Filtre a tabela
airqualitycom apenas linhas em queSolar.Rnão éNA.d. Filtre a tabela
airqualitycom apenas linhas em queSolar.Rnão éNAeMonthé igual a 5.