Conforme o R Core Team (2023), data frame é a estrutura que imita de forma mais próxima um dataset do SAS ou SPSS. De forma resumida um data frame é uma estrutura tabular com colunas (variáveis, atributos, etc) e linhas (registros, casos, observações, instâncias, etc). Diferente de uma matriz um data frame pode ter diferentes tipos de dados em suas colunas.
Um data frame possui todas as colunas com o mesmo tamanho (quantidade de regitros). A classe de um objeto data frame possui o nome data.frame. Abaixo pode ser visualizada a classe do data frameiris (muito usado em exemplos em Ciência de Dados) e também as primeiras linhas com o comando head.
Para continuar os próximos tópicos vamos trabalhar com um data frame (df_iris) criado a partir do data frameiris. Faremos ajustes nos nomes deste data frame.
# criar data frame df_irisdf_iris <- iris# mudar nomes para maiusculasnames(df_iris) <-toupper(names(df_iris))# substituir '.' por '_'names(df_iris) <-gsub(names(df_iris), pattern ="\\.", replacement ="_") class(df_iris)
Os atributos “padrão” de um data frame são: names, class e row.names. É possível acessá-los com a função attributes. O atributo names também pode ser obtido com a função names.
A função dim retorna as dimensões de um data frame (linhas e colunas). Estes dados também podem ser obtidos com as funções nrow e ncol.
dim(df_iris)
[1] 150 5
nrow(df_iris)
[1] 150
ncol(df_iris)
[1] 5
8.4 Acessando Dados
8.4.1 Índices
Como a estrutura de um data frame é organizada em linhas e colunas, podemos acessar os dados utilizando colchetes ([ ]): base[linha, coluna]. Podem ser usados intervalos de índices com o operador :.
# Acessar primeira linha e segunda coluna (Sepal.Width)df_iris[1, 2]
[1] 3.5
# Acessar linhas 1 até 3 e a segunda colunadf_iris[1:3, 2]
[1] 3.5 3.0 3.2
Apesar de ser possível, utilizar o índice faz com que a referência seja relativa, ou seja, a variável ‘1’ pode mudar caso o data frame seja editado. Por exemplo, caso em algum momento anterior a variável PETAL_LENGTH tenha sido excluída, uma nova variável assumirá o índice 1. Além disto, no momento da leitura do código por um usuário não fica claro qual variável está sendo acessada.
8.4.2 Usando Nomes das Colunas
Existem diversas outras formas para acessar dados de um data frame, inclusive utilizando o nome da coluna de forma explícita.
# Acessar primeira linha e segunda coluna (pelo nome)df_iris[1:3, 'SEPAL_WIDTH']
[1] 3.5 3.0 3.2
Uma forma bastante comum é através da utilização do operador $ para acessar a coluna pelo seu nome.
# Acessar primeira linha e segunda colunadf_iris[1, ]$SEPAL_WIDTH
[1] 3.5
# Acessar linhas 1 até 3 e a segunda colunadf_iris[1:3, ]$SEPAL_WIDTH
[1] 3.5 3.0 3.2
Nome Abreviado
Assim como nas listas, variáveis de um data frame podem ser acessadas com o mínimo de caracteres que as identifiquem dentro do data frame. Por exemplo, df_iris$SP retornará a variável SPECIES.
8.5 Filtrando Dados
Digamos que se deseje acessar apenas dados que cumpram determinada condição. Para isto, na seleção das linhas do data frame, deve ser informada condição lógica na forma abaixo:
# Retorna valores de Speal.Width onde Petal.Length for maior do que 6x <- df_iris[df_iris$PETAL_LENGTH >6, 'SEPAL_WIDTH']y <- df_iris[df_iris$PETAL_LENGTH >6.5, ]$SEPAL_WIDTHx
[1] 3.0 2.9 3.6 3.8 2.6 2.8 2.8 3.8 3.0
y
[1] 3.0 3.8 2.6 2.8
# Função que compara os objetosidentical(x, y)
[1] FALSE
O retorno é dado pelas linhas em que a variável PETAL_LENGTH atende as condições declaradas. Este teste retorna um vetor de valores lógicos, e os valores TRUE são os que “permanecem”. Abaixo outro exemplo:
head(df_iris$PETAL_LENGTH) >1.4
[1] FALSE FALSE FALSE TRUE FALSE TRUE
Aplicando este vetor de valores lógicos, o R entende que as posições correspondentes a TRUE devem ser mantidas. No exemplo abaixo, as posições (linhas) 4 e 6 atendem a condição especificada, portanto apenas estas serão selecionadas.
Os filtros em data frames usados com $ ou [ ] (com apenas 1 variável) retornam vetores e não data frames. Desta forma se perde a classe e a estrutura tabular característica do data frame original.
class(df_iris[1:3, 1])
[1] "numeric"
class(df_iris[1:3, 'SEPAL_WIDTH'])
[1] "numeric"
Entretanto, sendo selecionadas mais de uma coluna, a classe retornada segue sendo data.frame.
A função subset permite efetuar filtro em um data frame e muitas vezes oferece uma forma mais organizada visualmente, principalmente quando em filtros com muitas condições. Uma outra vantagem é que a função subset retorna faz a seleção em um data.frame e retorna um data frame, mesmo com a seleção de apenas 1 variável.
Esta função também permite seleção de colunas a serem mantidas. Note que a função subset não demanda que o data frame seja referenciado antes das variáveis e também aceita os nomes das variáveis sem aspas. Isto torna o código mais legível.
MPG CYL HP
Fiat 128 32.4 4 66
Honda Civic 30.4 4 52
Toyota Corolla 33.9 4 65
Fiat X1-9 27.3 4 66
Porsche 914-2 26.0 4 91
Lotus Europa 30.4 4 113
Usando um filtro um pouco mais complexo e sem inserir o nome dos argumentos da função (x, subset e select):
df_mtcars_filtrado <-subset(df_mtcars, # dados MPG >25& CYL ==4& HP >70, # filtro c(MPG, CYL, HP)) # colunasdf_mtcars_filtrado
MPG CYL HP
Porsche 914-2 26.0 4 91
Lotus Europa 30.4 4 113
Nos exemplos anteriores foram declaradas de forma explícita as variáveis a serem mantidas. Para declarar as variáveis a serem excluídas basta utiliza o sinal de subtração -, de forma análoga a seleção por índices em componentes de vetores.
Uma grande necessidade ao se trablahar com dados tabulados é a junção de dados. A junção nada mais é do que usar bases de dados diferentes e carregar dados entre elas a partir de uma chave de identificação. Vamos usar duas bases de dados, uma com código e nome do município e outra com o código do município e sua população. Estes dados foram buscados em IBGE (s.d.).
Para juntar estes dados, usaremos como chave de identificação presente nas duas tabelas o campo COD_MUNICIPIO. A função usada, merge exige dois argumentos x e y, que são as bases de dados que usaremos para a junção.
df_completo <-merge(x = df_cidades, y = df_populacao,by ="COD_MUNICIPIO")head(df_completo)
COD_MUNICIPIO NOME POPULACAO
1 3304557 Rio de Janeiro 6211423
2 3550308 São Paulo 11451245
3 4314902 Porto Alegre 1332570
Este exemplo é o mais básico, onde os dados presentes em ambas tabelas são das mesmas ciades e também são ligadas por apenas uma chave de identificação. Vejamos um exemplo um pouco mais realista, onde alguns dados não estão presentes em ambas tabelas.
# rbind faz a inclusao de linha nas as bases criadasdf_cidades <-rbind(df_cidades, c('3106200', 'Belo Horizonte'))df_populacao <-rbind(df_populacao, c('4106902', 1773733))df_completo <-merge(x = df_cidades, y = df_populacao,by ="COD_MUNICIPIO")head(df_completo)
COD_MUNICIPIO NOME POPULACAO
1 3304557 Rio de Janeiro 6211423
2 3550308 São Paulo 11451245
3 4314902 Porto Alegre 1332570
Veja que os dados de Belo Horizonte e do Município de código 4106902 (Curitiba) não foram inseridos no data frame resultante. Por padrão a função merge faz a junção pelos dados presentes nos dois data frames. Caso desejemos especificar, usamos os parâmetros all.x e all.y.
Usando all.x informamos ao R que desejamos que todas as linhas presentes na base passada como argumento x sejam mantidas. Onde não existirem dados para estas linhas na tabela y serão preenchidos com NA.
COD_MUNICIPIO NOME POPULACAO
1 3106200 Belo Horizonte <NA>
2 3304557 Rio de Janeiro 6211423
3 3550308 São Paulo 11451245
4 4314902 Porto Alegre 1332570
De forma análoga, usar all.y informa para que as linhas da base y sejam mantidas.
COD_MUNICIPIO NOME POPULACAO
1 3304557 Rio de Janeiro 6211423
2 3550308 São Paulo 11451245
3 4106902 <NA> 1773733
4 4314902 Porto Alegre 1332570
Para cruzamento de todas as linhas das duas tabelas usamos o argumento all.
df_completo <-merge(x = df_cidades, y = df_populacao,by ="COD_MUNICIPIO", all = T)head(df_completo)
COD_MUNICIPIO NOME POPULACAO
1 3106200 Belo Horizonte <NA>
2 3304557 Rio de Janeiro 6211423
3 3550308 São Paulo 11451245
4 4106902 <NA> 1773733
5 4314902 Porto Alegre 1332570