Tipos de objetos do R

Fugindo um pouco do padrão das postagens anteriores, irei falar um pouco sobre os tipos de objetos que o R permite, mais especificamente falar dos vetores, matrizes/arrays, data frames e listas. A ideia é apresentar estas estruturas de objetos, junto com suas características. Após, apresentar os possíveis jeitos de chamar seus elementos e alguns exemplos.



Vetores

Os vetores são a forma mais simples de armazenamento no R por possuírem apenas uma dimensão e todos seus elementos terem, obrigatoriamente, a mesma classe (isso é, todos os elementos ou são texto, ou são inteiros, ou são reais, ou são data, etc...). Temos por exemplo de vetores os seguintes casos:

c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # Vetor numérico de tamanho 10
1:10 # Uma maneira de montar sequências numéricas
c('arrorz', 'batata', 'feijão') # Vetor de textos de tamanho 3
c('arrorz', 'batata', 'feijão', '1') # Vetor de texto de tamanho 4 (note que o 1 está entre aspas, indicativo de texto)

Para obter apenas alguns valores de um vetor, podemos especificar a posição desejada, por exemplo:

c('arrorz', 'batata', 'feijão')[2:3] # Vetor de tamanho 2

Matrizes e arrays

Matrizes e arrays se diferenciam em apenas dois aspectos dos vetores: permitem que seus itens sejam apenas números ou textos (a restrição de todos serem da mesma classe permanece) e possui mais de uma dimensão. Enquanto as matrizes são vetores de duas dimensões, arrays possuem três ou mais dimensões. Temos por exemplo de matrizes e arrays:

matrix(1:9, 3) # Matriz com os números de 1 a 9, com 3 linhas e 3 colunas
matrix(1:9, 3, byrow = TRUE) # Matriz com os números de 1 a 9, com 3 linhas e 3 colunas, preenchendo primeiro as linhas
matrix(c('O', 'R', 'é', 'legal!'), 5, 3) # Matriz de texto. Os valores são repetidos até preencher toda a matriz.
array(1:24, c(2, 3, 4)) # O mesmo vale para números e arrays. No caso, um array de 2 linhas, 3 colunas e 4 níveis (2x3x4) com os valores de 1 a 24.

Onde, para matrizes, o segundo e terceiro parâmetros é o número de linhas e de colunas, respectivamente (Pode ser informado apenas um). Já para array, o segundo parâmetro deve ser um vetor informando as dimensões desejadas.  De maneira similar aos vetores, para obter alguns basta informar as posições em todas as dimensões.

matrix(1:9, 3)[2, 2] # Mostra apenas 5 (vetor de tamanho 1), o valor da segunda linha e segunda coluna.
matrix(1:9, 3)[2:3, 2] # Mostra apenas 5 e 6 (vetor de tamanho 2), valores da segunda e terceira linha da segunda coluna
array(1:24, c(2, 3, 4))[1, 2, 3] # Mostra apenas o valor 15 (vetor de tamanho 1), valor da primeira linha, da segunda coluna do terceiro nível

Para solicitar uma posição especifica de todas as demais dimensões basca não informar a posição da dimensão desejada.


matrix(1:9, 3)[2, ] # Mostra um vetor de tamanho 3 contendo os valores da 2a linha
array(1:24, c(2, 3, 4))[1, , ] # Mostra uma matriz 3x4 contendo os valores da primeira linha de todas as coluna de todos os níveis

Note que em ambos exemplos (tanto especificando todas as dimensões ou ocultando algumas), o valor retornado possui uma dimensão diferente da original (no primeiro caso temos um vetor e no segundo uma matrix, onde cada coluna representa um array). Caso desejássemos manter a estrutura original devemos acrescentar o parâmetro drop = FALSE.


matrix(1:9, 3)[2, 2, drop = FALSE] # Mostra uma matrix 1x1
array(1:24, c(2, 3, 4))[1, 2, 3, drop = FALSE] # Mostra um array 1x1x1
matrix(1:9, 3)[2, , drop = FALSE] # Mostra uma matrix 1x3 contendo os valores da 2a linha
array(1:24, c(2, 3, 4))[1, , , drop = FALSE] # Mostra um array 1x3x4 contendo os valores da 1a linha de todos os níveis

Data frames

Data frames são bem parecidos com matrizes, apenas não possuem a restrição de serem apenas texto ou número e a restrição de todos serem da mesma classe agora é por coluna. Em resumo, pode-se dizer que um data.frame é uma matriz de vetores de tamanhos iguais, cada um podendo ter uma classe diferente das outras. Este é o formato padrão de leitura de arquivos externos da maioria das funções. A criação de um data.frame é bastante parecida com a de um vetor:

data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time()) # Data frame com duas variáveis numéricas, uma de texto e uma data


A maneira de obter apenas algumas posições é semelhante com da matrix, informando a linha e a coluna separado por vírgulas e, caso algum seja omitido, retornado todos valores daquela dimensão. Note que informando mais de uma coluna, o resultado é um data.frame, indiferente do número de linhas. Já ao solicitar apenas uma coluna, o resultado é um vetor a menos que seja informado o parâmetro drop = FALSE.

data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time())[, 1] # Vetor
data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time())[, 1, drop = FALSE] # Data frame
data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time())[, 1:2] # Data frame
data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time())[1, ] # Data frame

Existe ainda outra maneira de chamar colunas inteiras, que é informar apenas o número da coluna. Note que desta maneira, o resultado será sempre outro data.frame.

data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time())[1] # Data frame
data.frame(x = 1:3, y = 3:1, z = c('a', 'b', 'c'), w = Sys.time())[1:2] # Data frame

Listas

O último tipo de objeto que irei apresentar aqui são as listas. Basicamente, listas são vetores sem nenhuma restrição - ou seja, cada elemento de uma lista pode ser qualquer coisa, incluindo outra lista. Elas são usadas principalmente em saídas de funções que fornecem mais de um tipo de informação.

list(x = 1:3) # Lista de tamanho 1
list(x = 1:3, y = c('a', 'b', 'c')) # Lista de tamanho 2
list(x = 1:3, y = c('a', 'b', 'c'), z = list(x = 1:3, y = c('a', 'b', 'c'))) # Lista de tamanho 3, contendo outra lista.

Para selecionar apenas alguns elementos, usa-se a mesma sintaxe de um vetor:

list(x = 1:3, y = c('a', 'b', 'c'), z = list(1:3, c('a', 'b', 'c')))[1] # Lista de tamanho 1
list(x = 1:3, y = c('a', 'b', 'c'), z = list(1:3, c('a', 'b', 'c')))[1:2] # Lista de tamanho 2
list(x = 1:3, y = c('a', 'b', 'c'), z = list(1:3, c('a', 'b', 'c')))[3] # Lista de tamanho 1

Relação listas x dataframes x vetores

Como a ajuda do R fala, "um data frame é uma lista de variáveis com o mesmo numero de linhas e com nomes de linhas iguais". Já na página de ajuda das listas, fala "quase todas as listas no R são, internalmente, vetores genéricos". Em resumo, tanto vetores quanto data frames são casos particulares de listas e, por isso, compartilham certos comportamentos, dentre os quais destaco o uso do for e da série de comandos *apply - funções que usualmente usamos somente com vetores.

Por exemplo, enquanto quando especificado uma matriz no for, o laço irá correr por todos os elementos. Já quando especificado um data frame, ele irá correr somente pelas colunas. Por exemplo:

for (i in matrix(1:9, 3)) { print(i) } # Imprime 9 vetores de tamanho 1
for (i in data.frame(1:3, 4:6, 7:9)) { print(i) } # Imprime 3 vetores de tamanho 3
for (i in list(1:3, 4:6, 7:9)) { print(i) } # Imprime 3 vetores de tamanho 3

Comportamento igual ao encontrado nos comandos *apply, como por exemplo o sapply:

sapply(matrix(1:9, 3), mean) # Vetor de tamanho 9
sapply(data.frame(1:3, 4:6, 7:9), mean) # Vetor de tamanho 3 - Média de 1 a 3, 4 a 6 e 7 a 9
sapply(list(1:3, 4:6, 7:9), mean) # Vetor de tamanho 3 - Média de 1 a 3, 4 a 6 e 7 a 9

Outro comando bastante útil é o Reduce(), que exige que o 2o parâmetro seja um vetor. Por exemplo, para juntar vários bancos de dados com um só comando basta:

banco1 <- data.frame(ID = 1:10, Idade = rnorm(10, 45, 5))
banco2 <- data.frame(ID = 1:10, Sexo = sample(c('F', 'M'), 10, rep = TRUE))
banco3 <- data.frame(ID = 1:10, Altura = rnorm(10, 170, 10))
banco4 <- data.frame(ID = 1:10, Hora = Sys.time() + rnorm(10, 0, 1000000))

banco <- Reduce(merge, list(banco1, banco2, banco3, banco4))

Considerações finais

Claro que nem todos os tipos de variáveis foram exemplificados aqui - temos por exemplo o data.table, que já foi assunto de outra postagem aqui no blog. Espero que tenha consigo explicar as principais diferenças entre os 4 tipos, especialmente para quem está começando a usar o R!

Dúvidas, críticas e sugestões são bem vindas :-)

Um comentário:

Anônimo disse...

Não tenho nada muito interessante para comentar, a não ser...
'arrorz'

:P