Data Analytics com Javascript

Descubra como aproveitar todo o potencial do Javascript para realizar uma poderosa análise de dados. Neste post, exploramos técnicas de Data Analytics com Javascript, usando bibliotecas NPM e o poderoso runtime Node.js.

Data Analytics com Javascript
Photo by Carlos Muza / Unsplash

Não é de hoje que se ouve falar sobre a importância da análise de dados para tomadas de decisões e como ela tem ditado regras no mundo dos negócios.
Você sendo do digital ou não, Data Analytics pode e vai ajudar a otimizar sua empresa com análises e respostas inteligentes baseadas nos seus dados.

Nesse artigo eu não vou me aprofundar sobre Data Analytics, mas mostrar que é possível, simples, rápido e produtivo trabalhar com Javascript quando se trata de dados em geral.

English version can be found here.

O que é Data Analytics?

Que é algo bom você já deve ter ouvido/lido, e também que pode ajudar, melhorar e otimizar, mas o que é exatamente?

A análise de dados é um processo de inspeção, limpeza, transformação e modelagem de dados visando descobrir informações úteis, informar conclusões e apoiar a tomada de decisões.

fonte: https://pt.wikipedia.org/wiki/An%C3%A1lise_de_dados

Em outras palavras, vamos olhar para as informações que temos, vamos trata-las, classificar e organizar de forma que depois possamos tirar conclusões para uma tomada de decisão a nível tático e/ou estratégico.

Então, um processo que um analista de dados faria, seria algo como:

Processo para analise de dados.

Em resumo, temos:

  • Definimos qual pergunta ou problemática estamos querendo resolver.
  • Coletamos os dados brutos relevantes ao problema.
  • Tratamos esses dados (formatando, relacionando, removendo coisas que não vamos utilizar, etc.).
  • Analisamos os dados.
  • Criamos formas de visualizar esses dados (plotar gráficos, gerar relatórios, planilhas etc).
  • Compartilhamos o resultado.

Analisando dados com Javascript

Como de costume, existem diversas bibliotecas no JS para resolver o mesmo problema de formas diferentes, aqui vamos olhar apenas para uma; Tidy.js.

Tidy JS é uma biblioteca inspirada em um pacote da linguagem R (Tidyverse) com uma sintaxe muito limpa e simples, priorizando a legibilidade do seu código.
A documentação é cheia de exemplos e bastante explicação sobre cada método.

Para iniciarmos um projeto não tem segredo algum, caso você já tenho iniciado algum projeto Node.js vai ver que é mais do mesmo. Basta criar um arquivo package.json e adicionar a lib com nossos arquivos JS e estamos prontos.
Vamos rodar dois comandos no terminal (iniciar o projeto e instalar a lib), antes, crie uma pasta no seu ambiente de trabalho e navegue até ela pelo terminal, em seguida execute:

npm init -y
npm install @tidyjs/tidy -S
Iniciando o projeto em Node.js e adicionando o Tidy.js ao projeto

Com nosso projeto iniciado, podemos abrir essa pasta no nosso editor de código:

Projeto aberto no Visual Studio Code.

Vamos fazer uma rápida modificação no arquivo package.json para que ele aceite a sintaxe do ES (Não precisa se preocupar com isso, é apenas um detalhe de padrão de projeto, mas caso queira saber mais, pesquise sobre "Node.js CommonJS vs ES6"). Basta abrir o arquivo e adicionar a linha "type": "module",:

Package.json do projeto.

Para começarmos com o código, vamos criar um arquivo .js na raiz do nosso projeto, o nome não importa muito agora, mas eu sugiro algo como index.js ou main.js.
Neste arquivo vamos colocar um pequeno código de exemplo da própria documentação, apenas para testarmos:

import { tidy, mutate, arrange, desc } from "@tidyjs/tidy";

const data = [
    {a: 1, b: 10 },
    {a: 3, b: 12 },
    {a: 2, b: 10 },
];

const results = tidy(
  data,
  mutate({ ab: (d) => d.a * d.b }),
  arrange(desc("ab"))
);

console.table(results);
Código de exemplo.

Anteriormente falamos sobre os passos para analisarmos dados, temos uma forma muito simples disso acontecendo aqui:
Temos a variável data com uma coleção de dados com as propriedades a e b, cada uma com um valor numérico e em ordem aleatória, que seria o nosso dado bruto.
Imaginando que a problemática aqui seja ordenar essa coleção de dados com base em uma terceira propriedade (ab) a qual é o resultado da multiplicação de a com b.

Para executar o código rode no terminal: node index.js, a saída tem o seguinte resultado:

Resultado do código de exemplo.

Então aqui, temos a nossa análise de dados com JS concluída, sem dor de cabeça e de uma forma simples e rápida.
Mas e se a gente tentar fazer algo mais voltado pro mundo real e com mais dados?
Para um exemplo mais complexo eu vou utilizar uma base de dados do site Kaggle, uma comunidade para cientistas de dados onde entre outras coisas existem várias databases de todos os tipos e tamanhos para você usar nos seus projetos de estudo.
Vou utilizar a base de dados contendo informações sobre ciclistas, a City Bike Dataset. Faça o download do Dataset e coloque ele na mesma pasta do nosso projeto:

Download do dataset.
Dataset importado no projeto.

Agora, vamos começar o nosso passo a passo que já falamos anteriormente, e para guiar a gente em busca do resultado vou usar a seguinte pergunta: "Qual o horário que as pessoas mais iniciam sua corrida de bicicleta?".

Montando um rápido rascunho para nos guiar, o que vamos fazer é:

Passo a passo do que vamos codificar.

Os dois primeiros passos já estão completos (Definir a pergunta e coletar os dados), vamos agora para o tratamento desses dados.
O Tiddy.js aceita os dados no formato JSON ou um Array do JS. Como temos o dado no formato CSV vamos precisar fazer um parse desse dado, para isso vamos usar outra biblioteca: `csvtojson`. Basta adiciona-la ao projeto:

npm install csvtojson moment -S
Adicionando csvtojson e moment ao projeto.

No nosso arquivo index.js vamos importar e utilizar a lib dessa forma:

import csv from "csvtojson";

const data = await csv().fromFile(
    "/Users/user/www/tidyjs/bike_data.csv"
    );
Lembre-se de trocar o caminho do arquivo CSV para o da sua máquina.

Agora temos o nosso CSV convertido para JSON na nossa variável data, o próximo passo é carregar isso no Tiddy.JS e aplicarmos o nosso tratamento, o código vai ficar dessa forma:

import { tidy, mutate, count } from "@tidyjs/tidy";
import moment from "moment";
import csv from "csvtojson";
import { promises as fs } from "fs";
import { ChartJSNodeCanvas } from "chartjs-node-canvas";

const data = await csv().fromFile(
  "/Users/tuliocalil/projetosJs/nodejs/tidyjs/bike_data.csv"
);

const results = tidy(
  data,
  mutate({ start_hour: (d) => moment(d.starttime).minutes(0).format("LT") }),
  count("start_hour", { name: "count" }),
  arrange(desc("count"))
);

console.table(results);
Importando CSV e passando para o TiddyJS

Explicando rapidamente, nas três primeiras linhas temos a importação de algumas funções do Tidy (tidy, mutate, arrange, desc e count), a importação do moment (para trabalharmos com datas, não é a biblioteca ideal atualmente, mas o Tiddy utiliza o moment para estender algumas funcionalidades) e o csvtojson, que como já vimos, faz o parse do CSV para JSON.

Logo no final do código, onde temos a declaração da variável results, temos o Tidy entrando em ação, estamos passando o data como primeiro parâmetro (nossos dados) e em seguida usando a função mutate, que vai criar uma propriedade dentro dos objetos da coleção de dados, estamos criando o start_hour, que irá receber como valor a hora de início da corrida, desconsiderando os minutos, para isso usamos o moment, zeramos os minutos e formatamos a data no formato "LT".
Fazemos também uma contagem da nova propriedade usando a função count, que conta os valores distintos de uma determinada propriedade e registra o valor em uma nova propriedade no objeto, nesse caso a nova propriedade se chama count também.
Por fim temos a função arrage com a desc, que vai apenas ordenar nossos dados, ela é dispensável mais a frente, mas agora que queremos ver os dados antes de plota-los, vamos precisar.
A saída do nosso console.table será a seguinte:

Saída do tratamento de dados.

Com nossos dados prontos, vamos agora para uma visualização mais bonita desses dados, para isso vamos adicionar mais uma lib (na verdade, duas):

npm install chartjs-node-canvas chart.js -S
Adicionando bibliotecas para gerar gráficos.

Com as novas bibliotecas instaladas, nosso código fica assim:

import { tidy, mutate, count } from "@tidyjs/tidy";
import moment from "moment";
import csv from "csvtojson";
import { promises as fs } from "fs";
import { ChartJSNodeCanvas } from "chartjs-node-canvas";

const data = await csv().fromFile(
  "/Users/tuliocalil/projetosJs/nodejs/tidyjs/bike_data.csv"
);

const results = tidy(
  data,
  mutate({ start_hour: (d) => moment(d.starttime).minutes(0).format("LT") }),
  count("start_hour", { name: "count" })
);

const configuration = {
  type: "bar",
  data: {
    datasets: [
      {
        label: "Bikes",
        data: results,
        borderColor: "#FFA500",
        backgroundColor: "#FFCD28",
        borderWidth: 2,
      },
    ],
  },
  options: {
    parsing: {
      xAxisKey: "start_hour",
      yAxisKey: "count",
    },
  },
};

const chartJSNodeCanvas = new ChartJSNodeCanvas({
  width: 400,
  height: 400,
});

const buffer = await chartJSNodeCanvas.renderToBuffer(configuration);
await fs.writeFile("./grafico.png", buffer, "base64");
Codigo final

Basicamente o que tem de novo é que removamos a ordenação (como eu comentei anteriormente, nesse exemplo ela não é necessária), e estamos configurando a biblioteca de gráficos (ChartsJS, mas você pode usar algo mais simples também) e adicionando os nossos dados nela.
Como resultado vamos ter uma imagem sendo criada na pasta do projeto e ela vai ser igual a essa:

Gráfico gerado com base nos dados.

Finalizamos a nossa análise de dados com uma base bem grande e com dados reais.
Como eu já vinha sugerindo em alguns momentos, todas as bibliotecas usadas aqui tem versões alternativas e você não precisa se prender a uma.

Conclusão

Espero que tenha ficado claro o quanto é simples utilizar o Javascript (Node.js) para dados. Não só pensando em quão comodo é utilizar uma linguagem que você já tem costume para um desafio novo, como também aproveitar todo o ecossistema do Node.js para isso ou conhecer uma alternativa ao que você já faz em outro ecossistema.
O Node.js é conhecido além de tudo por sua performance e isso pode ser aplicado aqui também (inclusive, fica aqui um link para um video do genial Erick Wendel sobre multi-thread) além de ter uma comunidade muito grande e o gerenciador de pacote mais popular, o NPM.

Podemos somar também o uso do Typescript e teremos ainda mais poder e produtividade durante o nosso desenvolvimento e manutenção dos nossos códigos, no exemplo abaixo eu criei um tipo (apenas algumas propriedades) para o meu Dataset, o que me permite ter um IntelliSense ótimo em tempo de desenvolvimento:

O código anterior, agora com typescript.

Aqui vale ressaltar também outras bibliotecas super legais e uteis no mesmo tema:

  • NeuroJS - Uma biblioteca para criar e treinar modelos de Deep Learn.
  • OpenCV - Poderosa (e famosa) biblioteca para visão computacional.
  • TensorflowJS - Uma biblioteca para criar e treinar modelos de Deep Learn.
  • D3.js - Visualizador e manipulador de visualização de dados.
  • Sigma.js - Visualizador e manipulador de visualização de dados.

Essas são algumas poucas disponíveis e vão ajudar muito na solução dos problemas.
Outro ponto é para quem é acostumado a usar o Collab do Google, é possível também utilizar Javascript por lá.

Vale também mencionar que o Pentaho (uma ferramenta para ETL bem conhecida) também permite o uso de Javascript no seu fluxo de trabalho.

Sobre conexões com banco de dados também temos soluções super maduras como os ORMs: Sequelize, TypeORM (com a dica anterior do Typescript você terá um mapeamento incrível dos seus dados), Mongoose e vários outros. E claro, temos a possibilidade de conectar diretamente no banco.

Eu não sou /exatamente/ da área de dados, recentemente precisei estudar um pouco sobre o assunto e para todo material que eu encontrava eu pensava "Ei, o JS resolve isso de uma forma muito mais simples", então resolvi escrever sobre (a curiosidade também não me deixou enquanto eu não fosse a fundo).
Se você acha que faltou algum ponto, fique à vontade para comentar ou caso tenha ficado com dúvida também.
O código do projeto pode ser encontrado aqui.