Redes Neurais Profundas (Parte IV). Criação, treinamento e teste de um modelo de rede neural
Conteúdo
- Introdução
- 1. Uma breve descrição dos recursos do pacote
- 1.1. Funções de inicialização dos neurônios
- 1.2. Funções de ativação dos neurônios
- 1.3. Métodos de treinamento
- 1.4. Métodos de regulação e estabilização
- 1.5. Métodos e parâmetros de treinamento de um RBM
- 1.6. Métodos e parâmetros de treinamento da DNN
- 2. Testando a qualidade do trabalho de uma DNN dependendo dos parâmetros usados
- 2.1. Experimentos
- 2.1.1. Dados de entrada (preparação)
- 2.1.2. Modelo básico de comparação
- 2.1.3. Estrutura de uma DNN
- 2.1.4. Variantes de treinamento
- 2.2. Análise de resultados
- Conclusão
- Aplicação
Introdução
Principais direções de estudo e aplicação
Atualmente, existem dois fluxos principais no estudo e aplicação de redes neurais profundas. Eles diferem na abordagem da inicialização dos pesos dos neurônios em camadas ocultas.
Abordagem 1. As redes neurais são muito sensíveis ao método de inicialização de neurônios em camadas ocultas, especialmente se o número de camadas ocultas aumentar (maior que 3). O professor G.Hynton foi o primeiro a tentar e resolver esse problema. A ideia por trás de sua abordagem foi iniciar os pesos dos neurônios em camadas ocultas com os pesos obtidos durante o treinamento não supervisionado das redes neurais auto-associativas constituídas por RBM (máquina de Boltzmann restrita) ou AE (autoencoder). Esses RBMs empilhados (SRBM) e AE empilhados (SAE) são treinados com uma grande variedade de dados não-rotulados. O objetivo desse treinamento é destacar estruturas ocultas (representações, imagens) e relacionamentos nos dados. A inicialização de neurônios com pesos MLP, obtidos durante o pré-treinamento, coloca o MLP ao espaço de soluções muito próximo ao ótimo. Isso permite diminuir o número de dados rotulados e as épocas durante o seguinte ajuste fino (treinamento) do MLP. Estas são vantagens extremamente importantes para muitas esferas de aplicação prática, especialmente ao processar muitos dados.
Abordagem 2: Outro grupo de cientistas liderados por Yoshua Benjio criou métodos específicos de inicialização de neurônios ocultos, funções específicas de ativação, métodos de estabilização e treinamento. O sucesso desta direção está relacionada com um extenso desenvolvimento de redes neurais convolutivas profundas e redes neuronais recorrentes (DCNN, RNN). Tais redes neurais apresentaram alta eficiência no reconhecimento de imagens, análise e classificação de textos, juntamente com a tradução do discurso falado de um idioma para outro. A ideias e métodos desenvolvidos para essas redes neurais também começaram a ser usadas para a MLP.
Atualmente, ambas abordagens são usadas ativamente. Deve-se notar que com quase os mesmos resultados, as redes neurais com pré-treinamento exigem menos recursos computacionais e menos amostras para treinamento. Esta é uma vantagem importante. Eu pessoalmente sou a favor das redes neurais profundas com pré-treinamento. Eu acredito que o futuro pertence à aprendizagem não supervisionada.
Pacotes em R que permitem desenvolver e usar DNN
R possui uma série de pacotes para criar e usar uma DNN com um nível diferente de complexidade e conjunto de recursos.
Pacotes que permitem criar, treinar e testar um DNN com pré-treinamento:
- deepnet é um pacote simples que não possui muitas configurações e parâmetros. Permite criar ambas as redes neurais SAE com pré-treinamento e SRBM. No artigo anterior nós consideramos uma implementação prática de Experts usando este pacote. O uso de RBM para pré-treinamento produz resultados menos estáveis. Este pacote é adequado para o primeiro encontro com este tema e sobre as peculiaridades de tais redes. Com a abordagem certa, ela pode ser usada em um Expert. RcppDL é uma versão deste pacote ligeiramente menor em С++.
- darch v.0.12 é um pacote complexo e flexível que tem muitos parâmetros e configurações. As configurações recomendadas são definidas como padrão. Este pacote permite criar e configurar uma rede neural de qualquer complexidade e configuração. Ela utiliza a SRBM para pré-treinamento. Este pacote é para usuários avançados. Nós vamos discutir os seus recursos em detalhes mais tarde.
Abaixo estão os pacotes que permitem criar, treinar e testar uma DNN sem pré-treinamento:
- H2O é um pacote para processamento de dados grandes (>1M de linhas e >1K de colunas). A rede neural profunda utilizada nela possui um sistema de regularização desenvolvido. Suas capacidades são excessivas para o nosso campo, mas isso não deve nos parar de usá-lo.
- mxnet permite criar não só uma MLP, mas também redes recorrentes complexas, por convolução e LSTM. Este pacote tem uma API para vários idiomas, incluindo R e Python. A filosofia do pacote é diferente das listadas acima. Isso ocorre porque os desenvolvedores escreveram pacotes principalmente para Python. O pacote mxnet para R é mais leve e possuindo menos recursos do que o pacote para Python. Isso não faz este pacote pior.
O tema das redes profundas e recorrentes está bem desenvolvido no ambiente Python. Existem muitos pacotes interessantes para a construção de redes neurais desse tipo que a R não possui. Estes são pacotes R que permitem executar programas/módulos escritos em Python:
- PythonInR e reticulate são dois pacotes que permitem execução de qualquer código Python em R. Para isso, você precisa ter o Python 2/3 instalado no seu computador.
- kerasr é uma interface R para uma biblioteca popular de aprendizagem profunda - keras.
- tensorflow é um pacote que fornece acesso à API TensorFow completa no ambiente R.
Recentemente, a Microsoft publicou a biblioteca cntk v.2.1 (Computational Network Toolkit) no GitHub. Ela pode ser usada como backend em comparação com Keras. Recomenda-se testá-lo em nossos problemas.
Yandex está se mantendo - a sua própria biblioteca O CatBoost está disponível em código aberto. Esta biblioteca pode ser usada para treinamento de modelos com dados de diferentes tipos. Isso inclui dados difíceis de apresentar como números, por exemplo, tipos de nuvens e tipos de mercadorias. O código-fonte, documentação, benchmarks e ferramentas necessárias já foram publicadas no GitHub com a licença Apache 2.0. Apesar de não serem redes neurais, mas árvores melhoradas, é aconselhável testar o algoritmo, especialmente porque contém a API da R.
1. Uma breve descrição dos recursos do pacote
O pacote darch ver. 0.12.0 fornece uma ampla gama de funcionalidades, permitindo que você não apenas crie e treine um modelo, mas faça o que quiser para suas necessidades e preferências. Mudanças significativas foram introduzidas na versão do pacote (0.10.0), considerado no artigo anterior. Foram adicionadas novas funções de ativação, inicialização e estabilização. A novidade mais notável é que tudo foi trazido para uma única função darch(), que é um construtor ao mesmo tempo. As placas gráficas são suportadas. Após o treinamento, a função retorna um objeto da classe DArch. A estrutura do objeto é apresentada na Fig. 1. As funções predict() e darchTest() retornam uma previsão sobre os novos dados ou métricas de classificação.
Fig.1. Estrutura do objeto DArch
Todos os parâmetros têm valores padrão. Esses valores geralmente não são ótimos. Todos esses parâmetros podem ser divididos em três grupos - geral, para RBM e para NN. Nós vamos considerar alguns deles em detalhes mais tarde.
Funções | Tipos |
---|---|
Funções de inicialização |
|
Funções de ativação |
|
Funções de treinamento |
|
Nível de treinamento |
|
Funções de estabilização |
|
Momentum |
|
Condições de parada |
|
Uma rede neural profunda é composta por n RBM (n = camadas -1) conectadas em uma rede auto-associativa (SRBM) e as redes neurais reais MLP com várias camadas. O treinamento em camada da RBM é um treinamento não supervisionado em dados não-rotulados. O ajuste fino da rede neural requer supervisão e é realizado em dados rotulados.
A divisão desses estágios de treinamento com parâmetros nos dá a oportunidade de usar dados de diferentes volumes (não uma estrutura diferente!!) e obter vários modelos ajustados com base em um pré-treinamento. Se os dados para pré-treinamento e ajuste fino forem iguais, o treinamento pode ser realizado de uma só vez sem dividi-lo em duas etapas. O pré-treinamento pode ser ignorado (rbm.numEpochs = 0; darch.numEpochs = 10)). Nesse caso, você pode usar apenas uma rede neural de várias camadas ou treinar apenas a RBM (rbm.numEpochs = 10; darch.numEpochs = 0). Você ainda terá acesso a todos os parâmetros internos.
A rede neural treinada pode ser treinada em novos dados quantas vezes for necessário. Isso só é possível com um número limitado de modelos. O diagrama estrutural de uma rede neural profunda inicializada por máquinas de Boltzmann complexas e restritas (DNRBM) é exibido na Fig.2.
Fig.2. Diagrama estrutural de DNSRBM
1.1. Funções de inicialização dos neurônios
Existem duas funções principais de inicialização de neurônios no pacote.
- generateWeightsUniform() usa a função runif(n, min, max), sendo implementada da seguinte forma:
> generateWeightsUniform function (numUnits1, numUnits2, weights.min = getParameter(".weights.min", -0.1, ...), weights.max = getParameter(".weights.max", 0.1, ...), ...) { matrix(runif(numUnits1 * numUnits2, weights.min, weights.max), nrow = numUnits1, ncol = numUnits2) } <environment: namespace:darch>
numUnits1 é o número de neurônios na camada anterior e numUnits2 é o número de neurônios na camada atual.
- generateWeightsNormal()usa a função rnorm(n, mean, sd) sendo implementada no pacote da seguinte forma:
> generateWeightsNormal function (numUnits1, numUnits2, weights.mean = getParameter(".weights.mean", 0, ...), weights.sd = getParameter(".weights.sd", 0.01, ...), ...) { matrix(rnorm(numUnits1 * numUnits2, weights.mean, weights.sd), nrow = numUnits1, ncol = numUnits2) } <environment: namespace:darch>
Outras quatro funções estão usando essas duas funções, mas definem min, max, média e sd com funções específicas. Você pode estudá-las se você inserir o nome da função sem colchetes no terminal.
1.2. Funções de ativação dos neurônios
Além das funções de ativação padrão, o pacote sugere uma ampla gama de novas funções. Aqui estão algumas delas:
x <- seq(-5, 5, 0.1) par(mfrow = c(2,3)) plot(x, y = 1/(1 + exp(-x)), t = "l", main = "sigmoid") abline(v = 0, col = 2) plot(x, y = tanh(x), t = "l", main = "tanh") abline(v = 0, h = 0, col = 2) plot(x, y = log(1 + exp(x)), t = "l", main = "softplus"); abline(v = 0, col = 2) plot(x, y = ifelse(x > 0, x ,exp(x) - 1), t = "l", main = "ELU") abline(h = 0, v = 0, col = 2) plot(x, y = ifelse(x > 0, x , 0), t = "l", main = "ReLU") abline(h = 0, v = 0, col = 2) par(mfrow = c(1,1))
Fig.3. Funções de ativação dos neurônios
Vamos considerar a função de ativação maxout separadamente. Esta função vem de redes por convolução. A camada oculta da rede neural é dividida por módulos do tamanho da agregação (poolSize). O número de neurônios na camada oculta deve ser divisível pelo tamanho da agregação (pool). Para o treinamento, um neurônio com uma ativação máxima é selecionado da pool e enviado para a entrada. A função de ativação dos neurônios na pool é definida separadamente. Em palavras simples, esta é uma camada dupla (convolução + maxpooling) com capacidades limitadas no passo de filtração. De acordo com várias publicações, ela produz bons resultados em conjunto com dropout. Fig. 4. É exibido esquematicamente uma camada oculta com 8 neurônios e dois tamanhos da pool
Fig.4. A função de ativação maxout
1.3. Métodos de treinamento
Infelizmente, existem apenas dois métodos de treinamento no pacote - backpropagation e rprop da versão básica e melhorada com atualização do peso durante a backpropagation e sem ela. Existe também a possibilidade de alterar o nível de treinamento com a ajuda do multiplicador bp.learnRateScale..
1.4. Métodos de regulação e estabilização
- dropout é uma técnica de eliminação (método de regularização) de uma parte dos neurônios da camada oculta durante o treinamento. Os neurônios são zerados em uma ordem aleatória. O número relativo de neurônios a serem descartados é definido pelo parâmetro darch.dropout. O nível de regularização em cada camada oculta pode ser diferente. A máscara de regularização pode ser gerada para cada lote ou para cada época.
- dropconnect desliga as conexões entre uma parte dos neurônios da camada atual e os neurônios da camada anterior. As conexões são cortadas em uma ordem aleatória. O número relativo de conexões a serem cortadas é definido pelo mesmo parâmetro darch.dropout (geralmente não superior a 0.5). De acordo com algumas publicações, o dropconnect exibe melhores resultados do que o método de regularização (dropout).
- dither é uma maneira de evitar um retreinamento através da redução (dithering) dos dados de entrada.
- weightDecay o peso de cada neurônio será multiplicado por (1 — weightDecay)antes da atualização.
- normalizeWeights é uma maneira de normalizar um vetor de entrada de pesos de neurônios com uma possível limitação acima (norma L2)
Os três primeiros métodos são usados apenas de maneira separada.
1.5. Métodos e parâmetros de treinamento de um RBM
Há duas maneiras de treinar uma SRBM. Qualquer RBM é treinada uma a uma durante a rbm.numEpochs ou cada RBM é treinada em uma única época ao mesmo tempo. A escolha de um desses métodos é feita pelo parâmetro rbm.consecutive: TRUE ou padrão é o primeiro método e FALSE é o segundo método. Fig.5 apresenta um esquema de treinamento em duas variantes. O rbm.lastLayer pode ser usado para especificar a camada de SRBM em que o pré-treinamento deve ser interrompido. Se 0, todas as camadas devem ser treinadas e se (-1) a camada superior é para deixar sem treino. Isso faz sentido, já que a camada superior precisa ser treinada separadamente e leva muito mais tempo. Outros parâmetros não precisam de explicações adicionais.
Fig.5. Dois métodos de treinamento de uma SRBM
1.6. Métodos e parâmetros de treinamento da DNN
Uma DNN pode ser treinada de duas maneiras - com pré-treinamento e sem ele. Os parâmetros utilizados nestes métodos são totalmente diferentes. Por exemplo, não é necessário usar métodos específicos de inicialização e regularização no treinamento com pré-treinamento. De fato, usar esses métodos pode piorar o resultado. A razão por trás disso é que, após um pré-treinamento, os pesos dos neurônios nas camadas ocultas serão colocados na área próxima aos valores ótimos e eles precisarão apenas de uma pequena afinação fina. Para obter o mesmo resultado no treinamento sem pré-treinamento, todos os métodos disponíveis de inicialização e regularização terão de ser utilizados. Geralmente, o treinamento de uma rede neural dessa maneira demora mais.
Então, vamos nos concentrar no treinamento com pré-treinamento. Normalmente, ele acontece em duas etapas.
- Treinando a SRBM em um grande conjunto de dados não gravados. Os parâmetros de pré-treinamento são definidos separadamente. Como resultado, nós temos uma rede neural iniciada por pesos da SRBM. Em seguida, a camada superior da rede neural é treinada com dados rotulados com seus próprios parâmetros de treinamento. Desta forma, nós temos uma rede neural com uma camada superior treinada e pesos iniciados nas camadas inferiores. Salve-o como um objeto independente para uso posterior.
- Na segunda etapa, nós usaremos algumas amostras rotuladas, baixo nível de treinamento e um pequeno número de épocas de treinamento para todas as camadas da rede neural. Este é um ajuste fino da rede. A rede neural é treinada.
A possibilidade de divisão de estágios de pré-treinamento, ajuste fino e treinamentos adicionais oferece uma flexibilidade incrível na criação de algoritmos de treinamento não só para uma DNN, mas para treinamento de comitês de DNN. Fig.6. representa várias variantes de treinamento de DNN e comitês de DNN.
- Variante а. Salve a DNN em todas as épocas durante o ajuste fino. Desta forma, nós teremos um número de DNN com um grau de treinamento diferente. Mais tarde, cada uma dessas redes neurais pode ser usada separadamente ou como parte de um comitê. A desvantagem deste cenário é que todos as DNN são treinadas nos mesmos dados, pois todos elas tinham os mesmos parâmetros de treinamento.
- Variante b. Faça o ajuste fino da DNN iniciada em paralelo com diferentes conjuntos de dados (janela deslizante, janela em crescimento, etc.) e diferentes parâmetros. Como resultado, nós teremos uma DNN que produzirá previsões menos correlacionadas do que as variantes a.
- Faça o ajuste fino da variante c na DNN iniciada sequencialmente com diferentes conjuntos de dados e diferentes parâmetros. Salve os modelos intermediários. Isto é o que anteriormente nós chamamos de treinamento adicional. Isso pode ser executado sempre que há dados novos suficientes.
Fig.6. Variantes de treinamento da DNN
2. Testando a qualidade do trabalho de uma DNN, dependendo dos parâmetros utilizados.
2.1. Experimentos
2.1.1. Dados de entrada (preparação)
Nós usaremos os dados e funções da parte anterior do artigo (1, 2, 3). Lá foram discutidos em detalhe várias variantes da preparação preliminar de dados. Vou mencionar brevemente as etapas de preparação preliminar que nós vamos realizar. OHLCV é o dado inicial, o mesmo que antes. Os dados de entrada são filtros digitais e os dados de saída são o ZigZag. As funções e a imagem do espaço de trabalho Cotir.RData podem ser usadas.
Os estágios de preparação de dados para realizar serão reunidos em funções separadas:
- PrepareData() — cria o DataSet inicial e remove os NA;
- SplitData() — divide o conjunto de dados iniciais nos subconjuntos de pré-treinamento, train, val, test;
- CappingData() — identifica e imputa os outliers em todos os subconjuntos.
Para salvar o espaço no artigo, eu não vou trazer a lista dessas funções aqui. Elas podem ser baixadas do GitHub já que elas foram consideradas em detalhes nos artigos anteriores. Nós vamos analisar os resultados mais tarde. Nós não vamos discutir todos os métodos de transformação de dados durante o processamento preliminar. Muitos deles são bem conhecidos e amplamente utilizados. Nós usaremos um método menos conhecido de discretização (supervisionado e não supervisionado). No segundo artigo nós consideramos dois pacotes de discretização supervisionada (discretization e smbinning). Eles contêm diferentes algoritmos de discretização.
Nós examinaremos os diferentes métodos de dividir variáveis contínuas em bins e as formas de usar essas variáveis discretizadas em modelos.
O que é binning?
Binning é um termo usado na modelagem de pontuação. Ela é conhecida como discretização na aprendizagem por máquinas. Este é um processo de transformar uma variável contínua em um número finito de intervalos (caixas). Isso ajuda a entender sua distribuição e relacionamento com a variável objetivo binária. Os bins criados neste processo podem se tornar características da característica preditiva para uso em modelos.
Por que o binning?
Apesar de algumas resalvas sobre o binning, ele possui vantagens significativas.
- Ele permite incluir os dados ausentes (NA) e outros cálculos específicos (divisão por zero, por exemplo) no modelo.
- Ele controla ou mitiga o impacto dos outliers no modelo.
- Ele resolve o problema de diferentes escalas em preditores, tornando os coeficientes ponderados comparáveis no modelo final.
Discretização não supervisionada
A discretização não supervisionada divide uma função contínua em bins sem levar em conta outras informações. Esta divisão tem duas opções. Elas são bins de mesmo comprimento e bins de mesma frequência.
Opção |
Alvo |
Exemplo |
Desvantagem |
---|---|---|---|
Bins de mesmo comprimento |
Comprensão da distribuição da variável |
Histograma clássico com bunkers de mesmo comprimento, que pode ser calculado usando regras diferentes (sturges, rice ets) |
O número de registros no bunker pode ser muito pequeno para um cálculo correto |
Bins de frequência qual |
Analisa o relacionamento com a variável objetivo binária usando índices como a taxa incorreta |
Quartilies ou Percentis | Os pontos de corte selecionados não podem maximizar a diferença entre as caixas na verificação contra a variável objetivo |
Discretização supervisionada
A discretização supervisionada divide a variável contínua em caixas projetadas na variável objetivo. A ideia-chave aqui é encontrar esses pontos de corte que maximizarão a diferença entre os grupos.
Usando algoritmos como ChiMerge ou Particionamento Recursivo, os analistas podem rapidamente encontrar pontos ótimos em segundos e avaliar sua relação com a variável objetivo, usando índices como peso de evidência (WoE) e valor de informação (IV).
WoE pode ser usado como um instrumento para transformar preditores no estágio de pré-processamento para algoritmos de aprendizagem supervisionada. Durante a discretização dos preditores, nós podemos substituí-los por suas novas variáveis nominais ou pelos valores de seu WoE. A segunda variante é interessante porque permite afastar-se da transformação das variáveis nominais (fatores) para as artificiais. Isso dá uma melhoria significativa na qualidade da classificação.
WOE e IV desempenham duas funções diferentes na análise de dados:
- WOE descreve a relação da variável preditiva e a variável objetivo binária.
- IV mede a força dessas relações.
Vamos descobrir o qual WOE e IV estão usando diagramas e fórmulas. Lembre-se do gráfico da variável v.fatl dividido em 10 áreas equitativas na segunda parte do artigo.
Fig.7. A variável v.fatl é dividida em 10 áreas equitativas
Capacidade preditiva de dados (WOE)
Como você pode ver, cada bin possui amostras que entram na classe "1" e na classe "-1". A capacidade preditiva dos bins WoEi são calculados com a fórmula
WoEi = ln(Gi/Bi)*100
где:
Gi — frequência relativa das amostras "boas" (no nosso caso "bom" = "1") em cada bin da variável;
Bi — frequência relativa das amostras "ruins" (no nosso caso "ruim" = "-1") em cada bin da variável.
Se WoEi = 1, o que significa que o número de amostras "boas" e "ruins" neste compartimento é aproximadamente o mesmo, então a habilidade preditiva desse bin é 0. Se as amostras "boas" superarem em número as "ruins", WOE >0 e vice-versa.
Valor de informação (IV)
Esta é a medida mais comum de identificar a significância de variáveis e medir a diferença na distribuição de amostras "boas" e "ruins". O valor da informação pode ser calculado com a fórmula:
IV = ∑ (Gi – Bi) ln (Gi/Bi)
O valor da informação de uma variável é igual à soma de todas bins da variável. Os valores desse coeficiente podem ser interpretados da seguinte forma:
- abaixo de 0,02 — variável estatisticamente insignificante;
- 0,02 - 0,1 — variável estatisticamente fraca;
- 0,1 - 0,3 — variável estatisticamente significativa;
- 0,3 e acima — variável estatisticamente forte.
Em seguida, os bins são unidos/divididos usando vários algoritmos e critérios de otimização para tornar a diferença entre esses bins tão grande quanto possível. Por exemplo, o pacote smbinning usa o Particionamento Recursivo para categorizar valores numéricos e o valor de informação para resolver os pontos de corte ótimos. O pacote discretization resolve esse problema com o ChiMerge e MDL. Deve-se ter em mente que os pontos de corte são obtidos no conjunto de treinamento e costuma-se dividir os conjuntos de validação e teste.
Existem vários pacotes que permitem fazer variáveis numéricas discretas de uma maneira ou de outra. Sendo elas: discretization, smbinning, Information, InformationValue e woebinning. Nós precisamos tornar o conjunto de dados de teste discreto, dividir os conjuntos de validação e teste usando essas informações. Nós também queremos ter controle visual dos resultados. Por causa desses requisitos, eu escolhi o pacote woebinning.
O pacote se divide automaticamente em valores numéricos e fatores e os liga à variável objetivo binária. Aqui são contempladas duas abordagens:
- a implementação de classificação fina e bruta uni sequencialmente classes e níveis granulados;
- um segmento de abordagem semelhante a uma árvore através de bins iniciais de iteração através da divisão binária.
Ambos os procedimentos combinam bins divididos com base nos valores semelhantes de WOE e a parada com base nos critérios IV. O pacote pode ser usado tanto com variáveis autônomas quanto com todo o quadro de dados. Isso fornece ferramentas flexíveis para estudar várias soluções para binning e para expandir novos dados.
Vamos fazer o cálculo. Nós já temos as cotações do terminal carregado em nosso ambiente de trabalho (ou imagem do ambiente de trabalho Cotir.RData do GitHub). Sequência de cálculos e resultados:
- PrepareData() — cria o conjunto de dados inicial dt[7906, 14], limpo de NA. O conjunto inclui o rótulo temporário Data, variáveis de entrada (12) e a variável objetivo Class (fator com dois níveis "-1" e "+1").
- SplitData() — divide o conjunto de dados inicial dt[] em subconjunto de pré-treinamento, train, val, test na proporção de 2000/1000/500/500, unindo eles em um dataframe DT[4, 4000, 14].
- CappingData() — identifica e imputa os outliers em todos os subconjuntos, obtém o conjunto DTcap[4, 4000, 14]. Apesar do fato de que a discretização é toleranta aos outliers, nós os imputaremos. Você pode experimentar sem esta etapa. Como você pode lembrar, os parâmetros de outliers (pre.outl) são definidos no subconjunto de pré-treinamento. Processe os conjuntos de train/val/test usando esses parâmetros.
- NormData() — normaliza o conjunto, usando o método spatialSing do pacote caret. Semelhante ao imputamento dos outliers, os parâmetros de normalização (preproc) são definidos no subconjunto pretrain. As amostras train/val/test são processadas usando esses parâmetros. Nós temos DTcap.n[4, 4000, 14] como resultado.
- DiscretizeData() — define os parâmetros de discretização (preCut), a qualidade das variáveis e suas bins à luz de WOE e IV.
evalq({ dt <- PrepareData(Data, Open, High, Low, Close, Volume) DT <- SplitData(dt, 2000, 1000, 500,500) pre.outl <- PreOutlier(DT$pretrain) DTcap <- CappingData(DT, impute = T, fill = T, dither = F, pre.outl = pre.outl) preproc <- PreNorm(DTcap, meth = meth) DTcap.n <- NormData(DTcap, preproc = preproc) preCut <- PreDiscret(DTcap.n) }, env)
Vamos colocar os dados de discretização em todas as variáveis em uma tabela e olhar para elas:
evalq(tabulate.binning <- woe.binning.table(preCut), env) > env$tabulate.binning $`WOE Table for v.fatl` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.3904381926 154 7.7% 130 24 13.2% 2.4% 15.6% 171.3 0.185 2 <= -0.03713814085 769 38.5% 498 271 50.4% 26.8% 35.2% 63.2 0.149 3 <= 0.1130198981 308 15.4% 141 167 14.3% 16.5% 54.2% -14.5 0.003 4 <= Inf 769 38.5% 219 550 22.2% 54.3% 71.5% -89.7 0.289 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.626 $`WOE Table for ftlm` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.2344708291 462 23.1% 333 129 33.7% 12.7% 27.9% 97.2 0.204 2 <= -0.01368798447 461 23.1% 268 193 27.1% 19.1% 41.9% 35.2 0.028 3 <= 0.1789073635 461 23.1% 210 251 21.3% 24.8% 54.4% -15.4 0.005 4 <= Inf 616 30.8% 177 439 17.9% 43.4% 71.3% -88.4 0.225 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.463 $`WOE Table for rbci` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.1718377948 616 30.8% 421 195 42.6% 19.3% 31.7% 79.4 0.185 2 <= -0.09060410462 153 7.6% 86 67 8.7% 6.6% 43.8% 27.4 0.006 3 <= 0.3208178176 923 46.2% 391 532 39.6% 52.6% 57.6% -28.4 0.037 4 <= Inf 308 15.4% 90 218 9.1% 21.5% 70.8% -86.1 0.107 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.335 $`WOE Table for v.rbci` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.1837437563 616 30.8% 406 210 41.1% 20.8% 34.1% 68.3 0.139 2 <= 0.03581374495 461 23.1% 253 208 25.6% 20.6% 45.1% 22.0 0.011 3 <= 0.2503922644 461 23.1% 194 267 19.6% 26.4% 57.9% -29.5 0.020 4 <= Inf 462 23.1% 135 327 13.7% 32.3% 70.8% -86.1 0.161 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.331 $`WOE Table for v.satl` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.01840058612 923 46.2% 585 338 59.2% 33.4% 36.6% 57.3 0.148 2 <= 0.3247097195 769 38.5% 316 453 32.0% 44.8% 58.9% -33.6 0.043 3 <= 0.4003869443 154 7.7% 32 122 3.2% 12.1% 79.2% -131.4 0.116 4 <= Inf 154 7.7% 55 99 5.6% 9.8% 64.3% -56.4 0.024 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.330 $`WOE Table for v.stlm` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.4030051922 154 7.7% 118 36 11.9% 3.6% 23.4% 121.1 0.102 2 <= -0.1867821117 462 23.1% 282 180 28.5% 17.8% 39.0% 47.3 0.051 3 <= 0.1141896118 615 30.8% 301 314 30.5% 31.0% 51.1% -1.8 0.000 4 <= Inf 769 38.5% 287 482 29.0% 47.6% 62.7% -49.4 0.092 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.244 $`WOE Table for pcci` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.1738420887 616 30.8% 397 219 40.2% 21.6% 35.6% 61.9 0.115 2 <= -0.03163945242 307 15.3% 165 142 16.7% 14.0% 46.3% 17.4 0.005 3 <= 0.2553612644 615 30.8% 270 345 27.3% 34.1% 56.1% -22.1 0.015 4 <= Inf 462 23.1% 156 306 15.8% 30.2% 66.2% -65.0 0.094 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.228 $`WOE Table for v.ftlm` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.03697698898 923 46.2% 555 368 56.2% 36.4% 39.9% 43.5 0.086 2 <= 0.2437475615 615 30.8% 279 336 28.2% 33.2% 54.6% -16.2 0.008 3 <= Inf 462 23.1% 154 308 15.6% 30.4% 66.7% -66.9 0.099 5 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.194 $`WOE Table for v.rftl` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.1578370554 616 30.8% 372 244 37.7% 24.1% 39.6% 44.6 0.060 2 <= 0.1880959621 768 38.4% 384 384 38.9% 37.9% 50.0% 2.4 0.000 3 <= 0.3289762494 308 15.4% 129 179 13.1% 17.7% 58.1% -30.4 0.014 4 <= Inf 308 15.4% 103 205 10.4% 20.3% 66.6% -66.4 0.065 6 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.140 $`WOE Table for stlm` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.4586732186 154 7.7% 60 94 6.1% 9.3% 61.0% -42.5 0.014 2 <= -0.1688696056 462 23.1% 266 196 26.9% 19.4% 42.4% 32.9 0.025 3 <= 0.2631157075 922 46.1% 440 482 44.5% 47.6% 52.3% -6.7 0.002 4 <= 0.3592235072 154 7.7% 97 57 9.8% 5.6% 37.0% 55.6 0.023 5 <= 0.4846279843 154 7.7% 81 73 8.2% 7.2% 47.4% 12.8 0.001 6 <= Inf 154 7.7% 44 110 4.5% 10.9% 71.4% -89.2 0.057 8 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.122 $`WOE Table for v.rstl` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.4541701981 154 7.7% 94 60 9.5% 5.9% 39.0% 47.3 0.017 2 <= -0.3526306487 154 7.7% 62 92 6.3% 9.1% 59.7% -37.1 0.010 3 <= -0.2496412214 154 7.7% 53 101 5.4% 10.0% 65.6% -62.1 0.029 4 <= -0.08554320418 307 15.3% 142 165 14.4% 16.3% 53.7% -12.6 0.002 5 <= 0.360854678 923 46.2% 491 432 49.7% 42.7% 46.8% 15.2 0.011 6 <= Inf 308 15.4% 146 162 14.8% 16.0% 52.6% -8.0 0.001 8 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.070 $`WOE Table for v.pcci` Final.Bin Total.Count Total.Distr. 0.Count 1.Count 0.Distr. 1.Distr. 1.Rate WOE IV 1 <= -0.4410911486 154 7.7% 92 62 9.3% 6.1% 40.3% 41.9 0.013 2 <= -0.03637567714 769 38.5% 400 369 40.5% 36.5% 48.0% 10.5 0.004 3 <= 0.1801156117 461 23.1% 206 255 20.9% 25.2% 55.3% -18.9 0.008 4 <= 0.2480148615 154 7.7% 84 70 8.5% 6.9% 45.5% 20.6 0.003 5 <= 0.3348752487 154 7.7% 67 87 6.8% 8.6% 56.5% -23.7 0.004 6 <= 0.4397404288 154 7.7% 76 78 7.7% 7.7% 50.6% -0.2 0.000 7 <= Inf 154 7.7% 63 91 6.4% 9.0% 59.1% -34.4 0.009 9 Total 2000 100.0% 988 1012 100.0% 100.0% 50.6% NA 0.042
A tabela possui os seguintes valores para cada variável:
- Final.Bin — limites de bin;
- Total.Count — número total de amostras em bin;
- Total.Distr — número relativo de amostras em bin;
- 0.Count — número de amostras pertencentes à classe "0";
- 1.Count — número de amostras pertencentes à classe "1";
- 0.Distr — — número relativo de amostras pertencentes à classe "0";
- 1.Distr — número relativo de amostras pertencentes à classe "1";
- 1.Rate — razão percentual das amostras da classe "1" para o número de amostras da classe "0";
- WOE — capacidade preditiva das bins;
- IV — importância estatística das bins.
A representação gráfica será mais ilustrativa. Desenhe os gráficos WOE de todas as variáveis na ordem crescente da sua IV com base nesta tabela:
> evalq(woe.binning.plot(preCut), env)
Fig.8. WOE das 4 melhores variáveis
Fig.9. WOE das variáveis 5-8
Fig.10. WOE de variáveis de entrada 9-12
Gráfico da variável total das variáveis por sua IV.
Fig.11. Intervalo de variáveis pela sua IV
Nós não vamos usar duas variáveis insignificantes v.rstl e v.pcci, que têm IV < 0.1. Nós podemos ver das tabelas que de 10 variáveis significativas, apenas a v.satl e stlm têm uma relação não-linear com a variável objetivo. Outras variáveis têm uma relação linear.
Para experiências adicionais, nós precisamos criar três conjuntos. Eles são:
- DTbin é um conjunto de dados onde os preditores numéricos contínuos são transformados em fatores com o número de níveis iguais ao número de caixas nas quais eles são divididos;
- DTdum é um conjunto de dados onde os preditores de fatores do conjunto de dados DTbin são transformados em variáveis binárias artificiais;
- DTwoe é um conjunto de dados onde os preditores de fatores são transformados em variáveis numéricas, substituindo seus níveis pelos valores de WOE desses níveis.
O primeiro conjunto de DTbin é necessário para treinamento e obtenção das métricas do modelo básico. O segundo e terceiro conjuntos serão utilizados para o treinamento da DNN e para comparar a eficiência desses dois métodos de transformação.
A função woe.binning.deploy() do pacote woebinning nos permitirá resolver esse problema com bastante facilidade. Os seguintes dados devem ser passados para a função:
- quadro de dados com preditores e a variável objetivo, onde a variável objetivo deve ter o valor de 0 ou 1;
- parâmetros de discretização, obtidos na fase anterior (preCut);
- nomes das variáveis que precisam ser categorizadas. Se todas as variáveis devem ser categorizadas, basta especificar o nome do quadro de dados;
- especificar o IV mínimo para que as variáveis não sejam categorizadas;
- especificar quais variáveis adicionais (exceto as categorizadas) que queremos obter. Existem duas variantes - "woe" e "dum".
A função retorna um quadro de dados contendo variáveis iniciais, variáveis categorizadas e variáveis adicionais (se elas foram especificadas). Os nomes das variáveis recém-criadas são criados adicionando um prefixo ou sufixo correspondente ao nome da variável inicial. Dessa forma, os prefixos de todas as variáveis adicionais são "dum" ou "woe" e as variáveis categorizadas possuem o sufixo "binned". Vamos escrever uma função DiscretizeData(), o que transformará o conjunto de dados inicial usando a woe.binning.deploy().
DiscretizeData <- function(X, preCut, var){ require(foreach) require(woeBinning) DTd <- list() foreach(i = 1:length(X)) %do% { X[[i]] %>% select(-Data) %>% targ.int() %>% woe.binning.deploy(preCut, min.iv.total = 0.1, add.woe.or.dum.var = var) -> res return(res) } -> DTd list(pretrain = DTd[[1]] , train = DTd[[2]] , val = DTd[[3]] , test = DTd[[4]] ) -> DTd return(DTd) }
Os parâmetros de entrada da função são dados iniciais (lista X) com os slots pretrain/train/val/test, parâmetros de discretização preCut e o tipo da variável adicional (string var).
A função removerá a variável "Data" de cada slot e alterará a variável objetivo - fator "Class" para a variável de objetivo numérico "Cl". Com base nisso, ela enviará woe.binning.deploy() para a entrada da função. Além disso, especificamos nos parâmetros de entrada desta função o IV mínimo = 0.1 para incluir as variáveis no conjunto de saída. Na saída, receberemos uma lista com os mesmos slots pretrain/train/val/test. Em cada slot, as variáveis categorizadas e, se solicitadas, as variáveis adicionais serão adicionadas às variáveis iniciais. Vamos calcular todos os conjuntos necessários e adicionar os dados brutos do conjunto DTcap.n para eles.
evalq({ require(dplyr) require(foreach) DTbin = DiscretizeData(DTcap.n, preCut = preCut, var = "") DTwoe = DiscretizeData(DTcap.n, preCut = preCut, var = "woe") DTdum = DiscretizeData(DTcap.n, preCut = preCut, var = "dum") X.woe <- list() X.bin <- list() X.dum <- list() foreach(i = 1:length(DTcap.n)) %do% { DTbin[[i]] %>% select(contains("binned")) -> X.bin[[i]] DTdum[[i]] %>% select(starts_with("dum")) -> X.dum[[i]] DTwoe[[i]] %>% select(starts_with("woe")) %>% divide_by(100) -> X.woe[[i]] return(list(bin = X.bin[[i]], woe = X.woe[[i]], dum = X.dum[[i]], raw = DTcap.n[[i]])) } -> DTcut list(pretrain = DTcut[[1]], train = DTcut[[2]], val = DTcut[[3]], test = DTcut[[4]] ) -> DTcut rm(DTwoe, DTdum, X.woe, X.bin, X.dum) }, env)
Uma vez que a WOE é um valor percentual, nós podemos dividir o WOE por 100 e obter valores de variáveis que podem ser enviadas para as entradas da rede neural sem normalização adicional. Vejamos a estrutura do slot obtido, por exemplo de DTcut$val.
> env$DTcut$val %>% str() List of 4 $ bin:'data.frame': 501 obs. of 10 variables: ..$ v.fatl.binned: Factor w/ 5 levels "(-Inf,-0.3904381926]",..: 1 1 3 2 4 3 4 4 4 4 ... ..$ ftlm.binned : Factor w/ 5 levels "(-Inf,-0.2344708291]",..: 2 1 1 1 2 2 3 4 4 4 ... ..$ rbci.binned : Factor w/ 5 levels "(-Inf,-0.1718377948]",..: 2 1 2 1 2 3 3 3 4 4 ... ..$ v.rbci.binned: Factor w/ 5 levels "(-Inf,-0.1837437563]",..: 1 1 3 2 4 3 4 4 4 4 ... ..$ v.satl.binned: Factor w/ 5 levels "(-Inf,-0.01840058612]",..: 1 1 1 1 1 1 1 1 1 2 ... ..$ v.stlm.binned: Factor w/ 5 levels "(-Inf,-0.4030051922]",..: 2 2 3 2 3 2 3 3 4 4 ... ..$ pcci.binned : Factor w/ 5 levels "(-Inf,-0.1738420887]",..: 1 1 4 2 4 2 4 2 2 3 ... ..$ v.ftlm.binned: Factor w/ 4 levels "(-Inf,-0.03697698898]",..: 1 1 3 2 3 2 3 3 2 2 ... ..$ v.rftl.binned: Factor w/ 5 levels "(-Inf,-0.1578370554]",..: 2 1 1 1 1 1 1 2 2 2 ... ..$ stlm.binned : Factor w/ 7 levels "(-Inf,-0.4586732186]",..: 2 2 2 2 1 1 1 1 1 2 ... $ woe:'data.frame': 501 obs. of 10 variables: ..$ woe.v.fatl.binned: num [1:501] 1.713 1.713 -0.145 0.632 -0.897 ... ..$ woe.ftlm.binned : num [1:501] 0.352 0.972 0.972 0.972 0.352 ... ..$ woe.rbci.binned : num [1:501] 0.274 0.794 0.274 0.794 0.274 ... ..$ woe.v.rbci.binned: num [1:501] 0.683 0.683 -0.295 0.22 -0.861 ... ..$ woe.v.satl.binned: num [1:501] 0.573 0.573 0.573 0.573 0.573 ... ..$ woe.v.stlm.binned: num [1:501] 0.473 0.473 -0.0183 0.473 -0.0183 ... ..$ woe.pcci.binned : num [1:501] 0.619 0.619 -0.65 0.174 -0.65 ... ..$ woe.v.ftlm.binned: num [1:501] 0.435 0.435 -0.669 -0.162 -0.669 ... ..$ woe.v.rftl.binned: num [1:501] 0.024 0.446 0.446 0.446 0.446 ... ..$ woe.stlm.binned : num [1:501] 0.329 0.329 0.329 0.329 -0.425 ... $ dum:'data.frame': 501 obs. of 41 variables: ..$ dum.v.fatl.-Inf.-0.3904381926.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.v.fatl.-0.03713814085.0.1130198981.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.v.fatl.-0.3904381926.-0.03713814085.binned: num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.v.fatl.0.1130198981.Inf.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.ftlm.-0.2344708291.-0.01368798447.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.ftlm.-Inf.-0.2344708291.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.ftlm.-0.01368798447.0.1789073635.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.ftlm.0.1789073635.Inf.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ....................................................................................... ..$ dum.stlm.-Inf.-0.4586732186.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.stlm.-0.1688696056.0.2631157075.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.stlm.0.2631157075.0.3592235072.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.stlm.0.3592235072.0.4846279843.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... ..$ dum.stlm.0.4846279843.Inf.binned : num [1:501] 0 0 0 0 0 0 0 0 0 0 ... $ raw:'data.frame': 501 obs. of 14 variables: ..$ Data : POSIXct[1:501], format: "2017-02-23 15:30:00" "2017-02-23 15:45:00" ... ..$ ftlm : num [1:501] -0.223 -0.374 -0.262 -0.31 -0.201 ... ..$ stlm : num [1:501] -0.189 -0.257 -0.271 -0.389 -0.473 ... ..$ rbci : num [1:501] -0.0945 -0.1925 -0.1348 -0.1801 -0.1192 ... ..$ pcci : num [1:501] -0.5714 -0.2602 0.4459 -0.0478 0.2596 ... ..$ v.fatl: num [1:501] -0.426 -0.3977 0.0936 -0.1512 0.1178 ... ..$ v.satl: num [1:501] -0.35 -0.392 -0.177 -0.356 -0.316 ... ..$ v.rftl: num [1:501] -0.0547 -0.2065 -0.3253 -0.4185 -0.4589 ... ..$ v.rstl: num [1:501] 0.0153 -0.0273 -0.0636 -0.1281 -0.15 ... ..$ v.ftlm: num [1:501] -0.321 -0.217 0.253 0.101 0.345 ... ..$ v.stlm: num [1:501] -0.288 -0.3 -0.109 -0.219 -0.176 ... ..$ v.rbci: num [1:501] -0.2923 -0.2403 0.1909 0.0116 0.2868 ... ..$ v.pcci: num [1:501] -0.0298 0.3738 0.6153 -0.5643 0.2742 ... ..$ Class : Factor w/ 2 levels "-1","1": 1 1 1 1 2 2 2 2 2 1 ...
Como você pode ver, o slot bin contém 10 variáveis de fatores com diferentes números de níveis. Eles têm o sufixo "binned". O slot woe contém 10 variáveis com níveis de fator alterados para o seu WOE (eles têm o prefixo "woe"). O slot dum tem 41 variáveis numéricas artificiais com os valores (0, 1) obtidos das variáveis de fatores através da codificação um para um (tem o prefixo "dum"). Existem 14 variáveis no slot raw. Eles são Data — timestamp, Class — variável fator objetivo e 12 preditores numéricos.
Temos todos os dados que precisaremos para outras experiências. Os objetos listados abaixo devem estar no ambiente env até agora. Deixe-nos salvar a área de trabalho com esses objetos para o arquivo PartIV.RData.
> ls(env) [1] "Close" "Data" "dt" "DT" "DTbin" "DTcap" "DTcap.n" "DTcut" "High" [10] "i" "Low" "Open" "pre.outl" "preCut" "preproc" "Volume"
2.1.2. Modelo básico de comparação
Nós vamos usar o modelo OneR implementado no pacote OneR como modelo base. Este modelo é simples, confiável e fácil de interpretar. Informações sobre o algoritmo podem ser encontradas na descrição do pacote. Este modelo está funcionando apenas com os dados de bin. O pacote contém funções auxiliares que podem ser variáveis numéricas discretas de diferentes maneiras. Como já transformamos os preditores em fatores, não precisamos deles.
Agora, eu vou elaborar o cálculo mostrado abaixo. Crie os conjuntos train/val/test, extraindo os slots correspondentes de DTcut e adicionando a classe de variável objetivo para eles. Vamos treinar o modelo com o conjunto train.
> evalq({ + require(OneR) + require(dplyr) + require(magrittr) + train <- cbind(DTcut$train$bin, Class = DTcut$train$raw$Class) %>% as.data.frame() + val <- cbind(DTcut$val$bin, Class = DTcut$val$raw$Class) %>% as.data.frame() + test <- cbind(DTcut$test$bin, Class = DTcut$test$raw$Class) %>% as.data.frame() + model <- OneR(data = train, formula = NULL, ties.method = "chisq", #c("first","chisq" + verbose = TRUE) #FALSE, TRUE + }, env) Loading required package: OneR Attribute Accuracy 1 * v.satl.binned 63.14% 2 v.fatl.binned 62.64% 3 ftlm.binned 62.54% 4 pcci.binned 61.44% 5 v.rftl.binned 59.74% 6 v.rbci.binned 58.94% 7 rbci.binned 58.64% 8 stlm.binned 58.04% 9 v.stlm.binned 57.54% 10 v.ftlm.binned 56.14% --- Chosen attribute due to accuracy and ties method (if applicable): '*' Warning message: In OneR(data = train, formula = NULL, ties.method = "chisq", verbose = TRUE) : data contains unused factor levelsO modelo selecionou a variável v.satl.binned com a precisão básica de 63,14% como base para a criação das regras. Vejamos as informações gerais sobre este modelo:
> summary(env$model) Call: OneR(data = train, formula = NULL, ties.method = "chisq", verbose = FALSE) Regras: If v.satl.binned = (-Inf,-0.01840058612] then Class = -1 If v.satl.binned = (-0.01840058612,0.3247097195] then Class = 1 If v.satl.binned = (0.3247097195,0.4003869443] then Class = 1 If v.satl.binned = (0.4003869443, Inf] then Class = 1 Accuracy: 632 of 1001 instances classified correctly (63.14%) Contingency table: v.satl.binned Class (-Inf,-0.01840058612] (-0.01840058612,0.3247097195] (0.3247097195,0.4003869443] (0.4003869443, Inf] Sum -1 * 325 161 28 37 551 1 143 * 229 * 35 * 43 450 Sum 468 390 63 80 1001 --- Maximum in each column: '*' Pearson's Chi-squared test: X-squared = 74.429, df = 3, p-value = 4.803e-16
Representação gráfica do resultado de treinamento:
plot(env$model)
Fig.12. Distribuição das categorias da variável v.satl.binned por classes no modelo
A precisão da previsão durante o treinamento não é muito alta. Nós vamos ver a precisão que este modelo mostrará no conjunto de validação:
> evalq(res.val <- eval_model(predict(model, val %>% as.data.frame()), val$Class), + env) Confusion matrix (absolute): Actual Prediction -1 1 Sum -1 106 87 193 1 100 208 308 Sum 206 295 501 Confusion matrix (relative): Actual Prediction -1 1 Sum -1 0.21 0.17 0.39 1 0.20 0.42 0.61 Sum 0.41 0.59 1.00 Accuracy: 0.6267 (314/501) Error rate: 0.3733 (187/501) Error rate reduction (vs. base rate): 0.0922 (p-value = 0.04597)
e no conjunto de teste:
> evalq(res.test <- eval_model(predict(model, test %>% as.data.frame()), test$Class), + env) Confusion matrix (absolute): Actual Prediction -1 1 Sum -1 130 102 232 1 76 193 269 Sum 206 295 501 Confusion matrix (relative): Actual Prediction -1 1 Sum -1 0.26 0.20 0.46 1 0.15 0.39 0.54 Sum 0.41 0.59 1.00 Accuracy: 0.6447 (323/501) Error rate: 0.3553 (178/501) Error rate reduction (vs. base rate): 0.1359 (p-value = 0.005976)
Os resultados não são encorajadores. A redução da taxa de erro mostra como a precisão aumentou em relação ao nível base (0.5). O baixo valor de p (< 0.05) indica que este modelo é capaz de produzir previsões melhor do que o nível básico. A precisão do conjunto de teste é 0.6447 (323/501), que é maior do que a precisão do conjunto de validação. O conjunto de teste está mais longe do conjunto de treinamento do que o conjunto de validação. Este resultado será o ponto de referência para comparar resultados de previsão de nossos futuros modelos.
2.1.3. Estrutura de uma DNN
Nós usaremos três conjuntos de dados para treinar e testar:
- DTcut$$raw — 12 variáveis de entrada (outliers imputados e normalizados).
- DTcut$$dum — 41 variáveis binárias.
- DTcut$$woe — 10 variáveis numéricas.
Nós vamos usar com todos os conjuntos de dados a variável Class = fator com dois níveis. Estrutura das redes neurais:
- DNNraw - layers = c(12, 16, 8(2), 2), funções de ativação c(tanh, maxout(lin), softmax)
- DNNwoe - layers = c(10, 16, 8(2), 2), funções de ativação c(tanh, maxout(lin), softmax)
- DNNdum - layers = c(41, 50, 8(2), 2), funções de ativação c(ReLU, maxout(ReLU), softmax)
O diagrama abaixo mostra a estrutura da rede neural DNNwoe. A rede neural possui uma camada de entrada, duas camadas ocultas e uma camada de saída. Duas outras redes neurais ( DNNdum, DNNraw) têm uma estrutura semelhante. Eles apenas diferem no número de neurônios em camadas e funções de ativação.
Fig.13. Estrutura da rede neural DNNwoe
2.1.4. Variantes de treinamento
Com pré-treinamento
O treinamento terá duas etapas
- pré-treinamento do SRBM com o conjunto /pretrain seguido do treinamento apenas da camada superior da rede neural, validação com o conjunto train e parâmetros — par_0;
- ajuste fino de toda a rede com os conjuntos de train/val e parâmetros par_1.
Nós podemos salvar os modelos intermediários de ajuste fino, mas não é obrigatório. O modelo que mostra os melhores resultados de treinamento deve ser salvo. Os parâmetros dessas duas etapas devem conter:
- par_0 — parâmetros gerais da rede neural, parâmetros de treinamento da RBM e parâmetros de treinamento da camada superior da DNN;
- par_1 — parâmetros de treinamento de todas as camadas da DNN.
Todos os parâmetros do DArch têm valores padrão. Se precisamos de parâmetros diferentes em uma determinada etapa do treinamento, nós podemos configurá-los por uma lista e eles substituirão os parâmetros padrão. Após o primeiro estágio de treinamento, nós obteremos a estrutura DArch com parâmetros e resultados de treinamento (erro de treinamento, erro de teste etc) e também a rede neural iniciada com os pesos do SRBM treinado. Para completar o segundo estágio de treinamento, você precisa incluir a estrutura DArch obtida na primeira etapa na lista de parâmetros para esta etapa de treinamento. Naturalmente, nós precisaremos de conjuntos de treinamento e de validação.
Consideremos os parâmetros necessários para o primeiro estágio de treinamento (pré-treinamento do SRBM e treinamento da camada superior da rede neural) e executá-lo:
##=====CODE I etap=========================== evalq({ require(darch) require(dplyr) require(magrittr) Ln <- c(0, 16, 8, 0)# // the number of input and output neurons will be identified automatically from the data set nEp_0 <- 25 #------------------ par_0 <- list( layers = Ln, # // let us take this parameter out of the list (for simplicity) seed = 54321,# // if we want to obtain identical data during initialization logLevel = 5, # // what level of information output we require # params RBM======================== rbm.consecutive = F, # each RBM is trained one epoch at a time rbm.numEpochs = nEp_0, rbm.batchSize = 50, rbm.allData = TRUE, rbm.lastLayer = -1, # // do not train the upper layer of SRBM rbm.learnRate = 0.3, rbm.unitFunction = "tanhUnitRbm", # params NN ======================== darch.batchSize = 50, darch.numEpochs = nEp_0,# // take this parameter out of the list for simplicity darch.trainLayers = c(F,F,T), #обучать //upper layer only darch.unitFunction = c("tanhUnit","maxoutUnit", "softmaxUnit"), bp.learnRate = 0.5, bp.learnRateScale = 1, darch.weightDecay = 0.0002, darch.dither = F, darch.dropout = c(0.1,0.2,0.1), darch.fineTuneFunction = backpropagation, #rpropagation normalizeWeights = T, normalizeWeightsBound = 1, darch.weightUpdateFunction = c("weightDecayWeightUpdate", "maxoutWeightUpdate", "weightDecayWeightUpdate"), darch.dropout.oneMaskPerEpoch = T, darch.maxout.poolSize = 2, darch.maxout.unitFunction = "linearUnit") #--------------------------- DNN_default <- darch(darch = NULL, paramsList = par_0, x = DTcut$pretrain$woe %>% as.data.frame(), y = DTcut$pretrain$raw$Class %>% as.data.frame(), xValid = DTcut$train$woe %>% as.data.frame(), yValid = DTcut$train$raw$Class %>% as.data.frame() ) }, env)Resultado após a conclusão do primeiro estágio de treinamento:
........................... INFO [2017-09-11 14:12:19] Classification error on Train set (best model): 31.95% (639/2000) INFO [2017-09-11 14:12:19] Train set (best model) Cross Entropy error: 1.233 INFO [2017-09-11 14:12:19] Classification error on Validation set (best model): 35.86% (359/1001) INFO [2017-09-11 14:12:19] Validation set (best model) Cross Entropy error: 1.306 INFO [2017-09-11 14:12:19] Best model was found after epoch 3 INFO [2017-09-11 14:12:19] Final 0.632 validation Cross Entropy error: 1.279 INFO [2017-09-11 14:12:19] Final 0.632 validation classification error: 34.42% INFO [2017-09-11 14:12:19] Fine-tuning finished after 5.975 secs
Segunda etapa do treinamento da rede neural:
##=====CODE II etap=========================== evalq({ require(darch) require(dplyr) require(magrittr) nEp_1 <- 100 bp.learnRate <- 1 par_1 <- list( layers = Ln, seed = 54321, logLevel = 5, rbm.numEpochs = 0,# SRBM is not to be trained! darch.batchSize = 50, darch.numEpochs = nEp_1, darch.trainLayers = c(T,T,T), #TRUE, darch.unitFunction = c("tanhUnit","maxoutUnit", "softmaxUnit"), bp.learnRate = bp.learnRate, bp.learnRateScale = 1, darch.weightDecay = 0.0002, darch.dither = F, darch.dropout = c(0.1,0.2,0.1), darch.fineTuneFunction = backpropagation, #rpropagation backpropagation normalizeWeights = T, normalizeWeightsBound = 1, darch.weightUpdateFunction = c("weightDecayWeightUpdate", "maxoutWeightUpdate", "weightDecayWeightUpdate"), darch.dropout.oneMaskPerEpoch = T, darch.maxout.poolSize = 2, darch.maxout.unitFunction = exponentialLinearUnit, darch.elu.alpha = 2) #------------------------------ DNN_1 <- darch( darch = DNN_default, paramsList = par_1, x = DTcut$train$woe %>% as.data.frame(), y = DTcut$train$raw$Class %>% as.data.frame(), xValid = DTcut$val$woe %>% as.data.frame(), yValid = DTcut$val$raw$Class %>% as.data.frame() ) }, env)
Resultado da segunda etapa do treinamento:
........................... INFO [2017-09-11 15:48:37] Finished epoch 100 of 100 after 0.279 secs (3666 patterns/sec) INFO [2017-09-11 15:48:37] Classification error on Train set (best model): 31.97% (320/1001) INFO [2017-09-11 15:48:37] Train set (best model) Cross Entropy error: 1.225 INFO [2017-09-11 15:48:37] Classification error on Validation set (best model): 31.14% (156/501) INFO [2017-09-11 15:48:37] Validation set (best model) Cross Entropy error: 1.190 INFO [2017-09-11 15:48:37] Best model was found after epoch 96 INFO [2017-09-11 15:48:37] Final 0.632 validation Cross Entropy error: 1.203 INFO [2017-09-11 15:48:37] Final 0.632 validation classification error: 31.44% INFO [2017-09-11 15:48:37] Fine-tuning finished after 37.22 secs
Gráfico da variação do erro de previsão durante o segundo estágio de treinamento:
plot(env$DNN_1, y = "raw")
Fig.14. Variação do erro de classificação durante o segundo estágio de treinamento
Vejamos o erro de classificação do modelo final no conjunto de teste:
#----------- evalq({ xValid = DTcut$test$woe %>% as.data.frame() yValid = DTcut$test$raw$Class %>% as.vector() Ypredict <- predict(DNN_1, newdata = xValid, type = "class") numIncorrect <- sum(Ypredict != yValid) cat(paste0("Incorrect classifications on all examples: ", numIncorrect, " (", round(numIncorrect/nrow(xValid)*100, 2), "%)\n")) caret::confusionMatrix(yValid, Ypredict) }, env) Incorrect classifications on all examples: 166 (33.13%) Confusion Matrix and Statistics Reference Prediction -1 1 -1 129 77 1 89 206 Accuracy : 0.6687 95% CI : (0.6255, 0.7098) No Information Rate : 0.5649 P-Value [Acc > NIR] : 1.307e-06 Kappa : 0.3217 Mcnemar's Test P-Value : 0.3932 Sensitivity : 0.5917 Specificity : 0.7279 Pos Pred Value : 0.6262 Neg Pred Value : 0.6983 Prevalence : 0.4351 Detection Rate : 0.2575 Detection Prevalence : 0.4112 Balanced Accuracy : 0.6598 'Positive' Class : -1 #----------------------------------------
A precisão neste conjunto de dados (woe) com esses parâmetros que estão longe de ser ótimos, é muito maior do que a precisão do modelo básico. Existe um potencial significativo para aumentar a precisão ao otimizar os hiperparâmetros da DNN. Se o cálculo for repetido, os dados podem não ser exatamente os mesmos que no artigo.
Vamos levar nossos scripts para um formulário mais compacto para cálculos adicionais com outros conjuntos de dados. Vamos escrever uma função para o conjunto woe:
#------------------- DNN.train.woe <- function(param, X){ require(darch) require(magrittr) darch( darch = NULL, paramsList = param[[1]], x = X[[1]]$woe %>% as.data.frame(), y = X[[1]]$raw$Class %>% as.data.frame(), xValid = X[[2]]$woe %>% as.data.frame(), yValid = X[[2]]$raw$Class %>% as.data.frame() ) %>% darch( ., paramsList = param[[2]], x = X[[2]]$woe %>% as.data.frame(), y = X[[2]]$raw$Class %>% as.data.frame(), xValid = X[[3]]$woe %>% as.data.frame(), yValid = X[[3]]$raw$Class %>% as.data.frame() ) -> Darch return(Darch) }
Repita os cálculos para o conjunto de dados DTcut$$woe em uma forma compacta:
evalq({ require(darch) require(magrittr) Ln <- c(0, 16, 8, 0) nEp_0 <- 25 nEp_1 <- 25 rbm.learnRate = c(0.5,0.3,0.1) bp.learnRate <- c(0.5,0.3,0.1) list(par_0, par_1) %>% DNN.train.woe(DTcut) -> Dnn.woe xValid = DTcut$test$woe %>% as.data.frame() yValid = DTcut$test$raw$Class %>% as.vector() Ypredict <- predict(Dnn.woe, newdata = xValid, type = "class") numIncorrect <- sum(Ypredict != yValid) cat(paste0("Incorrect classifications on all examples: ", numIncorrect, " (", round(numIncorrect/nrow(xValid)*100, 2), "%)\n")) caret::confusionMatrix(yValid, Ypredict) -> cM.woe }, env)
Faça o cálculo para o conjunto de dados DTcut$$raw:
#------------------------- DNN.train.raw <- function(param, X){ require(darch) require(magrittr) darch( darch = NULL, paramsList = param[[1]], x = X[[1]]$raw %>% tbl_df %>% select(-c(Data, Class)), y = X[[1]]$raw$Class %>% as.data.frame(), xValid = X[[2]]$raw %>% tbl_df %>% select(-c(Data, Class)), yValid = X[[2]]$raw$Class %>% as.data.frame() ) %>% darch( ., paramsList = param[[2]], x = X[[2]]$raw %>% tbl_df %>% select(-c(Data, Class)), y = X[[2]]$raw$Class %>% as.data.frame(), xValid = X[[3]]$raw %>% tbl_df %>% select(-c(Data, Class)), yValid = X[[3]]$raw$Class %>% as.data.frame() ) -> Darch return(Darch) } #------------------------------- evalq({ require(darch) require(magrittr) Ln <- c(0, 16, 8, 0) nEp_0 <- 25 nEp_1 <- 25 rbm.learnRate = c(0.5,0.3,0.1) bp.learnRate <- c(0.5,0.3,0.1) list(par_0, par_1) %>% DNN.train.raw(DTcut) -> Dnn.raw xValid = DTcut$test$raw %>% tbl_df %>% select(-c(Data, Class)) yValid = DTcut$test$raw$Class %>% as.vector() Ypredict <- predict(Dnn.raw, newdata = xValid, type = "class") numIncorrect <- sum(Ypredict != yValid) cat(paste0("Incorrect classifications on all examples: ", numIncorrect, " (", round(numIncorrect/nrow(xValid)*100, 2), "%)\n")) caret::confusionMatrix(yValid, Ypredict) -> cM.raw }, env) #----------------------------
Abaixo está o resultado e o gráfico da variação de erro de classificação para este conjunto:
> env$cM.raw
Confusion Matrix and Statistics
Reference
Prediction -1 1
-1 133 73
1 86 209
Accuracy : 0.6826
95% CI : (0.6399, 0.7232)
No Information Rate : 0.5629
P-Value [Acc > NIR] : 2.667e-08
Kappa : 0.3508
Mcnemar's Test P-Value : 0.3413
Sensitivity : 0.6073
Specificity : 0.7411
Pos Pred Value : 0.6456
Neg Pred Value : 0.7085
Prevalence : 0.4371
Detection Rate : 0.2655
Detection Prevalence : 0.4112
Balanced Accuracy : 0.6742
'Positive' Class : -1
#--------------------------------------
plot(env$Dnn.raw, y = "raw")
Fig.15. Variação do erro de classificação no segundo estágio
Eu não consegui treinar a rede neural com os dados DTcut$$dum. Você pode tentar fazer isso sozinho. Por exemplo, insira os dados DTcut$$bin e organize os parâmetros de treinamento para que os preditores sejam convertidos artificialmente.
Treinamento sem pré-treinamento
Vamos treinar a rede neural sem pré-treinamento com os mesmos dados (woe, raw) nos conjuntos pretrain/train/val. Vamos ver o resultado.
#-------WOE---------------- evalq({ require(darch) require(magrittr) Ln <- c(0, 16, 8, 0) nEp_1 <- 100 bp.learnRate <- c(0.5,0.7,0.1) #--param---------------- par_1 <- list( layers = Ln, seed = 54321, logLevel = 5, rbm.numEpochs = 0,# SRBM is not to be trained! darch.batchSize = 50, darch.numEpochs = nEp_1, darch.trainLayers = c(T,T,T), #TRUE, darch.unitFunction = c("tanhUnit","maxoutUnit", "softmaxUnit"), bp.learnRate = bp.learnRate, bp.learnRateScale = 1, darch.weightDecay = 0.0002, darch.dither = F, darch.dropout = c(0.0,0.2,0.1), darch.fineTuneFunction = backpropagation, #rpropagation backpropagation normalizeWeights = T, normalizeWeightsBound = 1, darch.weightUpdateFunction = c("weightDecayWeightUpdate", "maxoutWeightUpdate", "weightDecayWeightUpdate"), darch.dropout.oneMaskPerEpoch = T, darch.maxout.poolSize = 2, darch.maxout.unitFunction = exponentialLinearUnit, darch.elu.alpha = 2) #--train--------------------------- darch( darch = NULL, paramsList = par_1, x = DTcut[[1]]$woe %>% as.data.frame(), y = DTcut[[1]]$raw$Class %>% as.data.frame(), xValid = DTcut[[2]]$woe %>% as.data.frame(), yValid = DTcut[[2]]$raw$Class %>% as.data.frame() ) -> Dnn.woe.I #---test-------------------------- xValid = DTcut$val$woe %>% as.data.frame() yValid = DTcut$val$raw$Class %>% as.vector() Ypredict <- predict(Dnn.woe.I, newdata = xValid, type = "class") numIncorrect <- sum(Ypredict != yValid) cat(paste0("Incorrect classifications on all examples: ", numIncorrect, " (", round(numIncorrect/nrow(xValid)*100, 2), "%)\n")) caret::confusionMatrix(yValid, Ypredict) -> cM.woe.I }, env) #---------Ris16------------------------------------ plot(env$Dnn.woe.I, type = "class") env$cM.woe.I
Métricas:
....................................................... INFO [2017-09-14 10:38:01] Classification error on Train set (best model): 28.7% (574/2000) INFO [2017-09-14 10:38:01] Train set (best model) Cross Entropy error: 1.140 INFO [2017-09-14 10:38:02] Classification error on Validation set (best model): 35.86% (359/1001) INFO [2017-09-14 10:38:02] Validation set (best model) Cross Entropy error: 1.299 INFO [2017-09-14 10:38:02] Best model was found after epoch 67 INFO [2017-09-14 10:38:02] Final 0.632 validation Cross Entropy error: 1.241 INFO [2017-09-14 10:38:02] Final 0.632 validation classification error: 33.23% INFO [2017-09-14 10:38:02] Fine-tuning finished after 37.13 secs Incorrect classifications on all examples: 150 (29.94%) > env$cM.woe.I Confusion Matrix and Statistics Reference Prediction -1 1 -1 144 62 1 88 207 Accuracy : 0.7006 95% CI : (0.6584, 0.7404) No Information Rate : 0.5369 P-Value [Acc > NIR] : 5.393e-14 Kappa : 0.3932 Mcnemar's Test P-Value : 0.04123 Sensitivity : 0.6207 Specificity : 0.7695 Pos Pred Value : 0.6990 Neg Pred Value : 0.7017 Prevalence : 0.4631 Detection Rate : 0.2874 Detection Prevalence : 0.4112 Balanced Accuracy : 0.6951 'Positive' Class : -1
Gráfico da variação do erro de classificação durante o treinamento:
Fig.16. Variação do erro de classificação sem pré-treinamento com o conjunto $woe
O mesmo para o conjunto /raw:
evalq({ require(darch) require(magrittr) Ln <- c(0, 16, 8, 0) nEp_1 <- 100 bp.learnRate <- c(0.5,0.7,0.1) #--param----------------------------- par_1 <- list( layers = Ln, seed = 54321, logLevel = 5, rbm.numEpochs = 0,# SRBM is not to be trained! darch.batchSize = 50, darch.numEpochs = nEp_1, darch.trainLayers = c(T,T,T), #TRUE, darch.unitFunction = c("tanhUnit","maxoutUnit", "softmaxUnit"), bp.learnRate = bp.learnRate, bp.learnRateScale = 1, darch.weightDecay = 0.0002, darch.dither = F, darch.dropout = c(0.1,0.2,0.1), darch.fineTuneFunction = backpropagation, #rpropagation backpropagation normalizeWeights = T, normalizeWeightsBound = 1, darch.weightUpdateFunction = c("weightDecayWeightUpdate", "maxoutWeightUpdate", "weightDecayWeightUpdate"), darch.dropout.oneMaskPerEpoch = T, darch.maxout.poolSize = 2, darch.maxout.unitFunction = exponentialLinearUnit, darch.elu.alpha = 2) #---train------------------------------ darch( darch = NULL, paramsList = par_1, x = DTcut[[1]]$raw %>% tbl_df %>% select(-c(Data, Class)) , y = DTcut[[1]]$raw$Class %>% as.vector(), xValid = DTcut[[2]]$raw %>% tbl_df %>% select(-c(Data, Class)) , yValid = DTcut[[2]]$raw$Class %>% as.vector() ) -> Dnn.raw.I #---test-------------------------------- xValid = DTcut[[3]]$raw %>% tbl_df %>% select(-c(Data, Class)) yValid = DTcut[[3]]$raw$Class %>% as.vector() Ypredict <- predict(Dnn.raw.I, newdata = xValid, type = "class") numIncorrect <- sum(Ypredict != yValid) cat(paste0("Incorrect classifications on all examples: ", numIncorrect, " (", round(numIncorrect/nrow(xValid)*100, 2), "%)\n")) caret::confusionMatrix(yValid, Ypredict) -> cM.raw.I }, env) #---------Ris17---------------------------------- env$cM.raw.I plot(env$Dnn.raw.I, type = "class")
Métricas:
INFO [2017-09-14 11:06:13] Classification error on Train set (best model): 30.75% (615/2000) INFO [2017-09-14 11:06:13] Train set (best model) Cross Entropy error: 1.189 INFO [2017-09-14 11:06:13] Classification error on Validation set (best model): 33.67% (337/1001) INFO [2017-09-14 11:06:13] Validation set (best model) Cross Entropy error: 1.236 INFO [2017-09-14 11:06:13] Best model was found after epoch 45 INFO [2017-09-14 11:06:13] Final 0.632 validation Cross Entropy error: 1.219 INFO [2017-09-14 11:06:13] Final 0.632 validation classification error: 32.59% INFO [2017-09-14 11:06:13] Fine-tuning finished after 35.47 secs Incorrect classifications on all examples: 161 (32.14%) > #---------Ris17---------------------------------- > env$cM.raw.I Confusion Matrix and Statistics Reference Prediction -1 1 -1 140 66 1 95 200 Accuracy : 0.6786 95% CI : (0.6358, 0.7194) No Information Rate : 0.5309 P-Value [Acc > NIR] : 1.283e-11 Kappa : 0.3501 Mcnemar's Test P-Value : 0.02733 Sensitivity : 0.5957 Specificity : 0.7519 Pos Pred Value : 0.6796 Neg Pred Value : 0.6780 Prevalence : 0.4691 Detection Rate : 0.2794 Detection Prevalence : 0.4112 Balanced Accuracy : 0.6738 'Positive' Class : -1
Chart of the classification error change:
Fig.17. Change of the classification error without pretraining with the $raw set
2.2. Análise de resultados
Vamos colocar o resultado de nossos experimentos em uma tabela:
Tipo de treinamento | Conjunto /woe | Conjunto /raw |
---|---|---|
Com pré-treinamento | 0.6687 (0.6255 - 0.7098) | 0.6826(0.6399 - 0.7232) |
Sem pré-treinamento | 0.7006(0.6589 - 0.7404) | 0.6786(0.6359 - 0.7194) |
O erro de classificação com o pré-treinamento é quase o mesmo em ambos os conjuntos. Está na faixa de 30+/-4%. Apesar de um erro menor, fica claro a partir do gráfico de variação do erro de classificação que houve uma reconversão durante o treinamento sem pré-treinamento (o erro nos conjuntos de validação e teste foi significativamente maior que o erro de treinamento). Portanto, nós usaremos o treino com o pré-treinamento em nossos experimentos adicionais.
O resultado não é muito maior do que o resultado do modelo básico. Nós temos a possibilidade de melhorar as características ao otimizar alguns hiperparâmetros. Nós vamos fazer isso no próximo artigo.
Conclusão
Apesar das limitações (por exemplo, apenas dois métodos básicos de treinamento), o pacote darch permite criar redes neurais diferentes em estrutura e parâmetros. Este pacote é uma boa ferramenta para o estudo profundo das redes neurais.
As características fracas da DNN são explicadas principalmente pelo uso dos parâmetros ou parâmetros padrão próximos a eles. O conjunto woe não mostrou vantagens antes do conjunto bruto. Portanto, no próximo artigo, nós iremos:
- otimizar uma parte dos hiperparâmetros na DNN.woe criado anteriormente;
- criaremos uma DNN, usando a biblioteca TensorFlow, testá-la e comparar os resultados com a DNN (darch);
- criaremos um conjunto de redes neurais de diferentes tipos (empacotamento, empilhamento) e veremos como isso melhora a qualidade das previsões.
Aplicação
GitHub/PartIV contém:
- FunPrepareData.R — funções usadas para a preparação de dados
- RunPrepareData.R — scripts para a preparação de dados
- Experiment.R — scripts para executar experimentos
- Part_IV.RData — imagem da área de trabalho com todos os objetos obtidos após o estágio de preparação de dados
- SessionInfo.txt — informações sobre o software usado
- Darch_default.txt — lista de parâmetros da estrutura DArch com os valores padrão
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/3473
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso