Analisando grandes bancos de dados no R.

Dando continuidade ao post anterior (eu juro que o próximo post não vai ser 'Fazendo algo em grandes bancos de dados no R'), vamos dar uma olhada em outro pacote que auxilia na manipulação de bancos grandes no R: o data.table. Mais uma vez, usarei os dados do ENEM 2011 como exemplo.

Como o site do data.table descreve, ele é uma versão mais incrementada do data.frame, o formato padrão de leitura de arquivos externos do R e com uma sintaxe é bastante parecida, facilitando bastante o aprendizado. A ideia do post é apresentar as principais funções do data.table e mostrar o ganho computacional dele. Ao final, um link com todos o código utilizado.

Se o seu banco está no formato data.frame, é necessário transforma-lo em data.table. Para tal, basta executar o comando data.table(). O pacote possui alguns comandos para leitura de arquivos externos direto em data.table, como o fread(). No caso do banco do ENEM, optei por carregar o banco em data.frame e depois transforma-lo em data.table, o que falhou devido o tamanho grande do banco. Para solucionar, importei somente as variáveis de interesse e depois transformei o banco em data.table.

Após transformar o banco em data.table, podemos notar as primeiras diferenças já no print do objeto. Ao contrário do tata.frame (que tenta exibir todo o banco), ao visualizar a variável são exibidas apenas as 5 primeiras e 5 últimas observações, além da linha estar representada por "numero da linha:", e não somente "numero da linha".

Exemplo 1: Adição de colunas.

O primeiro exemplo que faremos é a criação de uma nova variável, a da nota final do ENEM. Nos dois tipos de variável (data.table e data.frame), podemos acrescentar uma variável nova da seguinte maneira:

dados$NomeFinal <- (dados$NU_NT_CN + dados$NU_NT_CH + dados$NU_NT_LC + dados$NU_NT_MT + dados$NU_NOTA_REDACAO) / 5

Neste exemplo, já temos uma vantagem do data.table (0,42 segundos) frente ao data.frame (0,58 segundos). Ainda é possível aumentar essa diferença, usando o operador := do data.table, como no exemplo:

dados[,NotaFinal := (NU_NT_CN + NU_NT_CH + NU_NT_LC + NU_NT_MT + NU_NOTA_REDACAO) / 5]


Usando o comando acima, o tempo foi de 0.16 segundos. A sintaxe é bastante parecida com a criação de variáveis do R, diferenciando apenas nos : que aparecem antes do sinal de igual. 

Exemplo 2: Agrupamento de observações descriminando por uma ou mais variáveis.

Aqui temos uma das principais  - se não a principal - vantagens do data.table: o agrupamento de observações. A sua sintaxe é, novamente, bastante intuitiva. Por exemplo, para calcular a nota média do ENEM por estado podemos utilizar:

dados[, mean(NotaFinal), by = 'UF_INSC']

Para obter um resultado similar com data.frame, podemos utilizar o comando aggregate(), como por exemplo:

aggregate(NotaFinal ~ UF_INSC, data = dados, mean)

Aqui a diferença de tempo se torna maior, demorando 6,46 segundos no data.frame, enquanto no data.table demora apenas 0,29 segundos. É possível agrupar por duas ou mais variáveis informando um vetor com os nomes das variáveis. Por exemplo, calculando a nota média por estado e por sexo (levou 0,47 segundos no data.table, enquanto no data.frame 8,30):

dados[, mean(NotaFinal), by=c('UF_INSC', 'TP_SEXO')]

Exemplo 3: Selecionando observações.

Você deve ter notado que nos 2 exemplos acima sempre informamos do segundo parâmetro em diante (tem uma vírgula na frente sempre). Isso é devido ao primeiro parâmetro ser exclusivo para indicar quais observações eu quero (ao não informar, eu digo que quero todos), e é o quesito no qual o data.table mais se diferencia em termos de velocidade. Antes de utilizarmos ele, devemos informar quais são as variáveis que usaremos como chave através do comando setkey(). Por exemplo, para pegar somente os candidatos que realizaram a prova no RS, devemos fazer:

setkey(dados, UF_INSC)
dados_RS <- dados['RS']

Os dois comandos juntos demoraram 0,9 segundos, enquanto o equivalente para data.frame demorou 1,73 segundos. Quando a (ou uma das) variável chave é numérica devemos informar os valores desejados utilizando data.table. Por exemplo, caso queiramos computar a nota média apenas dos que realizaram todas as provas e por estado:

setkey(dados, IN_PRESENCA_CN, IN_PRESENCA_CH, IN_PRESENCA_LC, IN_PRESENCA_MT, IN_STATUS_REDACAO)
valores_desejados <- data.table(IN_PRESENCA_CN = 1, IN_PRESENCA_CH = 1, IN_PRESENCA_LC = 1, IN_PRESENCA_MT = 1, IN_STATUS_REDACAO = 'P')
dados[valores_desejados, mean(NotaFinal), by = UF_INSC]

Este segundo exemplo levou 0,26 segundos no data.table, enquanto o comando equivalente no data.frame levou 10,44 segundos.

Considerações finais

Se você chegou até aqui, já sabe o suficiente para utilizar o pacote data.table. Importante ressaltar que esse post é apenas um exemplo dos principais comandos, e não um manual completo do pacote. Outro ponto que vale a pena ser ressaltado é que um data.table é um data.frame, portanto todas funções que exigem data.frame como parâmetros também funcionam com data.table.

O código utilizado pode ser baixado aqui. Dúvidas, críticas e sugestões são bem vindas :-)

Um comentário:

Anônimo disse...

Nossa, acho que do jeito que ficou o data.table dá tranquilo para sair do SQL <3 Vou tentar fazer uns experimentos!