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 2

O 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.4

E 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:

  1. Todos os seus elementos (colunas) precisam ter o mesmo comprimento (número de linhas).

  2. Todos os seus elementos (colunas) precisam ser nomeados.

  3. Data frames têm 2 dimensões.

As propriedades (1) e (2) se devem ao formato das bases de dados. Elas são retangulares7 — observamos as mesmas variáveis (colunas) para todas as unidades amostrais (linhas)8 —, 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       Casada

Quando 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, 2

Transformar 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                      Casada

A 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 11

O 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 mtcars tem 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)
## NULL

Ter 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] 160

O código acima está nos devolvendo o valor presente na segunda linha da terceira coluna da base mtcars.

Também podemos pegar todos 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    4

Por fim, lembrando que dento 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    2

O 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”?

  1. mtcars$mpg
  2. mtcars[ , 3]
  3. mtcars("mpg")
  4. mtcars[ , "mpg"]
  5. mtcars.mpg
  6. mtcars[ , 1]
  7. mtcars[1, 1]
  8. mpg$mtcars

  1. Também existem bases não retangulares, como dados de imagens por exemplos, mas não trataremos dessas estruturas neste livro.↩︎

  2. Mesmo quando uma variável não existe para uma unidade amostral, representamos esse valor como um missing↩︎


Curso-R