No post Full Metal BI Itch eu coloquei uma pergunta:
E se você pudesse voltar um ano? O que faria?
Colocando de outra maneira, e se fosse possível saber hoje, agora, o que vai acontecer dentro de um ano? Que diferença isso faria na sua vida? E na vida de sua empresa ou organização?
Toda Ciência que busca criar um modelo abstrato a partir da realidade tem potencial para prever o futuro. Por exemplo, se você jogar uma pedra para o alto, a Física diz quanto tempo ela vai tomar para cair na sua cabeça, com um erro bem pequeno até. Economia, que anda tão em moda, oferece modelos de resposta ao que acontece quando se atua em certas variáveis e assim por diante – Química, Biologia, Medicina, Farmácia e por aí vai.
Essa é justamente a função central de BI, na minha opinião: estudar o presente para poder estimar o futuro com alguma precisão. Essa previsão pode, então, alimentar as ações do presente, de maneira até mesmo automática, como eu mostrei na série As Soluções Clássicas.
Eu sempre falo de Data Mining, mas nunca mostro. É complicado falar em poucas linhas de um tema tão complexo, tão vasto. Por isso eu decidi fazer um post com uma visão geral de como funciona um projeto de Data Mining. Assim, hoje vamos percorrer esse caminho, do início ao fim. Quem nunca mexeu ou viu o assunto de perto, e só ouviu falar, vai poder fazer uma idéia de como funciona um projeto desses na vida real.
Quanto mais experiente e mais safo é o profissional de Data Mining, o tal do – afff – Data Scientist, mais embolado fica o processo. Com experiência vem a velocidade e a economia de movimentos, o que torna as coisas mais rápidas e fases inteiras podem sumir na cabeça dele. Por isso não se impressione se vir alguém executando apenas uma ou outra etapa, ou mudando a ordem delas, pois provavelmente ele já tem conhecimento suficiente para isso. Ele atingiu o Shuhari.
Vou explicar em poucas palavras o meu cenário, só para não ficar tudo muito etéreo. Daí vamos entrar em Data Mining, com o SEMMA e botar esse lance na rua, usando-o para justificar o nosso (meu ;-) ) salário.
Esse post nasceu com 15 linhas. De tanto eu rever e mudar, acabou como uma verdadeira Introdução Rápida a Data Mining. Na boa, se quiser pular fique à vontade. Semana que vem eu devo trazer a segunda parte do BI Morreu!, que deve ser beeeeem mais curta e muito mais divertida. (Mentira, este aqui está mais. Por outro lado, vai ter Chaves. Putz, páreo duro…)
Você foi avisado. ;-)
Senta que lá vem história!
Zabbix & Data Vault
Estou apoiando a construção de um Data Vault para arquivar os dados de vários [Zabbix][zabbix_bitly]es e, de quebra, facilitar análises sobre eles.
Anteontem eu consegui completar uma transformação PDI que faz a carga de um satélite mais complicado, que captura um histórico que existe no sistema de origem. Ainda não sei se está mesmo certo, e só ontem eu consegui identificar esse tipo de satélite no padrão DV 2.0 e por isso não vou entrar nos seus detalhes.
Aos que, como eu, morrem de véspera: acho que é um tipo status. Assim que eu tiver certeza eu posto aqui uma explicação sobre ele.
E como funciona esse sistema? Bom, o Zabbix monitora um monte de medidas, de um monte de itens. Por exemplo, ele pode acompanhar a quantidade de memória RAM disponível em um servidor. Traduzindo em zabixxês, ele registra uma métrica (quantidade) de um item (RAM) de um host (servidor.) E ele faz isso dentro de um período pré-definido, como uma vez por minuto ou uma vez por segundo.
E o Zabbix faz isso com uma enormidade de tipos de hosts (computadores, roteadores, switchs, sensores etc. etc. etc.), medindo uma infinidade de itens (porta, memória, uso de CPU, disco, tensões, fluxos blá blá blá.)
Cada medida que chega é arquivada em uma tabela chamada history
, que guarda a medida atômica. Em uma instalação de maior porte, como a na qual eu estou trabalhando, uma tabela dessas chega a acumular vários milhões de linhas por mês, com até centenas de milhares (ou mais) de novas linhas adicionadas diariamente. E são essas linhas que precisam ser arquivadas no Data Vault. Aliás, usando o jargão DV, é preciso arquivar esse histórico em um satélite.
O primeiro passo para conseguir isso foi descobrir, junto ao cliente, se ele precisa desse dado atômico, ou se contenta-se com uma agregação. Por exemplo, podemos agregar tudo, que às vezes está em segundos ou minutos, para horas. Daí cada item teria no máximo 24 pontos por dia, reduzindo em muito o volume de dados tratados.
E ele podia! Melhor ainda: o Zabbix possui uma tabela auxiliar chamada trends
que acumula essa agregação, fazendo o grosso do trabalho com muito mais eficiência. A única coisa que sobreou, então, foi ler a tabela trends
e levá-la para o satélite (que seria ligado a um item, que por sua vez tem um relacionamento com um host – ambos hubs):
Assim, o satélite Item 001
ficou os dados de cada item, o Item 003
com os nomes e o Item 002
com as coletas temporais de cada métrica. Meu trabalho foi justamente resolver o ETL desse satélite – mas esse é assunto para outro dia.
E isso é tudo que você precisa saber sobre o cenário.
Acabou!
… Só que não! Assim que eu versionei e botei o processo no ar, veio a pergunta:
Conversation with XXX on Ter 07 Mar 2017 16:19:37 BRT:
(16:19:37) XXX:
Tem pespectiva de crescimento?
Duhn… Me pegou de surpresa. Não, eu não tenho a menor idéia! Mas faz assim: deixa rodar uma semana e extrapola! Que coisa…
Claro que eu não respondi isso. Até admito que isso me passou pela cabeça, mas um segundo depois eu lembrei que a tabela guarda, justamente, histórico! Ou seja, a carga inicial do satélite Item 002
já vem com um histórico! Neste caso, desde 2016. Como possui dados agregados na hora, temos aí pelo menos uns 300 dias de crescimento, carregados de uma talagada só.
Era tentador demais para eu deixar quieto, hehe.
Extrapolando
Ao contrário do que o nome sugere, extrapolar não é dar um pulo a mais, não é extra pular.
Nem tem nada a ver com um super frio, um frio extra-Polar.
Tá-dá-dum-tssssss!!
Fingindo que nada aconteceu, vamos de novo: todo nós fazemos extrapolações, corriqueiras e diárias. Por exemplo, sempre voltamos ao mesmo restaurante porque se ele estava lá ontem, deve continuar lá hoje – extrapolamos a continuidade temporal de uma empresa para o dia seguinte a partir do fato que ela esteve lá nos últimos X dias.
Eu só tinha que fazer a mesma coisa aqui: contar o número de linhas por dia, pegar algumas diferenças entre dois dias e tirar uma média de crescimento diário. Fácil… e extremamente sem-graça.
Para que simplificar, se podemos complicar, não? ;-)
O Problema & Sua Solução
Meu cliente tem um disco rígido com 600 GB reservados para o banco de dados. Comprar disco novo é – apesar de tudo – complicado, já que é um disco especial e coisa e tal. Logo, se o disco não for o bastante para o serviço, ele precisa saber antecipadamente quando vai lotar, para poder agir a tempo de substitui-lo sem interromper o processo de ETL. É um problema clássico da área de TI chamada Capacity Planning.
- Quanto tempo de coletas diárias esse HD comporta?
- Com que velocidade ele está enchendo?
- Quando ele vai estar a 75% da capacidade?
- Quando é que eu terei mais 6 meses até ele lotar completamente?
Note que essas perguntas têm uma resposta válida apenas se as condições atuais se mantiverem inalteradas. Por exemplo, a velocidade de ocupação do HD depende que o sistema de origem continue se comportando como vem fazendo até hoje, e que o cliente não inclua mais nada no Data Vault. Mesmo assim, ainda é uma medida com alguma imprecisão – é só pensar em arquivos temporários e auto-gestão do banco de dados (um Postgres, aliás), sistema operacional etc. etc. etc.
Como esse problema é resolvido?
De maneira simples, basta medir a variação de espaço ocupado de um dia para outro, ao longo de algum tempo, e tirar uma média. Por exemplo, suponha que esta tabela mostre a evolução do espaço ocupado dia-a-dia:
Dia | Bytes Gastos |
---|---|
1 | 1000 |
2 | 1100 |
3 | 1220 |
4 | 1310 |
5 | 1460 |
… | … |
Podemos “plotar”[^1] isso. Apelando para o bom e velho LibreOffice Calc/MS Office Excel:
Isso quer dizer que do dia 1 para o dia 2 o HD teve 100 bytes gastos. Podemos fazer uma tabela:
Dia | Delta Bytes |
---|---|
1-2 | 100 |
2-3 | 120 |
3-4 | 90 |
4-5 | 150 |
… | … |
Somando tudo e dividindo por quatro, temos que cerca de 115 bytes são acrescidos a cada dia – em média. Essa é a velocidade média da ocupação do disco: 115 bytes/dia. Usando isto podemos responder as perguntas:
- Quanto tempo de coletas diárias esse HD comporta? R.: 600 GB / (115 bytes/dia) = 5.6e9 dias ~ 15.3 milhões de anos;
- Com que velocidade ele está enchendo? R.: 115 bytes/dia.
- Quando ele vai estar a 75% da capacidade? R.: 75% de 600 GB = 450 GB. 450×(1024^3)÷115 = daqui a 4.2 milhões de dias, ou 11.3 milhões de anos;
- Quando é que eu terei mais 6 meses até ele lotar completamente? R.: Esqueça, isso não vai acontecer nem durante a vida do seu tataraneto. :-)
Pegou a idéia?
Agora vamos tratar os dados que eu peguei do sistema, dentro do processo SEMMA.
SEMMA na Veia
O mundo é um lugar livre, e podemos seguir o caminho que quisermos. Se formos inteligentes, faremos o que outros já fizeram antes de nós e resultou em sucesso. Uma dessas coisas é o processo de garimpagem de dados. Existem dois mais famosos:
O primeiro é mais abrangente e engloba a parte que já fizemos, de entender o negócio e o problema. Ele foi desenvolvido por um consórcio de fornecedores e especialistas, e é bem legal.
O segundo possui essencialmente as mesmas partes, exceto as etapas de entender o problema, e foi criado pelo [SAS][sas_bitly] para suportar o Enterprise Miner, a ferramenta de DM deles. Ele é bem didático e direto e por isso vou usá-lo aqui.
Como sempre, melhor ou pior é algo flexível em BI. Métodos e ferramentas existem aos borbotões por aí e o truque é escolher aqueles que fazem o trabalho que você precisa, sem te aborrecer demais.
SEMMA significa:
- Sample
- Explore
- Modify
- Model
- Assess
Funciona assim:
- Ao invés de pegar o dataset inteiro, escolha uma amostra. Isso é importante porque precisamos reservar uma parte dos dados que estão sendo analisados para testar o resultado, ou seja, para descobrir o quanto a nossa previsão, o nosso modelo, está dentro da realidade. O post A Nuvem Negra discorre um pouco sobre a importância dessa etapa. Os dados usados na modelagem são chamados de dados de treinamento, e o conjunto restante de dados de teste;
- De vez em quando temos uma idéia clara do que aqueles dados devem representar, outras vezes não. Por via das dúvidas, explore esses dados de algumas maneiras para tentar apreender o que está acontecendo ali, ou se a sua intuição está bem calibrada. Por exemplo, plote-os ou calcule uma estatística básica (média, mediana, dispersão etc.) sobre eles;
- O mundo real é sujo, e dados do mundo real são sujos da mesma forma. Como se isso não bastasse, ainda existem aquelas situações nas quais os dados precisam ser re-alinhados, digamos assim, ou traduzidos. Basta pensar num clássico dos clássicos: uma lista de perfis de compradores, em que o gênero não vem como M ou F, mas como 0 ou 1. Mesmo que possamos usar números, é muito mais prático (e para alguns modelos, imprescindível) traduzi-los para letras. Sempre precisamos olhar os nossos dados e verificar se é preciso modificá-los de alguma forma, e como;
- Só então é que podemos partir para os finalmentes: construir um modelo. É a parte mais divertida da bagaça: passar aquela renca de linhas numa regressão polinomial e ver se o Chi-Quadrado está baixo o bastante, é rodar uma clusterização e descobrir se existem grupos óbvios ou talvez nem tanto, e assim por diante. No exemplo de hoje eu vou tentar ajustar os dados a um modelo linear, ou seja, a uma descrição dos dados que se posicionam em uma organização retilínea;
- Pronto, certo? Não! É muita inocência acreditar que só porque o modelo mostrou um alto coeficiente R e uma baixa dispersão ele está correto, menos ainda pronto. Há muita coisa que pode (e boa parte vai) dar errado na sua modelagem. Só para começar, você pode sofrer de overfitting, uma situação em que seu modelo explica bem demais os pontos que você estudou, mas muito bem mesmo!, mas falha completamente em qualquer ponto fora da amostra. Por isso precisamos avaliar a adequação do modelo à realidade. É justamente para isso que serve separar o conjunto total de dados em pelo menos duas partes, o que é feito lá na primeira etapa: se os dados são uniformes, e as partições de dados equilibradas, o modelo ajustado em na amostra vai apresentar a mesma precisão na partição restante
Se o modelo ou o particionamento não forem bons o bastante, o ajuste do modelo ao dados de teste vai ser pior que aos dados de treinamento. Se isso acontecer – se o modelo não se mostrar tão bom quanto parecia – mas ainda assim for um resultado bom o bastante para seu uso, o trabalho acabou. Se, por outro lado, o ajuste do modelo aos dados de teste ficar muito ruim, precisamos recomeçar o processo do início: rever amostragem, explorar, modificar a amostra, modelar e testar de novo. Deu certo? Fim! Ainda está ruim? Repita de novo, e de novo até chegar no resultado que você quer, ou provar que não pode ir além daquilo.
Ao trabalho!
Sample
Temos uma tabela que aumenta a cada hora. Ela tem este layout:
Coluna | Tipo |
---|---|
h_item_bk |
Bigint |
s_item_002_ldts |
timestamp |
s_item_002_rsrc |
Varchar |
s_item_002_ledts |
timestamp |
clock |
Bigint |
num |
Integer |
value_avg |
Number (16,4) |
value_max |
Number (16,4) |
value_min |
Number (16,4) |
Dela nos interessa apenas a contagem de linhas por dia. Podemos usar a coluna s_item_002_ldts
ou clock
para fazer essa contagem, já que são as que guardam o tempo de cada medida. Como a coluna LDTS é do padrão do Data Vault, vamos deixá-la de lado e ficar com clock
, que tem mais a ver com o assunto em si.
Só para constar, tanto faz a coluna que escolhermos já que ambas,
s_item_002_ldts
eclock
, são iguais. A primeira é um timestamp no formatoAAAA-MM-DD hh:mm:ss.mmm
, enquanto que a segunda é a mesma data/hora representado em formato Unix Epoch (a quantidade de segundos desde 1 de janeiro de 1970.)
Quantas linhas são capturadas por hora? A consulta SQL abaixo nos dá essa lista:
SELECT clock, SUM(1) AS qtd FROM dv.s_item_002 GROUP BY clock ORDER BY 1
O resultado é:
Clock | Qtd |
---|---|
1456801200 | 65 |
1456804800 | 68 |
1456808400 | 57 |
1456812000 | 57 |
1456815600 | 63 |
1456819200 | 53 |
1456822800 | 62 |
1456826400 | 56 |
1456830000 | 56 |
1456833600 | 50 |
1456837200 | 60 |
… | … |
Vamos converter clock
para data/hora só por curiosidade:
Data/Hora | Qtd |
---|---|
2016-03-01 00:00:00.0 | 65 |
2016-03-01 01:00:00.0 | 68 |
2016-03-01 02:00:00.0 | 57 |
2016-03-01 03:00:00.0 | 57 |
2016-03-01 04:00:00.0 | 63 |
2016-03-01 05:00:00.0 | 53 |
2016-03-01 06:00:00.0 | 62 |
2016-03-01 07:00:00.0 | 56 |
2016-03-01 08:00:00.0 | 56 |
2016-03-01 09:00:00.0 | 50 |
2016-03-01 10:00:00.0 | 60 |
… | … |
Ou seja, existe 65 linhas correspondentes a itens coletados entre a meia-noite e a uma da manhã de primeiro de março de 2016. Daí há 68 linhas na hora seguinte, e 57 logo depois e assim por diante.
O conjunto total que eu tinha para analisar possuía (neste exato instante já é maior) 8.774 linhas. É um conjunto pequeno, então eu poderia analisá-lo inteiramente, mas isso seria conceitualmente errado, e por isso eu vou escolher uma amostra.
Apenas “conceitualmente errado” porque um ajuste de reta tem muito pouco a ganhar separando o volume inteiro em datasets de treino e teste. No final das contas, para uma regressão linear, que é o modelo que eu estou buscando, o resultado acaba ficando até mais próximo da realidade incluindo todo mundo.
Como amostrar? Há diversas técnicas:
- Percentual: sorteia-se um X % de linhas do dataset original;
- Periódico: pega-se uma linha a cada X linhas;
- Particionado: quebra-se o dataset em faixas e pega-se uma quantidade de cada faixa.
Como a intenção é apenas passar pela etapa e cumprir a tabela, vou apelar para uma amostragem simples: [Reservoir Sampling][reservoir_bitly]. A vantagem dessa técnica – para mim, hehe – é que o PDI possui um passo que faz isso. Assim, eu escrevi uma transformação bem simples que lê o dataset original, faz o “sampling” e devolve um dataset de amostra.
Pronto, etapa concluída.
Explore
Hora de explorar esse dataset para ver se achamos algum comportamento ou algo que sugira uma abordagem em detrimento de outra.
Como o próprio nome sugere, essa etapa do SEMMA é voltada a examinar o conjunto de dados de várias formas, em busca de alguma pista sobre o quê informação eles guardam. Para isso vale de tudo:
- Montar uma tabela com estatísticas básicas: média, mediana, dispersão, máximo, mínimo, esperança etc.
- Plotar um gráfico simples, bi- ou tri-dimensional;
- Contagens diversas ou construções de clusters.
Qualquer coisa vale, para ser sincero. Se você já está com um palpite, pode testá-lo. Se você acha que uma determinada variável é inútil, pode buscar evidências disso. O importante é que você ganhe um “sentimento de conhecer” o dataset em questão.
E quando você não souber o que usar, use tudo que souber. Cedo ou tarde você vai passar por um momento ah-ha! e a coisa via começar a ficar mais intuitiva.
Já passei algumas vezes por situações em que, de qualquer forma que eu olhasse os dados, nada aparecia. Não tem grilo: ausência de padrão não é um erro, mas um fato. Apenas certifique-se que fez o bastante e, neste caso, mire seu processo em provar que os dados não tem correlação útil. Esse resultado vai te levar a buscar mais dados, ou a abandonar de vez o problema.
Uma vez vi um amigo comentar que trabalhou por meses com uma grande companhia de Internet para tentar analisar os dados de navegação dos usuários. No final eles concluíram que não havia nada para concluir. :-D
Qualquer ferramenta serve, mas eu vou optar pelo [Weka][weka_bitly] porque é a ferramenta de Data Mining tradicionalmente associada ao Pentaho. Existem outras que, na minha opinião, são mais adequadas ao uso em produção (como RapidMiner) ou poderosas (como o R) e oferecem mais possibilidades, mas no momento o Weka basta – poderoso e fácil de usar.
Sem transformar este post em um tutorial, vale a pena dizer só que o Weka facilita o trabalho de explorar: rode-o, selecione o módulo Explorer, clique em Open File e depois em Visualize.
Hmm… Lembram-se que nossa intenção original era achar uma “velocidade” para o crescimento do volume de dados? Essa amostra oferece uma séria ameaça a esta idéia. Notou o quadrante superior esquerdo? Ele até acomoda uma reta, mas parece mais uma corcova. Não acredito que ali exista uma exponencial… muito menos uma assíntota.
Hora de pegar outro conjunto de dados: vamos usar tudo, de uma vez – podemo, afinal, já que é pequeno.
Ô, diacho! Mesma coisa?!?
Isso quer dizer que 1) a amostra é muito boa, pois é praticamente a mesma coisa que o conjunto original e 2) o sistema exibe um comportamento de tendência a estabilidade. Lembrando que esses dados são a quantidade de dados por hora, vemos que no começo havia muita variação, e aos poucos vai se fortalecendo uma regularidade maior, com uma variabilidade menor.
Opa, descobrimos algo importante! E era isso que eu estava procurando. Agora podemos ver que o sistema está entrando em equilíbrio, e os dados do início são menos relevantes que os dados do final, que são muito mais regulares.
A consequência disso é que, se levarmos em conta TUDO, vamos acabar diluindo o comportamento atual do sistema com uma tendência que não existe mais! Logo, a nossa ação mais imediata é limar o dataset original para, vai, logo depois daquele degrau, quando o sistema ficou mais estável:
Depois de procurar um pouco descobri que esse X vermelho está, mais ou menos, perto do ponto clock
= 1474963200. Vou reaplicar a amostragem e remover tudo que vier antes dele. Também vou dividir o dataset (tirar uma amostra) em duas partes iguais. Eis o novo gráfico:
Esse gráfico foi desenhado com o GNUPlot.
Beleza! Agora sim, temos um conjunto de dados bacana.
Modify
A etapa de modificação do SEMMA contempla todo tipo de tratamento dos dados para torná-los adequados ao estudo. Ou seja, remover outliers indesejados (sim, existem outrliers desejáveis!), agregar, quebrar, normalizar, traduzir, classificar e categorizar as inúmeras variáveis, tratar nulos, brancos, erros etc. etc. etc.
O nosso caso até que é bem comportado: duas colunas, X e Y, com números inteiros.
Por outro lado, olhe de novo: é uma lista de clocks! Quero dizer, de Unix Time!
Unix Time, também chamado de POSIX time ou epoch, é um sistema para descrever instantes no tempo, definido como o número de segundos passados desde a meia-noite de 1/1/1970 (uma quinta-feira, diga-se de passagem.)
Muito prático para medir e guardar tempo, mas inadequado para estimar variação de bytes por dia. Então aqui está a nossa modificação: trocar clock por dia!
Felizmente o PDI pode nos ajudar nisso de novo: basta converter clock
para data e hora, e depois somar todos os pontos de um mesmo dia, isto é, agregar por dia. Atualizei a transformação e agora a amostra sai assim:
dia | qtd |
---|---|
25/02/2017 | 657 |
26/02/2017 | 1168 |
27/02/2017 | 730 |
28/02/2017 | 876 |
01/03/2017 | 1241 |
02/03/2017 | 730 |
03/03/2017 | 730 |
04/03/2017 | 949 |
05/03/2017 | 803 |
06/03/2017 | 730 |
… | … |
Que plotando dá:
Notou algo incomun?
Você, que aprendeu operações básicas na quarta série e funções na sétima, me diga: que operação algébrica leva uma data em um número? Ou então, se olharmos apenas para a primeira linha, que número, dividido por 657 é igual à 25/2/2017? Nenhum, não é? Claro! O tipo DATE
não serve para operações matemáticas. Então, se quisermos achar uma equação que expressa a quantidade de linhas capturadas em função do dia, precisamos converter as datas em alguma outra coisa como, por exemplo, um número de dias.
Daí eu fiz a seguinte alteração: a primeira data é 0 e daí em diante cada data é alterada para o número do dia correspondente. A tabela acima fica, então, assim:
dia | qtd |
---|---|
0 | 657 |
1 | 1168 |
2 | 730 |
3 | 876 |
4 | 1241 |
5 | 730 |
6 | 730 |
7 | 949 |
8 | 803 |
9 | 730 |
… | … |
Agora sim, podemos achar um função que leve x = {N} (x pertencente ao conjunto dos número Naturais) em y = {N}.
Atenção que a coisa agora ficou mais complicada.
Depois de todas essas alterações, o conjunto de dados está diferente do conjunto inicial. A lista que temos para trabalhar, agora, não reflete mais o comportamento do sistema. Antes, tínhamos uma amostra de linhas por hora. Escolhida aleatoriamente, uma linha qualquer representava o sistema naquele momento em que ela foi capturada.
Após converter a escala de horas para dias, precisamos fazer essa conversão sobre os dados originais. Não podemos fazer essa troca sobre a amostra!
Porquê? Por que o total de linhas capturadas num certo dia da amostra é menor que o mesmo total, naquele mesmo dia, sobre o volume inteiro!
Estando conscientes desta mudança, voltamos um passo atrás, geramos um dataset original de novo – agora convertido em dias – e só então é que poderíamos pegar uma amostra! Caso contrário, estaríamos olhando um sistema potencialmente diferente dos dados reais!
Só que o dataset, que começou com mais de oito mil pontos, caiu a 163 linhas. Se já era pequeno, agora está muito menor (uma ordem de grandeza menor, para ser mais preciso.)
Escolher uma amostra de um conjunto tão pequeno é mais que desnecessário, é perigoso, pois pode nos levar a um resultado enviesado. Só nos resta decidir entre acumular mais dados, e atrasar a análise, ou usar o dataset inteiro, e aceitar que nosso modelo estará sob risco de overfitting, entre outros.
Como este post é só uma visão geral, vamos aceitar os riscos inerentes a um dataset pequeno e seguir adiante.
Acabamos de modificar completamente nosso dataset. Podemos passar para a etapa seguinte? A rigor, não: precisaríamos retornar com esse novo conjunto de dados para a etapa de exploração e ver se algo mudou significativamente. O nosso caso é muito simples, então podemos seguir adiante sem preocupação, mas nunca tome essa decisão automaticamente, ok?
Model
YEAH!! Chegamos lá! :-D Agora é que a parte legal acontece, quando vamos realmente aplicar nossos cérebros em estudar os dados. Nosso objetivo, lembre-se, é tirar dali um modelo matemático, algo que explique o que está acontecendo e como está acontecendo. Com sorte tiramos até porque está acontecendo.
Mas vamos um passo de cada vez.
Antes de mais nada, entenda que aqui existe um pouco de chute. O exemplo de hoje é muito simples, diria até que não dá para ficar mais simples, mas raramente isso acontece. O mais comum é ter algum problema já tratado, uma combinações de problemas conhecidos, ou algo tão inédito que você talvez tenha que inventar algo novo.
Esse amigo meu, doutor em Física Nuclear, topou com um destes, numa entrevista de emprego Kobayashi Maur. O entrevistador passou um problema, com uma semana para resolver. Imagine: entrevista de emprego, prova, com prazo de uma semana para entregar. Daí você tem um grau do que é o topo da cadeia alimentar em Data Mining.[^2]
Existem classes de modelos mais ou menos aptos a cada tipo de problema. Assim, descobrir perfis de cliente sugere uso de clusters e árvores de decisão, enquanto que tendências sugerem algum tipo de regressão. Para quem está começando essa parte é o Inferno na Terra – de onde começar, raios? Como saber ao menos o que pode ser chutado como modelo??
Por isso que é imprescindível que o profissional aspirante a – arfff – Cientista de Dados (coça, coça) faça um curso de Estatística básica e, preferencialmente, um curso de Data Mining mesmo. O curso de Estatística serve para dar traquejo matemático, mas o que vai agregar valor é o curso de Data Mining, que é onde se aprende quais modelos existem, e como eles podem ser usados, em que situação etc.
Certos tipos de profissionais, como físicos e engenheiros, tem uma aptidão natural para Data Mining, já que muito do que se estuda nessas faculdades é criar e resolver modelos. Entretanto, nada libera ninguém de um tempo de trabalho na área até “pegar o jeito”, claro. Experiência conta muito!
Ok, agora vamos ao nosso caso. Sabemos – da etapa de exploração dos dados – que o sistema de origem dos dados está “em regime”, ou seja, está com um comportamento regular. Houve uma zona de ajustes, no início, quando a quantidade de linhas capturadas por hora variou bastante. Hoje isso não acontece mais e o volume de dados entrantes é praticamente constante.
Isso já é um modelo! O volume de dados novos amanhã será igual ao de hoje. Ou seja, velocidade constante de crescimento. Que velocidade? Podemos pegar o último ponto e repetir, por exemplo, ou pegar uma média de todos para dar um chute mais “educado”.
Quem estudou Cálculo I e Cálculo Numérico (ou fez alguma matéria de laboratório de Física I), conhece uma forma simples de avaliar comportamentos regulares: plotar os pontos em um gŕafico log ou log-log. Se nosso sistema tiver um comportamento linear próximo à constante, uma escala muito grande (10x) ou um gráfico semi-log vai mostrar os pontos alinhados muito perto de uma linha horizontal. Vejamos:
Primeiro: nossa hipótese foi comprovada, o sistema possui um comportamento próximo à constante ou, no mínimo, linear. Isso é mais que suficiente para consolidar o modelo. Só por via das dúvidas, vamos fazer a coisa com um pouco mais de Matemática, mas antes, cabe outra observação: notou os dois outliers? São o primeiro e último pontos do dataset. Devemos fazer algo?
Outliers, em quantidade ou deslocamento suficientes podem afetar intensamente o resultado do modelo, logo devemos tentar removê-los sempre que tivermos uma certeza boa de representarem um estado incorreto do sistema, ou de frequência desprezível (i.é., raro, improvável.) O importante é saber se removê-los vai melhorar o modelo ou piorá-lo, sempre.
Pensemos um pouco: porque estão ali? Porque são justamente o primeiro e o segudo ponto?
Uma hipótese razoável é que não representam o dia inteiro e por isso não correspondem ao comportamento regular do sistema. Se isso for verdade, podemos removê-los.
Ela se sustenta?
- O último ponto representa o estado do sistema quando o ETL rodou pela primeira vez, durante o dia. Logo, sim, para o último ponto sustenta-se, sim. Podemos removê-lo;
- O primeiro ponto representa um corte no dataset, bem no
clock
igual a 1474963200. Isso corresponde à data/hora2016-09-27 05:00:00
. Em outras palavras, o dataset começa no dia 27/9/2016, mas com dados apenas a partir das cinco horas da manhã! Tudo entre a meia-noite e as cinco foi descartado! Então não é um dia completo, e a hipótese, de novo, mostra-se correta. Por isso eliminamos também este ponto.
Note que, se tivéssemos retornado à etapa de exploração no final da etapa de modificação, já teríamos feito todas essas observações.
Beleza, então já sabemos que o sistema apresenta um comportamento de uma reta ao longo do tempo. Em Estatística existe uma técnica chamada Regressão Linear, que descobre modelos de retas a partir de observações. É uma idéia simples: traçar uma reta (= calcular o coeficiente de inclinação a e a intersecção com o eixo X, b) entre os pontos medidos, de tal forma que ela (a reta) fique à menor distância possível de todos os pontos, simultaneamente.
Dito ao contrário, uma regressão linear descobre o valor de a e b da equação f(x) = a.x + b
que minimiza a soma de todas as distâncias de f(x) a cada ponto medido.
Traduzindo, e olhando a figura anterior: queremos achar a e b tais que a soma de todos os ds seja a menor possível. Pronto, acabou a teoria de regressão linear. Se quiser saber mais vá atrás deste link.
O LibreOffice e o Excel (e o Weka, e o RapidMiner e o R e o…) fazem isso. Para mostrar como, eu vou usar momentaneamente um conjunto de dados artificial, diferente do nosso problema, ok? Só para deixar mais claro como tudo funciona.
Primeiro, clique com o botão direito do mouse sobre um dos pontos do gráfico e escolha a opção Trend Line, conforme mostra a figura:
Entre alguns parâmetros, como o nome da função e quais resultados você quer ver. Na imagem abaixo você vê que eu coloquei f(t) como nome da função e pedi para ser exibido a função em si e o coeficiente de relacionamento (R^2):
Quando você dá Ok no diálogo acima, o Calc sumperimpõe a reta encontrada sobre seus pontos. Eu mexi um pouco mais e fiz com que ele mostrasse não apenas a reta sobre os pontos já medidos, mas também coloquei os pontos de cinco dias seguintes, extrapolando o crescimento do volume de dados:
Ficou claro? É assim, aliás, que vamos usar o modelo.
Aplicando essa técnica ao dataset sem os outliers, temos:
![ Modelo de progressão do volume de linhas coletadas dia-a-dia. ][Figura 14]
Show! :-) A regressão linear deu o seguinte:
- Reta:
f(x) = 0,4334.x + 1700
- Coeficiente de correlação ao quadrado:
R^2 = 0,39
A interpretação desse modelo é o seguinte:
- A cada dia, o sistema incorpora um número de linhas igual a 0,4334 x dias, mais 1700;
- Esse relacionamento entre o dia e o volume de dados não é dos melhores, já que R^2 está distante de 1.
O R^2 é um indicador de “qualidade” do ajuste. Quanto mais perto de 1, mais ajustada é a reta que encontramos, e quanto mais perto de zero, pior é o ajuste. Como o R^2 do nosso caso está mais perto de zero do que de um, somos levados a concluir que o ajuste da reta não ficou tão bom quanto possível. Isso não significa que o Calc errou, ou mesmo que podemos melhorar nosso ajuste, mas antes implica que há uma dispersão entre os dados que torna questionável o resultado da nossa análise.
Assess
A última parte do SEMMA diz respeito a testar o modelo em relação à realidade. Como usamos o dataset completo para construir o modelo, temos duas opções para fazer essa avaliação de qualidade:
- Deixamos o sistema acumular pontos por mais algum tempo, como uma semana ou um mês, e usamos esses novos valores para testar o modelo;
- Voltamos atrás, dividimos o nosso (já exíguo) dataset em amostra de treinamento e amostra de teste e refazemos a regressão linear.
Em qualquer um dos dois casos, a medida de sucesso é o quanto o modelo acerto em relação à realidade. Há várias maneiras de fazer isso, que depende inclusive do modelo usado. Este caso, por exemplo, mostra como avaliar a qualidade do modelo em uma regressão múltipla (coeficientes lineares, várias variáveis.)
O nosso caso é muito simples, insisto, mas não quero deixar essa seção sem nada. Então vamos dividir o dataset em dois, regredir o primeiro e ver como a extrapolação casa com o segundo.
Primeiro, separei aquelas 161 (163 – 2 outliers) linhas de dados em dois conjuntos, um com 80% (128 linhas) para treinamento, e outro com 20%, ou 33 linhas, para teste.
Primeiro, eis o resultado da regressão:
Interessantemente o bastante, o R^2 é maior neste conjunto que no conjunto total, o que torna este modelo melhor neste dataset que o primeiro, para todos os pontos. Isso, e o valor de a quase o dobro do primeiro modelo, sugerem que talvez exista algum outro comportamento embutido aqui, sutil o bastante para não aparecer em um simples plot. Se bobear, eu acertei um ponto de inflexão sem querer. Vixe.
Usando essa equação eu montei um segundo gráfico, no qual aparecem os 20% de pontos restantes, juntos com duas novas séries de pontos: em vermelho/diamante os pontos calculados a partir do modelo, e em nabla (triângulo invertido, uma letra grega) verde, a diferença entre o valor sugerido pelo modelo, para aquele dia, e o valor efetivamente medido. Veja:
E aí está: o erro, nabla verde, segue crescendo lentamente, mas sem dúvida nenhuma crescendo.
Respostas, Afinal!
Então nosso estudo, nossa garimpagem, produziu o seguinte resultado: (vou usar o primeiro modelo, só por gosto)
O banco de dados cresce a uma taxa de
f(x) = 0,4334.x + 1700
linhas por dia.
Mas quanto representa isso em bytes? Afinal, o espaço em disco é medido em GB, não em linhas – ao menos não diretamente.
Eu rodei algumas consultas no Postgres e descobri que, a tabela inteira carregada só com esses dados, dava uma média de 120 bytes por linha. O que faz sentido, se lembrarmos do layout desta tabela:
Coluna | Tipo | Tamanho |
---|---|---|
h_item_bk | Bigint | 8 |
s_item_002_ldts | timestamp | 8 |
s_item_002_rsrc | Varchar | 64 |
s_item_002_ledts | timestamp | 8 |
clock | Bigint | 8 |
num | Integer | 4 |
value_avg | Number (16,4) | 20 |
value_max | Number (16,4) | 20 |
value_min | Number (16,4) | 20 |
O total dá 160, mas dos 64 bytes possíveis para o VARCHAR apenas 8, “ZABBIX000”, são usados. Somando um para o fim da string, o total cai para 105 bytes. Um pouco de overhead explica a média em 120 bytes, o que não é de todo inaceitável. Logo, multiplicamos a equação inteira por 120 e temos um modelo em bytes. Ah, e mais um detalhe que eu não havia contado: estamos coletando dados de 10 Zabbixes, logo o modelo final precisa ser multiplicado por dez, também.
Portanto nosso modelo deve ser:
O espaço em disco ocupado pela tabela cresce a uma taxa de
f(x) = 520.x + 2040000
bytes por dia.
Não se esqueça que x = 0 é 27/9/2016 e tudo é medido a partir daí.
Pronto! Podemos FINALMENTE responder as perguntas com algum critério:
Quanto tempo de coletas diárias esse HD comporta?
Se ele tem 600GB de espaço, e mais nada acontecer ou for acrescentado:
600 GB = 520.x + 2040000 600 . 1024^3 = 520x + 2040000 520x = 644245094400 - 2040000 x = 1.238.928.951 dias, aprox. = 3.394.325 de anos, aprox.
Bom, da primeira vez eu estava de brincadeira, mas agora estamos bem mais embasados: qualquer que seja o erro do nosso cálculo, ainda tem muuuuuuuuito tempo até encher isso tudo. Para mim, passou de 10 anos é infinito.
Com que velocidade ele está enchendo?
Basta resolver a equação para um dia:
f(x) = 520.x + 2040000 f(1) = 520.1 + 2040000 = 2.040.520 bytes/dia = 1.993 KB/dia = 1,9 MB/dia = 0,002 GB/dia
Eu fui dividindo por 1024, no caso de você estar se perguntando.
Quando ele vai estar a 75% da capacidade?
Em 0,75 * 3,3 milhões de anos, ou 2,4 milhões de anos, aproximadamente. :-P
Quando é que eu terei mais 6 meses até ele lotar completamente?
Irrelevante, concordam?
Conclusão
Este post começou como o relato de um exercício que eu fiz, em cinco minutos, para tranquilizar os donos dos servidores de Data Vault, dizendo que não estávamos capturando tanta coisa assim, afinal. Era quarta-feira, eu ia escrever o post da semana e pensei, porque não? Eu estava postando muita coisa ousada ultimamente, e seria um post divertido de escrever (ainda que não tanto de ler.)
Mas, meus amigos e amigas, caramba!… Estou escrevendo há três dias!
Francamente, acho que valeu a pena. Até porque, que coisa doida, ontem apareceu este comentário no post do A Nuvem Negra, feito pelo Rafael:
(…)
Já que, como você diz, BI não existe (risos), por mais que a gente estude e trabalhe com, ficamos na dúvida sobre o que é ou não é BI. Olhar Business Intelligence como ciência pura me fez pensar o seguinte: BI e Ciência de Dados seriam a mesma coisa? Fico com a impressão de que Ciência de Dados está sendo vendida no Brasil mais como um chavão e relacionado especificamente com Big Data.
E sobre testar o que foi aprendido com o passado, isso se daria em ambiente de teste ou de produção?
(…)
Passem lá para olhá-lo, foi muito inteligente e acho que agrega muito lê-lo.
Bom, o que eu posso dizer? Eu acabei respondendo as perguntas dele, ainda que meio indiretamente. Se não, vejamos:
- Ciência de Dados e BI são a mesma coisa? Resposta: não, Rafael. Se há alguma equivalência entre Ciência de Dados, um termo do qual eu não gosto, e alguma coisa, eu diria que Data Mining é essa alguma coisa. Juro para você, meu caro, quando você postou, eu já tinha escrito isso (está lá no começo, procure):
“Por isso que é imprescindível que o profissional aspirante a – arfff – Cientista de Dados (coça, coça) faça um curso de Estatística básica(…)”
Ou seja, para mim Data Science é o jargão da vez para Data Mining, assim como Data Discovery foi para OLAP.
- E como testar o que aprendemos com o passado? Concorda comigo que foi exatamente essa pergunta que eu acabei respondendo hoje? O tal “aprender” pode ser entendido como “construir um modelo”. Levamos esse modelo “para produção” de diversas formas. Hoje eu mostrei como planejar a capacidade do seu ambiente usando Data Mining. No exemplo de hoje, levar o modelo para produção equivale a saber que tamanho de disco precisamos para aguentar até a próxima troca de hardware. Em outros casos, levar para produção pode ser programar o caixa eletrônico para mostrar uma oferta de crédito sempre que o cliente A ou B se registrar. Pode ser planejar uma plantação de eucaliptos para produção de papel, que só vai acontecer daqui a uma década. Pode ser construir um algoritmo de controle da injeção eletrônica em função de inúmeros fatores. Pode ser um monte de coisas!
Esse, aliás, é um bom tema para um post. Estou vendo outra série surgindo – explicando Data Mining ou, afff, Data Science. :-D
O nome original deste post era Prevendo o Futuro. Eu não tive como não alterá-lo para Introdução à Data Mining depois de tudo, e ainda mais depois do comentário do Rafael.
Aliás, Rafael, muito obrigado pelo comentário. Prometo que vou postar mais coisas daquele naipe. Aguarde o Bola Quadrada, hehe!
Então é isso.
Acabou? Sério? ALELUIA!
A-LE-LU-IA!!!!!
:-)
Parabéns por chegarem até aqui, e obrigado pela companhia.
Até a próxima. ;-)