Não terceirize a Normalização/Padronização dos Dados


layout: post permalink: /:title

title: “68.618 vezes obrigado!” image: Cover excerpt: “68.618 vezes obrigado!”


Na literatura de mineração de dados muitos autores afirmam que o pré-processamento é uma fase que ocupa 80% do tempo e que os algoritmos são as grandes estrelas com as suas inúmeras formas de descoberta de padrões, regras e associações; e que por isso detêm os 20% mais importantes no que diz respeito à mineração de dados.

Baseado em experiências empíricas acredito que o pré-processamento ocupa 90% do tempo, e que também é responsável por 95% do resultado; dentro da perspectiva da mineração de dados no qual:

Resultado = Custo Computacional  + Consistência dos Resultados + Reprodutibilidade

Onde o custo computacional é definido como:

 Custo Computacional = Custo Espacial + Custo Temporal

Dito isso, vejo que em fóruns e até mesmo palestras que devido ao grau de dificuldade de trabalhar com os dados, ocorre a famosa terceirização da normalização/padronização dos dados. Isso se dá na forma em que os algoritmos/soluções de análise de dados pegam todos os dados e simplesmente ‘fazem a mágica acontecer’ (acreditem, eu vi um ‘Sales Engineer’  de uma das top 3  ferramentas de Business Intelligence (pela Gartner) falar isso).

No entanto, em alguns pré-experimentos com MARS (Multivariate Adaptive Regression Splines) no Statistica 10 e MLPRegression no Weka observei que muitos valores das variáveis de resposta (i.e. valores para realizar o teste e/ou checagem matemática do algoritmo) estavam com números que não faziam sentido algum, e pior: não davam a reprodutibilidade necessária para exercer um simples hindcast (não confundam com backtesting).

Vejamos dois casos práticos a respeito disso.

Neste primeiro caso vejam o resultado do RBF Regressor no Weka que está abaixo:

=== Run information ===  Scheme:       weka.classifiers.functions.RBFClassifier -N 2 -R 0.01 -L 1.0E-6 -C 1 -G -A -P 1 -E 1 -S 1  Relation:     WekaExcel-weka.filters.unsupervised.attribute.Remove-R8-weka.filters.unsupervised.attribute.Remove-R1, 6-weka.filters.unsupervised.attribute.Remove-R5  Instances:    671  Attributes:   5                Var1                Var2                Var3                Var4                Paid  Test mode:    evaluate on training data  === Classifier model (full training set) ===  Output weights for different classes:  -0.658867061591664 0.7268781531574563 Unit center:  1.103191478913074 0.3187908580844808 1.339867551710916 -2.348360195617461 Output weights for different classes:  7.294836535867017 -7.294947917203681 Unit center:  0.001306958680758934 -0.001914844611731498 6.641791379162694E-4 1.0009616503748857 Scale:  0.7556789838127707 Attribute weights:  1.2177544598559824 1.0557440195728327 1.6425390340750194 3.7580013072113965 Bias weights for different classes:  -1.1716428958295801 1.171406635309079 Time taken to build model: 0.33 seconds

Até aí nada demais, basta ver qual é o teste dos coeficientes regressores e substituir os coeficientes para posteriormente realizar o cálculo, certo?

Até aí perfeito, mas tem um pequeno problema: todas as variáveis do modelo são nominais e o classificador já fez a normalização os dados. Ou seja, neste exato momento você transformou o modelo em black box, mesmo com todos os coeficientes expostos. Ou seja, a transparência do modelo foi trocada pelo fato da não normalização dos dados.

Neste segundo exemplo vamos ver o resultado de uma RBFNetwork no Weka.

=== Classifier model (full training set) ===

 Radial basis function network

(Linear regression applied to K-means clusters as basis functions):

 Linear Regression Model

 Dummy_Paid =

      -0.2146 * pCluster_0_0 +

      0.2148 * pCluster_0_1 +

      0.612

Neste caso, estou ainda com as mesmas variáveis nominais.

Uma das propriedades da RBFNetwork no Weka, é que a grosso modo o algoritmo permite a escolha do número de clusters e porteriormente implementa uma função de base radial (i.e. realiza a atribuição de valores partindo do distanciamento de um centro) para realizar a classificação.

Abaixo a descrição do algoritmo:

NAME

weka.classifiers.functions.RBFNetwork

SYNOPSIS

Class that implements a normalized Gaussian radial basisbasis function network.

It uses the k-means clustering algorithm to provide the basis functions and learns either a logistic regression (discrete class problems) or linear regression (numeric class problems) on top of that. Symmetric multivariate Gaussians are fit to the data from each cluster. If the class is nominal it uses the given number of clusters per class. It standardizes all numeric attributes to zero mean and unit variance.

OPTIONS

debug – If set to true, classifier may output additional info to the console.

ridge – Set the Ridge value for the logistic or linear regression.

maxIts – Maximum number of iterations for the logistic regression to perform. Only applied to discrete class problems.

clusteringSeed – The random seed to pass on to K-means.

minStdDev – Sets the minimum standard deviation for the clusters.

numClusters – The number of clusters for K-Means to generate.

A frase mais importante é “It standardizes all numeric attributes to zero mean and unit variance.”

Isso é, o algoritmo realiza a padronização (a re-escala) de todos os atributos numéricos dentro de um range numérico que supõe que os dados estejam em uma distribuição normal padrão que tem média zero e que a unidade variação tem como base a variância.

Sabendo isto, rodei o meu experimento com os seguintes parâmetros.

 RBFNetwork

Nesta imagem, como tinha controle do pré-processamento dos dados propositalmente coloquei a variável de decisão como a geradora dos centroides dos dois clusters. Após isso fiz uma pergunta ao Eibe Frank que é um dos desenvolvedores do Weka sobre o testes dos coeficientes do Output e obtive a seguinte resposta:

pCluster_0_0 and pCluster_0_1 are cluster membership probabilities. RBFNetwork internally uses clusters build using SimpleKMeans. They are not output, so you can’t manually reproduce the classifications generated by RBFNetwork.

Cheers, Eibe

Ou seja, se não tivesse inserido (ou mesmo a percepção do que o algoritmo fazia) a minha variável de decisão, jamais saberia como o algoritmo chegou ao resultado.

Neste caso o pré-processamento foi feito de uma maneira reprodutível, ou no mínimo rastreável o que ajudou na compreensão do modelo, e de quebra me permitiu ganhar um midset para trabalhar com problemas de função de base radial e clustering. Mais um item no cinto de utilidades do batman minerador de dados.

O grande aprendizado é que quem tem o controle do pré-processamento tem o controle do modelo, seja na velocidade de execução do algoritmo, como também exerce influência nos resultados do modelo. Então, não terceirize a normalização de dados.

 FONTES

http://stn.spotfire.com/spotfire_client_help/norm/norm_scale_between_0_and_1.htm

http://stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range