English Русский 中文 Español Deutsch 日本語
Redes Neurais Profundas (Parte I). Preparando os Dados

Redes Neurais Profundas (Parte I). Preparando os Dados

MetaTrader 5Integração | 20 setembro 2017, 09:26
3 957 0
Vladimir Perervenko
Vladimir Perervenko
Neste artigo, nós continuaremos a explorar as redes neurais profundas (RNP) que eu comecei nos artigos anteriores (1, 2, 3).

A RNP são amplamente utilizadas e intensamente desenvolvidos em muitas áreas. Os exemplos mais comuns do uso das redes neurais no dia a dia são o reconhecimento de fala, imagem e a tradução automática de um idioma para o outro. As RNPs também são usadas ​​na negociação. Dado o rápido desenvolvimento da negociação algorítmica, o estudo aprofundado das RNPs parece ser útil.

Ultimamente, os desenvolvedores trouxeram muitas novas ideias, métodos e abordagens para o uso da RNP, provando-a experimentalmente. Esta série de artigos considerará o estado e as principais direções do desenvolvimento da RNP. Muito espaço será dedicado a testar várias ideias e métodos usando experiências práticas ao lado de características qualitativas da RNP. Em nosso trabalho, nós usaremos apenas as redes multicamadas totalmente conectadas.

Os artigos terão quatro áreas de foco: 

  • Preparação, avaliação e amplificação dos dados de entrada por várias transformações.
  • Novas capacidades do pacote de darch (v.0.12). Flexibilidade e funcionalidade estendida.
  • O uso da amplificação de resultados de predição (otimização de hiperparâmetros da RNP e de conjuntos de redes neurais).
  • Capacidades gráficas para controlar o funcionamento de um Expert Advisor durante a aprendizagem e o trabalho. 

Este artigo considerará a preparação dos dados recebidos na plataforma de negociação para o uso da rede neural.

Conteúdo

Introdução

O desenvolvimento, treinamento e teste de uma rede neural profunda são realizados em estágios que possuem uma sequênciarigorosa. Semelhante a qualquer modelo de aprendizagem de máquina, o processo de criação de um RNP pode ser dividida em duas partes desiguais:

  • preparação dos dados de entrada e saída para os experimentos;
  • criação, treinamento, teste e otimização dos parâmetros da RNP.

A primeira etapa leva uma parte maior do tempo do projeto - cerca de 70%. O trabalho de uma RNP depende em grande parte do sucesso deste estágio. Afinal, lixo entra - lixo sai. É por isso que descreveremos detalhadamente a sequênciade ações nesta etapa.

Para repetir os experimentos, você precisará instalar o MRO 3.4.0 e o Rstudio. As instruções para instalar este software podem ser facilmente encontradas na internet. Os arquivos anexados a este artigo também contêm essas informações, portanto não vamos considerar isso em detalhes.


A linguagem R

Lembre-se de algumas coisas importantes sobre a R. Esta é uma linguagem de programação e um ambiente para computação gráfica e estatística. Ela foi desenvolvida em 1996 pelos cientistas neozelandeses Ross Ihaka e Robert Gentleman na Universidade de Auckland. R é um projeto GNU,ou seja, um software de código aberto. A abordagem de uso de software livre cai para os seguintes princípios (liberdades):

  • a liberdade de lançar programas para qualquer propósito (liberdade 0);
  • a liberdade de estudar como o programa funciona e adaptá-lo às necessidades do programador (liberdade 1);
  • a liberdade de distribuir cópias para que você possa ajudar o seu vizinho (liberdade 2);
  • a liberdade de melhorar o programa e distribuir a versão modificada para beneficiar toda a comunidade com a mudança.

Hoje a R está sendo melhorada e desenvolvida principalmente pela "R Development Core Team" e R Consortium fundado no ano passado. A lista dos membros do consórcio (IBM, Microsoft, Rstudio, Google, Mango, Oracle e outros) indica um bom suporte, interesse significativo e boas perspectivas da linguagem. 

Vantagens da R:

  • Hoje, R é o padrão em computação estatística.
  • Ela possui suporte e é desenvolvida pela comunidade científica mundial.
  • Um amplo conjunto de pacotes relativos a todas as direções avançadas na mineração de dados. Deve-se mencionar que o tempo entre uma publicação de uma nova ideia por parte dos cientistas e a implementação desta ideia em R não passa de duas semanas.
  • E, por último, mas não menos importante, ela é absolutamente grátis.

1. Criação dos dados iniciais (não processados)

"Todos os movimentos de preços anteriores, atuais e futuros estão no próprio preço"

Existem muitos métodos (pacotes) projetados para preparação preliminar, avaliação e escolha dos preditores. A revisão desses métodos pode ser encontrada em [1]. Sua variedade é explicada pela diversidade de dados do mundo real. O tipo de dados em uso definirá os métodos de exploração e processamento.

Nós estamos explorando os dados financeiros. Estes são hierárquicos, séries temporais regulares que são infinitas e podem ser facilmente extraídos. A linha base é a cotação em OHLCV para o instrumento no tempo gráfico específico.

Todos as outras séries temporais provêm desta linha base:

  • não paramétrica. Por exemplo, x^2, sqrt(abs(x)), x^3, -x^2 etc.
  • funcional não paramétrica. Por exemplo, sin(2*n*x), ln(abs(x)), log(Pr(t)/Pr(t-1)) etc.
  • paramétrica. Aqui temos uma série de indicadores, que são usados ​​principalmente como preditores. Eles podem ser osciladores e diferentes tipos de filtros.

Os indicadores que geram sinais (fatores) ou uma sequência de declarações condicionais produzindo um sinal podem ser usados ​​como uma variável objetivo.

1.1. Cotações

As cotações OHLC, Volume e tempo que recebemos do terminal como vetores (o, h, l, cl, v, d). Nós precisamos escrever uma função que se junte aos vetores recebidos do terminal no dataFrame. Para isso, nós mudaremos o formato da hora de início da barra para o formato POSIXct.

#---pr.OHLCV-------------------
pr.OHLCV <- function(d, o,  h,  l,  cl, v){
# (d, o,  h,  l,  cl, v)- vector
  require('magrittr')
  require('dplyr')
  require('anytime')
  price <- cbind(Data = rev(d), 
                 Open = rev(o), High = rev(h), 
                 Low = rev(l), Close = rev(cl),
                 Vol = rev(v)) %>% as.tibble()  
  price$Data %<>% anytime(., tz = "CET") 
  return(price)
}

Como os vetores da cotação foram carregados no ambiente env, vamos calcular o dataFrame pr e limpar o ambiente env de variáveis ​​não utilizadas:

evalq({pr <- pr.OHLCV(Data, Open, High, Low, Close, Volume)
       rm(list = c("Data", "Open", "High", "Low", "Close", "Volume"))
       }, 
env)

Nós queremos ver como este dataFrame se parece no início:
> head(env$pr)
# A tibble: 6 x 6
                 Data    Open    High     Low   Close
               <dttm>   <dbl>   <dbl>   <dbl>   <dbl>
1 2017-01-10 11:00:00 122.758 122.893 122.746 122.859
2 2017-01-10 11:15:00 122.860 122.924 122.818 122.848
3 2017-01-10 11:30:00 122.850 122.856 122.705 122.720
4 2017-01-10 11:45:00 122.721 122.737 122.654 122.693
5 2017-01-10 12:00:00 122.692 122.850 122.692 122.818
6 2017-01-10 12:15:00 122.820 122.937 122.785 122.920
# ... com 1 variável a mais: Vol <dbl>

e no final:

> tail(env$pr)
# A tibble: 6 x 6
                 Data    Open    High     Low   Close
               <dttm>   <dbl>   <dbl>   <dbl>   <dbl>
1 2017-05-05 20:30:00 123.795 123.895 123.780 123.888
2 2017-05-05 20:45:00 123.889 123.893 123.813 123.831
3 2017-05-05 21:00:00 123.833 123.934 123.825 123.916
4 2017-05-05 21:15:00 123.914 123.938 123.851 123.858
5 2017-05-05 21:30:00 123.859 123.864 123.781 123.781
6 2017-05-05 21:45:00 123.779 123.864 123.781 123.781
# ... com 1 variável a mais: Vol <dbl>

Assim, existem 8000 barras com a data de início 10.01.2017 e a data final 05.05.2017. Vamos adicionar variações do preço para o dataframe pr Preço MédioPreço Típico e Preço Ponderado

evalq(pr %<>% mutate(.,
                  Med = (High + Low)/2,
                  Typ = (High + Low + Close)/3,
                  Wg  = (High + Low + 2 * Close)/4,
                  #CO  = Close - Open,
                  #HO  = High - Open,
                  #LO  = Low - Open,
                  dH  = c(NA, diff(High)),
                  dL  = c(NA, diff(Low))
                  ), 
      env) 


1.2. Preditores

Nós vamos trabalhar com um conjunto de preditores simplificados. Os filtros digitais FATL, SATL, RFTL, RSTL desempenharão esse papel. Eles são descritos em detalhes no artigo de V. Kravchuk "New Adaptive Method of Following the Tendency and Market Cycles", que pode ser encontrado nos arquivos anexados a este artigo (veja o capítulo "New Tools of Technical Analysis and their Interpretation"). Eu vou listá-los aqui.

  • FATL - Fast Adaptive Trend Line;
  • SATL - Slow Adaptive Trend Line;
  • RFTL - Reference Fast Trend Line;
  • RSTL - Reference Slow Trend Line.

A taxa de variação do FATL e SATL podem ser monitoradas usando os indicadores FTLM - Fast Trend Line Momentum e STLM - Slow Trend Line Momentum.

Existem dois osciladores entre as ferramentas técnicas que nós precisaremos - os índices RBCI e PCCI. O índice RBCI (Range Bound Channel Index) é um índice de canal limitado pela largura da banda, que é calculado por meio de um filtro de canal. O filtro remove a tendência de baixa freqüência e o ruído de baixa freqüência. O índice PCCI (Perfect Commodity Channel Index) é um índice de canais de commodities perfeito.

A função que calcula os filtros digitais FATL, SATL, RFTL, RSTL é a seguinte:

#-----DigFiltr-------------------------
DigFiltr <- function(X, type = 1){
# X - vector
  require(rowr)
  fatl <- c( +0.4360409450, +0.3658689069, +0.2460452079, +0.1104506886, -0.0054034585,
             -0.0760367731, -0.0933058722, -0.0670110374, -0.0190795053, +0.0259609206,
             +0.0502044896, +0.0477818607, +0.0249252327, -0.0047706151, -0.0272432537,
             -0.0338917071, -0.0244141482, -0.0055774838, +0.0128149838, +0.0226522218,
             +0.0208778257, +0.0100299086, -0.0036771622, -0.0136744850, -0.0160483392,
             -0.0108597376, -0.0016060704, +0.0069480557, +0.0110573605, +0.0095711419,
             +0.0040444064, -0.0023824623, -0.0067093714, -0.0072003400, -0.0047717710,
             0.0005541115, 0.0007860160, 0.0130129076, 0.0040364019 )
  rftl <- c(-0.0025097319, +0.0513007762 , +0.1142800493 , +0.1699342860 , +0.2025269304 ,
            +0.2025269304, +0.1699342860 , +0.1142800493 , +0.0513007762 , -0.0025097319 ,
            -0.0353166244, -0.0433375629 , -0.0311244617 , -0.0088618137 , +0.0120580088 ,
            +0.0233183633, +0.0221931304 , +0.0115769653 , -0.0022157966 , -0.0126536111 ,
            -0.0157416029, -0.0113395830 , -0.0025905610 , +0.0059521459 , +0.0105212252 ,
            +0.0096970755, +0.0046585685 , -0.0017079230 , -0.0063513565 , -0.0074539350 ,
            -0.0050439973, -0.0007459678 , +0.0032271474 , +0.0051357867 , +0.0044454862 ,
            +0.0018784961, -0.0011065767 , -0.0031162862 , -0.0033443253 , -0.0022163335 ,
            +0.0002573669, +0.0003650790 , +0.0060440751 , +0.0018747783)
  satl <- c(+0.0982862174, +0.0975682269 , +0.0961401078 , +0.0940230544, +0.0912437090 ,
            +0.0878391006, +0.0838544303 , +0.0793406350 ,+0.0743569346 ,+0.0689666682 ,
            +0.0632381578 ,+0.0572428925 , +0.0510534242,+0.0447468229, +0.0383959950, 
            +0.0320735368, +0.0258537721 ,+0.0198005183 , +0.0139807863,+0.0084512448, 
            +0.0032639979, -0.0015350359, -0.0059060082 ,-0.0098190256 , -0.0132507215,
            -0.0161875265, -0.0186164872, -0.0205446727, -0.0219739146 ,-0.0229204861 ,
            -0.0234080863,-0.0234566315, -0.0231017777, -0.0223796900, -0.0213300463 ,-0.0199924534 ,
            -0.0184126992,-0.0166377699, -0.0147139428, -0.0126796776, -0.0105938331 ,-0.0084736770 ,
            -0.0063841850,-0.0043466731, -0.0023956944, -0.0005535180, +0.0011421469 ,+0.0026845693 ,
            +0.0040471369,+0.0052380201, +0.0062194591, +0.0070340085, +0.0076266453 ,+0.0080376628 ,
            +0.0083037666,+0.0083694798, +0.0082901022, +0.0080741359, +0.0077543820 ,+0.0073260526 ,
            +0.0068163569,+0.0062325477, +0.0056078229, +0.0049516078, +0.0161380976 )
  rstl <- c(-0.0074151919,-0.0060698985,-0.0044979052,-0.0027054278,-0.0007031702,+0.0014951741,
            +0.0038713513,+0.0064043271,+0.0090702334,+0.0118431116,+0.0146922652,+0.0175884606, 
            +0.0204976517,+0.0233865835,+0.0262218588,+0.0289681736,+0.0315922931,+0.0340614696,
            +0.0363444061,+0.0384120882,+0.0402373884,+0.0417969735,+0.0430701377,+0.0440399188,
            +0.0446941124,+0.0450230100,+0.0450230100,+0.0446941124,+0.0440399188,+0.0430701377,
            +0.0417969735,+0.0402373884,+0.0384120882,+0.0363444061,+0.0340614696,+0.0315922931,
            +0.0289681736,+0.0262218588,+0.0233865835,+0.0204976517,+0.0175884606,+0.0146922652,
            +0.0118431116,+0.0090702334,+0.0064043271,+0.0038713513,+0.0014951741,-0.0007031702,
            -0.0027054278,-0.0044979052,-0.0060698985,-0.0074151919,-0.0085278517,-0.0094111161,
            -0.0100658241,-0.0104994302,-0.0107227904,-0.0107450280,-0.0105824763,-0.0102517019,
            -0.0097708805,-0.0091581551,-0.0084345004,-0.0076214397,-0.0067401718,-0.0058083144,
            -0.0048528295,-0.0038816271,-0.0029244713,-0.0019911267,-0.0010974211,-0.0002535559,
            +0.0005231953,+0.0012297491,+0.0018539149,+0.0023994354,+0.0028490136,+0.0032221429,
            +0.0034936183,+0.0036818974,+0.0038037944,+0.0038338964,+0.0037975350,+0.0036986051,
            +0.0035521320,+0.0033559226,+0.0031224409,+0.0028550092,+0.0025688349,+0.0022682355, 
            +0.0073925495)
  if (type == 1) {k = fatl} 
  if (type == 2) {k = rftl} 
  if (type == 3) {k = satl}
  if (type == 4) {k = rstl}
  n <- length(k)
  m <- length(X)
  k <- rev(k)
  f <- rowr::rollApply(data = X, 
                       fun = function(x) {sum(x * k)},
                       window = n, minimum = n, align = "right")
  while (length(f) < m) { f <- c(NA,f)}
  return(f)
}

Depois de terem sido calculados, adicione-os ao dataframe pr

evalq(pr %<>% mutate(.,
                   fatl = DigFiltr(Close, 1),
                   rftl = DigFiltr(Close, 2),
                   satl = DigFiltr(Close, 3),
                   rstl = DigFiltr(Close, 4)
                   ),
      env) 

Adicionado os osciladores FTLM, STLM, RBCI, PCCI, suas primeiras diferenças e as primeiras diferenças dos filtros digitais no dataframe pr:

evalq(pr %<>% mutate(.,
                     ftlm = fatl - rftl,
                     rbci = fatl - satl,
                     stlm = satl - rstl,
                     pcci = Close - fatl,
                     v.fatl = c(NA, diff(fatl)),
                     v.rftl = c(NA, diff(rftl)),
                     v.satl = c(NA, diff(satl)),
                     v.rstl = c(NA, diff(rstl)*10)
                     ),
      env)
evalq(pr %<>% mutate(.,
                     v.ftlm = c(NA, diff(ftlm)),
                     v.stlm = c(NA, diff(stlm)),
                     v.rbci = c(NA, diff(rbci)),
                     v.pcci = c(NA, diff(pcci))
                    ),
      env)


1.3. Variável objetivo

O ZigZag() será usado como um indicador que gera a variável objetivo.

A função para o seu cálculo receberá as séries temporais e dois parâmetros: um comprimento mínimo de uma curva (int ou double) e o tipo do preço para cálculo (Close, Med, Typ, Wd, com (High, Low)).

#------ZZ-----------------------------------
par <- c(25, 5)
ZZ <- function(x, par) {
# x - vector
  require(TTR)
  require(magrittr)
  ch = par[1] 
  mode = par[2]
  if (ch > 1) ch <- ch/(10 ^ (Dig - 1))
  switch(mode, xx <- x$Close,
         xx <- x$Med, xx <- x$Typ,
         xx <- x$Wd, xx <- x %>% select(High,Low))
  zz <- ZigZag(xx, change = ch, percent = F, 
               retrace = F, lastExtreme = T)
  n <- 1:length(zz)
  for (i in n) { if (is.na(zz[i])) zz[i] = zz[i - 1]}
  return(zz)
}

Calcule o ZigZag, a primeira diferença, o sinal da primeira diferença e adiciona-os ao dataframepr:

evalq(pr %<>% cbind(., zigz = ZZ(., par = par)), env)
evalq(pr %<>% cbind(., dz = diff(pr$zigz) %>% c(NA, .)), env) 
evalq(pr %<>% cbind(., sig = sign(pr$dz)), env)

1.4.Conjunto inicial de dados

Vamos resumir os dados que devemos ter como resultado dos cálculos.

Nós recebemos do terminal os vetores OHLCV e uma marca temporária de início da barra no tempo gráfico M15 para o EURJPY. Esses dados formaram o dataframe pr. As variáveis FATL, SATL, RFTL, RSTL, FTLM, STLM, RBCI, PCCI e suas primeiras diferenças foram adicionadas a este dataframe. O ZigZag com uma alavancagem mínima de 25 pontos (4 casas decimais), sua primeira diferença e o sinal da primeira diferença (-1,1), que será usado como sinal, foram adicionados ao dataframe também.

Todos esses dados foram carregados não no ambiente global, mas em um novo ambiente filho env, onde todos os cálculos serão realizados. Esta divisão permitirá o uso de conjuntos de dados de diferentes símbolos ou tempos gráficos sem conflitos de nomes durante o cálculo.

A estrutura do conjunto de dados total pr é exibida abaixo. As variáveis, necessárias para os seguintes cálculos, podem ser facilmente extraídas deste.

str(env$pr)
'data.frame':   8000 obs. of  30 variables:
 $ Data  : POSIXct, format: "2017-01-10 11:00:00" ...
 $ Open  : num  123 123 123 123 123 ...
 $ High  : num  123 123 123 123 123 ...
 $ Low   : num  123 123 123 123 123 ...
 $ Close : num  123 123 123 123 123 ...
 $ Vol   : num  3830 3360 3220 3241 3071 ...
 $ Med   : num  123 123 123 123 123 ...
 $ Typ   : num  123 123 123 123 123 ...
 $ Wg    : num  123 123 123 123 123 ...
 $ dH    : num  NA 0.031 -0.068 -0.119 0.113 ...
 $ dL    : num  NA 0.072 -0.113 -0.051 0.038 ...
 $ fatl  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ rftl  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ satl  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ rstl  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ ftlm  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ rbci  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stlm  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ pcci  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.fatl: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.rftl: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.satl: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.rstl: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.ftlm: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.stlm: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.rbci: num  NA NA NA NA NA NA NA NA NA NA ...
 $ v.pcci: num  NA NA NA NA NA NA NA NA NA NA ...
 $ zigz  : num  123 123 123 123 123 ...
 $ dz    : num  NA -0.0162 -0.0162 -0.0162 -0.0162 ...
 $ sig   : num  NA -1 -1 -1 -1 -1 -1 -1 -1 -1 ...


Selecione todos os preditores calculados anteriormente a partir do dataframe DataSet . Converte a variável objetivo sig em um fator e move uma barra para a frente (no futuro).

evalq(dataSet <- pr %>% tbl_df() %>%
        dplyr::select(Data, ftlm, stlm, rbci, pcci,
                      v.fatl, v.satl, v.rftl, v.rstl,
                      v.ftlm, v.stlm, v.rbci, v.pcci, sig) %>%
        dplyr::filter(., sig != 0) %>% 
        mutate(., Class = factor(sig, ordered = F) %>% 
                 dplyr::lead()) %>% 
        dplyr::select(-sig),
      env)


Visualizando a análise de dados

Desenha o gráfico OHLC usando o pacote ggplot2. Pega os dados nos últimos dois dias e desenha um gráfico de cotações em barras.

evalq(pr %>% tail(., 200) %>%
        ggplot(aes(x = Data, y = Close)) +
        geom_candlestick(aes(open = Open, high = High, low = Low, close = Close)) +
        labs(title = "EURJPY Candlestick Chart", y = "Close Price", x = "") + 
        theme_tq(), env)


Ris1

Fig.1. Gráfico de cotações

Desenha o FATL, SATL, RFTL, RSTL ZZ:gráfico

evalq(pr %>% tail(., 200) %>%
        ggplot(aes(x = Data, y = Close)) +
        geom_candlestick(aes(open = Open, high = High, low = Low, close = Close)) +
        geom_line(aes(Data, fatl), color = "steelblue", size = 1) +
        geom_line(aes(Data, rftl), color = "red", size = 1) +
        geom_line(aes(Data, satl), color = "gold", size = 1) +
        geom_line(aes(Data, rstl), color = "green", size = 1) +
        geom_line(aes(Data, zigz), color = "black", size = 1) +
        labs(title = "EURJPY Candlestick Chart", 
             subtitle = "Combining Chart Geoms",
             y = "Close Price", x = "") + 
        theme_tq(), env)


Ris2

Fig.2. FATL, SATL, RFTL, RSTL ZZ

Divide os osciladores em três grupos para uma representação mais conveniente.

require(dygraphs)
evalq(dataSet %>% tail(., 200) %>% tk_tbl %>%
        select(Data, ftlm, stlm, rbci, pcci) %>%
        tk_xts() %>% 
        dygraph(., main = "Oscilator base") %>% 
        dyOptions(., 
                  fillGraph = TRUE, 
                  fillAlpha = 0.2,
                  drawGapEdgePoints = TRUE,
                  colors = c("green", "violet", "red", "blue"),
                  digitsAfterDecimal = Dig) %>%
        dyLegend(show = "always", 
                 hideOnMouseOut = TRUE), 
      env)


Ris3

Fig.3. Base oscillators

evalq(dataSet %>% tail(., 200) %>% tk_tbl %>%
        select(Data, v.fatl, v.satl, v.rftl, v.rstl) %>%
        tk_xts() %>% 
        dygraph(., main = "Oscilator 2") %>% 
        dyOptions(., 
                  fillGraph = TRUE, 
                  fillAlpha = 0.2,
                  drawGapEdgePoints = TRUE,
                  colors = c("green", "violet", "red", "darkblue"),
                  digitsAfterDecimal = Dig) %>%
        dyLegend(show = "always", 
                 hideOnMouseOut = TRUE), 
      env)


Ris4

Fig.4. Osciladores do segundo grupo

Os osciladores do terceiro grupo serão desenhados nas últimas 100 barras:

evalq(dataSet %>% tail(., 100) %>% tk_tbl %>%
        select(Data, v.ftlm, v.stlm, v.rbci, v.pcci) %>%
        tk_xts() %>% 
        dygraph(., main = "Oscilator 3") %>% 
        dyOptions(., 
                  fillGraph = TRUE, 
                  fillAlpha = 0.2,
                  drawGapEdgePoints = TRUE,
                  colors = c("green", "violet", "red", "darkblue"),
                  digitsAfterDecimal = Dig) %>%
        dyLegend(show = "always", 
                 hideOnMouseOut = TRUE), 
      env)


Ris5

Fig.5. Osciladores do terceiro grupo

2.Exploração da análise de dados, EDA

"Não há questões estatísticas triviais, há procedimentos estatísticos duvidosos." - Sir David Cox

"Uma resposta aproximada ao problema certo vale muito mais do que uma resposta exata para um problema aproximado". — John Tukey

Nós estamos usando a EDA para desenvolver a compreensão dos dados em uso. A maneira mais simples de fazer isso é usar as perguntas como ferramenta de pesquisa. Quando fazemos uma pergunta, nós estamos focados em uma certa parte dos dados. Isso ajudará a decidir quais gráficos, modelos e transformações nós devemos usar.

A EDA é essencialmente um processo criativo. Semelhante aos processos mais criativos, a chave para fazer uma boa pergunta é criar ainda mais perguntas. É difícil fazer perguntas fundamentais no início da análise, pois não sabemos quais as conclusões que o conjunto de dados contém. Por outro lado, cada nova questão que perguntamos, é destacado um novo aspecto dos dados, aumentando nossas chances de fazer uma descoberta. Nós podemos rapidamente mudar para a parte mais interessante do conjunto de dados e esclarecer a situação fazendo perguntas sequenciais.

Não há regras para quais questões nós devemos pedir para estudar os dados. Dito isto, existem dois tipos de perguntas que serão úteis:

  • Qual tipo de alteração minhas variáveis estão ​​passando?
  • Que tipo de covariação está ocorrendo entre as variáveis?

Vamos definir o conceito principal.

Variações são a tendência que os valores de uma variável tem a mudar em diferentes medidas. Há muitos exemplos de variações na vida cotidiana. Se você medir qualquer variável contínua sete vezes, você terá sete valores diferentes. Isso é verdade mesmo para constantes, por exemplo, a velocidade da luz. Cada medida conterá pequenos erros que serão diferentes a cada vez. Variáveis ​​do mesmo tipo também podem mudar. Por exemplo, a cor do olho de diferentes pessoas ou o nível de energia elétrica em diferentes momentos. Cada variável possui seu próprio caráter de variações que podem revelar informações interessantes. A melhor maneira de entender essa informação é visualizar a distribuição dos valores das variáveis. Este é um caso em que um diagrama é melhor do que mil palavras.

2.1.Estatísticas totais

A estatística total de uma série temporal é conveniente para rastrear usando a função table.Stats()::PerformenceAnalitics.

> table.Stats(env$dataSet %>% tk_xts())
Using column `Data` for date_var.
                     ftlm      stlm      rbci      pcci
Observations    7955.0000 7908.0000 7934.0000 7960.0000
NAs               42.0000   89.0000   63.0000   37.0000
Minimum           -0.7597   -1.0213   -0.9523   -0.5517
Quartile 1        -0.0556   -0.1602   -0.0636   -0.0245
Median            -0.0001    0.0062   -0.0016   -0.0001
Arithmetic Mean    0.0007    0.0025    0.0007    0.0001
Geometric Mean    -0.0062       NaN   -0.0084   -0.0011
Quartile 3         0.0562    0.1539    0.0675    0.0241
Maximum            2.7505    3.0407    2.3872    1.8859
SE Mean            0.0014    0.0033    0.0015    0.0006
LCL Mean (0.95)   -0.0020   -0.0040   -0.0022   -0.0010
UCL Mean (0.95)    0.0034    0.0090    0.0035    0.0012
Variance           0.0152    0.0858    0.0172    0.0026
Stdev              0.1231    0.2929    0.1311    0.0506
Skewness           4.2129    1.7842    2.3037    6.4718
Kurtosis          84.6116   16.7471   45.0133  247.4208
                   v.fatl    v.satl    v.rftl    v.rstl
Observations    7959.0000 7933.0000 7954.0000 7907.0000
NAs               38.0000   64.0000   43.0000   90.0000
Minimum           -0.3967   -0.0871   -0.1882   -0.4719
Quartile 1        -0.0225   -0.0111   -0.0142   -0.0759
Median            -0.0006    0.0003    0.0000    0.0024
Arithmetic Mean    0.0002    0.0002    0.0002    0.0011
Geometric Mean    -0.0009    0.0000   -0.0003   -0.0078
Quartile 3         0.0220    0.0110    0.0138    0.0751
Maximum            1.4832    0.3579    0.6513    1.3093
SE Mean            0.0005    0.0002    0.0003    0.0015
LCL Mean (0.95)   -0.0009   -0.0003   -0.0005   -0.0020
UCL Mean (0.95)    0.0012    0.0007    0.0009    0.0041
Variance           0.0023    0.0005    0.0009    0.0188
Stdev              0.0483    0.0219    0.0308    0.1372
Skewness           5.2643    2.6705    3.9472    1.5682
Kurtosis         145.8441   36.9378   74.4182   13.5724
                   v.ftlm    v.stlm    v.rbci    v.pcci
Observations    7954.0000 7907.0000 7933.0000 7959.0000
NAs               43.0000   90.0000   64.0000   38.0000
Minimum           -0.9500   -0.2055   -0.6361   -1.4732
Quartile 1        -0.0280   -0.0136   -0.0209   -0.0277
Median            -0.0002   -0.0001   -0.0004   -0.0002
Arithmetic Mean    0.0000    0.0001    0.0000    0.0000
Geometric Mean    -0.0018   -0.0003   -0.0009       NaN
Quartile 3         0.0273    0.0143    0.0207    0.0278
Maximum            1.4536    0.3852    1.1254    1.9978
SE Mean            0.0006    0.0003    0.0005    0.0006
LCL Mean (0.95)   -0.0012   -0.0005   -0.0009   -0.0013
UCL Mean (0.95)    0.0013    0.0007    0.0009    0.0013
Variance           0.0032    0.0007    0.0018    0.0034
Stdev              0.0561    0.0264    0.0427    0.0579
Skewness           1.2051    0.8513    2.0643    3.0207
Kurtosis          86.2425   23.0651   86.3768  233.1964

Aqui está o que esta tabela nos diz:

  • Todos os preditores têm um número relativamente pequeno de variáveis ​​indefinidas NA.
  • Todos os preditores têm uma pronunciada assimetria direita.
  • Todos os preditores têm uma alta curtose.

2.2.Visualizando as estatísticas totais

"O maior valor de uma imagem é quando isso nos obriga a notar o que nunca esperamos ver". — John Tukey

Vejamos a variação e covariação entre as variáveis ​​no conjunto de dados. Como o número de variáveis ​​(14) não nos permite representá-las em um gráfico, eles terão que ser divididos em três grupos.

require(GGally)
evalq(ggpairs(dataSet, columns = 2:6, 
              mapping = aes(color = Class),
              title = "DigFilter1"), 
      env)


digFilter 1

Fig. 6. Primeiro grupo de preditores

evalq(ggpairs(dataSet, columns = 7:10, 
              mapping = aes(color = Class),
              title = "DigFilter2"), 
      env)


digFilter 2

Fig. 7. Segundo grupo de preditores

evalq(ggpairs(dataSet, columns = 11:14, 
              mapping = aes(color = Class),
              title = "DigFilter3"), 
      env)


digFilter 3

Fig. 8. Terceiro grupo de preditores

Isto é o que devemos ver nos gráficos:

  • Todos os preditores têm a forma de distribuições próximas ao normal, embora haja uma assimetria direita bem pronunciada;
  • Todos os preditores têm uma faixa interquartil muito estreita (IQR);
  • Todos os preditores têm outliers proeminentes;
  • o número de exemplos em dois níveis da variável objetivo "Class" tem uma pequena diferença.

3.Preparação dos dados

Normalmente, a preparação dos dados tem sete estágios:

  • "Imputação" — remoção ou imputação de dados perdidos/indefinidos;
  • "Variância" — remoção de variáveis ​​com dispersão zero ou quase zero;
  • "Dividir" — dividir o conjunto de dados nos subconjuntos train/valid/test;
  • "Dimensionamento" — escalando o intervalo de variáveis;
  • "Outliers" — remoção ou entrada de outliers;
  • "Amostragem" — correção do desequilíbrio da classe;
  • "Denoise" — remoção ou redefinição de ruído;
  • "Seleção" — selecionando preditores irrelevantes.

3.1. Limpeza de dados

A primeira etapa da preparação dos dados brutos é a remoção ou imputação de valores indefinidos e lacunas nos dados. Embora muitos modelos permitam o uso de dados indefinidos (NA) e lacunas nos conjuntos de dados, é melhor excluí-los antes de iniciar as ações principais. Esta operação é realizada para o conjunto de dados completo, independentemente do modelo.

As estatísticas totais de nossos dados brutos indicaram que o conjunto de dados contém NA. Estes são artificiais A, que apareceram ao calcular os filtros digitais. Não há muitos deles para que eles possam ser excluídos. Nós já obtivemos a base de dados pronta para posterior processamento. Vamos limpá-la.

Em um caso geral, a limpeza significa as seguintes operações:

  • remoção de preditores com uma dispersão zero ou quase zero (method = c(“zv”, “nzv”));
  • remoção de variáveis ​​altamente correlacionadas. Cabe ao usuário definir o limite para o coeficiente de correlação (method = “corr”). Seu valor padrão é igual a 0.9. Este estágio nem sempre é necessário. Depende dos seguintes métodos de transformação;
  • remoção de preditores que possuem apenas um valor exclusivo em qualquer classe (method = “conditionalX”).

Todas essas operações são implementadas na função preProcess()::caret através dos métodos considerados acima. Essas operações são realizadas para a base de dados completa antes da divisão nos conjuntos de treinamento e teste.

require(caret)
evalq({preProClean <- preProcess(x = dataSet,method = c("zv", "nzv", "conditionalX", "corr"))
      dataSetClean <- predict(preProClean, dataSet %>% na.omit)},
env)

Deixe-nos ver se há algum preditor excluído e o que temos após a limpeza:

> env$preProClean$method$remove
#[1] "v.rbci" 
> dim(env$dataSetClean)
[1] 7906   13
> colnames(env$dataSetClean)
 [1] "Data"   "ftlm"   "stlm"   "rbci"   "pcci"  
 [6] "v.fatl" "v.satl" "v.rftl" "v.rstl" "v.ftlm"
[11] "v.stlm" "v.pcci" "Class"

3.2. Identificando e processando os outliers

Problemas com a qualidade dos dados, tais como a assimetria e os valores atípicos (outliers), geralmente são interligados e interdependentes. Isso não só faz um processamento preliminar de dados que consome tempo, mas também dificulta a busca de correlações e tendências no conjunto de dados.

O que são outliers?

Vamos concordar que um outlier é uma observação muito distante de outras observações. Uma classificação detalhada de outliers, seus métodos de identificação e processamento são descritos em [2].

Tipos de outliers

Os outliers causam distorções significativas na distribuição de variáveis ​​e treinam um modelo usando tais dados. Existem muitos métodos de identificação e processamento de valores atípicos. A escolha do método depende principalmente de identificarmos ou não o local a nível local ou global. Os outliers locais são valores atípicos de uma variável. Os outliers globais são valores atípicos em um espaço multidimensional definido por uma matriz ou um dataframe.

O que causa os outliers?

Os outliers podem ser divididos por origem:

Artificial

  • erros de entrada de dados. Aqui pertencem os erros ocorridos durante a coleta, gravação e processamento de dados;
  • erros experimentais;
  • erros de amostragem.

Erros naturais causados ​​pela natureza da variável.

Qual o impacto que os outliers possuem?

Os outliers podem arruinar os resultados da análise de dados e modelagem estatística. Isso aumenta a dispersão de erros e diminui o poder estatístico dos testes. Se os outliers não são distribuídos aleatoriamente, eles podem reduzir a normalidade. Os outliers também podem influenciar a assunção principal de análises de regressão e dispersão, juntamente com outros pressupostos estatísticos do modelo.

Como podemos identificar os valores atípicos locais?

Normalmente, os outliers podem ser revelados através da visualização de dados. Um dos métodos mais simples e amplamente utilizados é o boxplot. Vamos levar o preditor ftlm como um exemplo:

evalq(ggplot(dataSetClean, aes(x = factor(0), 
                               y = ftlm,
                               color = 'red')) + 
        geom_boxplot() + xlab("") + 
        scale_x_discrete(breaks = NULL) + 
        coord_flip(),
      env)


Outlier ftlm

Fig.9. Boxplot ftlm

Alguns comentários ao diagrama:

IQR é a faixa interquartil ou a distância entre o primeiro e o terceiro quartil.

Desta forma, nós podemos definir os outliers de várias maneiras:

  • Qualquer valor menor que -1.5*IQR e maior que +1.5*IQR é um valor atípico. Às vezes, o coeficiente é definido como 2 ou 3. Todos os valores entre 1.5*IQR e 3*IQR são chamados de outliers médios e os valores acima de3*IQR são chamados de outliers extremos.
  • Qualquer valor que parece estar fora do 5º e 95º percentil pode ser considerado um valor atípico,
  • Os pontos traçados três ou mais MSD longe são também outliers.

Avançando, nós vamos usar a primeira definição de outliers - através do IQR.

Como os outliers podem ser processados?

A maioria dos métodos de processamento de outliers são semelhantes aos métodos de processamento de NA - removendo as observações, transformando as observações, segmentando, imputando e outros.

  • Remoção dos outliers. Nós removemos os valor atípicos se eles aparecem como resultado de um erro de entrada de dados ou se o número de outliers é muito pequeno. Nós também podemos cortar as extremidades da distribuição para remover os outliers. Por exemplo, nós podemos descartar 1% de cima e de baixo.

  • Transformação e vinculação:
    • a transformação de variáveis ​​pode excluir os outliers (isto será analisado na próxima parte do artigo);
    • o logaritmo natural diminui os casos de mudanças pelos valores extremos (isso também será discutido em detalhes na próxima parte do artigo);
    • a discretização também é uma maneira de transformar uma variável (veja a próxima parte);
    • nós também podemos usar a atribuição de peso para as observações (não discutiremos isso neste artigo).

  • Imputação. Os mesmos métodos que usamos para imputar valores indefinidos podem ser usados ​​para imputar os outliers. Para isso, a média, a mediana e o modo podem ser usados. Antes de imputar os valores, é necessário estabelecer se o outlier é natural ou artificial. Se o outlier for artificial, ele pode ser imputado.

Se a amostra contiver um número significativo de outliers, elas devem ser analisadas separadamente em um modelo estatístico. Vamos discutir os métodos gerais utilizados para enfrentar os outliers. Eles são a remoção e a imputação.

Remoção dos outliers

Os outliers devem ser excluídos se forem causados ​​pela entrada de dados, o processamento de dados ou se o número de outliers for muito pequeno (somente quando se identificam métricas de variáveis ​​estatísticas).

Os dados de uma variável (ftlm, por exemplo) podem ser extraídos sem outliers da seguinte maneira:

evalq({dataSetClean$ftlm -> x  
  out.ftlm <- x[!x %in% boxplot.stats(x)$out]}, 
  env)

Or:

evalq({dataSetClean$ftlm -> x 
  out.ftlm1 <- x[x > quantile(x, .25) - 1.5*IQR(x) & 
          x < quantile(x, .75) + 1.5*IQR(x)]},
  env) 


Eles são idênticos?

> evalq(all.equal(out.ftlm, out.ftlm1), env)
[1] TRUE

Quantos outliers existem no conjunto de dados?

> nrow(env$dataSetClean) - length(env$out.ftlm)
[1] 402 

Isto é o como o ftlm aparenta sem os outliers:

boxplot(env$out.ftlm, main = "ftlm  without outliers", 
        boxwex = 0.5)


Outlier 2

Fig. 10. ftlm sem outliers

O método descrito acima não é adequado para matrizes e matrizes de dados, pois cada variável em um dataframe pode ter um número diferente de valores atípicos. Um método de substituição de valores atípicos locais para NA seguido de métodos padrão de processamento de NA é adequado para tais amostras. A função que substituirá os outliers locais por NA é exibida abaixo:

#-------remove_outliers-------------------------------
remove_outliers <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs = c(.25, .75), 
                  na.rm = na.rm, ...)
  H <- 1.5 * IQR(x, na.rm = na.rm)
  y <- x
  y[x < (qnt[1] - H)] <- NA
  y[x > (qnt[2] + H)] <- NA
  y
}


Vamos mudar dataSetClean em todas as variáveis, exceto em c(Data, Class), e os outliers para NA. Tendo feito isso, vamos ver como a distribuição do novo conjunto x.out:se altera.

evalq({
  dataSetClean %>% select(-c(Data,Class)) %>% as.data.frame() -> x 
  foreach(i = 1:ncol(x), .combine = "cbind") %do% {
    remove_outliers(x[ ,i])
  } -> x.out
  colnames(x.out) <- colnames(x)
  },  
env)
par(mfrow = c(1, 1))
chart.Boxplot(env$x, 
              main = "x.out with outliers",
              xlab = "")

Outlier 3

Fig. 11. Dados com outliers

chart.Boxplot(env$x.out, 
              main = "x.out without outliers",
              xlab = "")

Outlier 4

Fig.12. Dados sem outliers

Imputando o NA que apareceu em vez dos outliers

A imputação é uma substituição de valores que faltam, incorretos ou inválidos por outros valores. Os dados de entrada para treinamento do modelo devem conter apenas valores válidos. Você também pode:

  • substituir NA pela média, mediana, mod (as características estatísticas do conjunto não mudarão)
  • substituir os outliers superiores a 1,5*IQR por um percentil de 0,95 e os outliers menores que -1,5*IQR por um percentil de 0,05.

Vamos escrever uma função para executar a última versão da ação. Após a transformação ter sido feita, vamos dar uma olhada na distribuição:

#-------capping_outliers-------------------------------
capping_outliers <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs = c(.25, .75), 
                  na.rm = na.rm, ...)
  caps <- quantile(x, probs = c(.05, .95), 
                   na.rm = na.rm, ...)
  H <- 1.5 * IQR(x, na.rm = na.rm)
  y <- x
  y[x < (qnt[1] - H)] <- caps[1] 
  y[x > (qnt[2] + H)] <- caps[2] 
  y
}

evalq({dataSetClean %>% select(-c(Data,Class)) %>%
    as.data.frame() -> x 
    foreach(i = 1:ncol(x), .combine = "cbind") %do% {
      capping_outliers(x[ ,i])
    } -> x.cap
    colnames(x.cap) <- colnames(x)
   },  
env)
chart.Boxplot(env$x.cap, 
              main = "x.cap with capping outliers",
              xlab = "")




Outlier 5

Fig.13. Conjunto de dados com outliers imputados

Consideremos a variação e covariação no tampão de DataSet. Isso é o mesmo que o dataSet, mas limpo e contendo outliers locais imputados. O número de variáveis ​​(13) torna impossível colocá-las no mesmo gráfico, então elas devem ser divididas em dois grupos.

evalq(x.cap %>% tbl_df() %>% 
        cbind(Data = dataSetClean$Data, .,
              Class = dataSetClean$Class) -> 
        dataSetCap, 
      env)
require(GGally)
evalq(ggpairs(dataSetCap, columns = 2:7, 

              mapping = aes(color = Class),
              title = "PredCap1"), 
      env)


Outlier 6


Fig.14. Variação e covariação da primeira parte do conjunto de dados com os outliers imputados.

 E a segunda parte do conjunto:

evalq(ggpairs(dataSetCap, columns = 8:13, 
              mapping = aes(color = Class),
              title = "PredCap2"), 
      env)


Outlier 7

Fig.15. Variação e covariação da segunda parte do conjunto de dados com os outliers imputados

Como identificar os outliers globais?

Os outliers bidimensionais ou multidimensionais geralmente são identificados usando o índice de impacto ou proximidade. Várias distâncias são usadas para identificar os valores atípicos globais. Pacotes como DMwR, mvoutliers, Rlof podem ser usados ​​para isso. Os outliers globais são avaliados com LOF (local outlier factor). Calcula e compara LOF para um conjunto com outliers x e um conjunto com outliers imputados x.cap.

##------DMwR2-------------------
require(DMwR2)
evalq(lof.x <- lofactor(x,10), env)
evalq(lof.x.cap <- lofactor(x.cap,10), env)
par(mfrow = c(1, 3))
boxplot(env$lof.x, main = "lof.x", 
        boxwex = 0.5)
boxplot(env$lof.x.cap, main = "lof.x.cap", 
        boxwex = 0.5)
hist(env$lof.x.cap, breaks = 20)
par(mfrow = c(1, 1))


LOF 1

Fig.16. Fator outlier global para um conjunto de dados com outliers e um conjunto de dados com outliers imputados

A função lof() é implementada no pacote Rlof. ele encontra o fator outlier local [3] dos dados da matriz usando k vizinhos mais próximos. O fator outlier local (LOF) é a probabilidade de pertencer aos outliers que são calculados a cada observação. Com base nessa probabilidade, o usuário decide se a observação é um outlier.

O LOF leva em consideração a densidade local para identificar se a observação é um outlier. Esta é uma implementação mais eficiente do LOF usando outra estrutura de dados e funções de cálculo da distância para comparar com a função lofactor() disponível no pacote "dprep". Isto suportará vários valores de k que serão calculados simultaneamente, e várias medidas de distância além do padrão Euclidiano. Os cálculos são realizados simultaneamente em vários núcleos do processador. Vamos calcular o lofactor para os mesmos dois conjuntos (x e x.cap) para 5, 6, 7, 8, 9 e 10 vizinhos usando o método "minkowski" de cálculo da distância. Vamos desenhar os histogramas desses fatores.

require(Rlof)
evalq(Rlof.x <- lof(x, c(5:10), cores = 2,
                       method = 'minkowski'),
        env)
  evalq(Rlof.x.cap <- lof(x.cap, c(5:10), 
                          cores = 2, 
                          method = 'minkowski'),
        env)
par(mfrow = c(2, 3))  
hist(env$Rlof.x.cap[ ,6], breaks = 20)
hist(env$Rlof.x.cap[ ,5], breaks = 20)
hist(env$Rlof.x.cap[ ,4], breaks = 20)
hist(env$Rlof.x.cap[ ,3], breaks = 20)
hist(env$Rlof.x.cap[ ,2], breaks = 20)
hist(env$Rlof.x.cap[ ,1], breaks = 20)
par(mfrow = c(1, 1))


 

LOF 2

Fig.17. Fator outlier global para k vizinhos

 Quase todas as observações estão dentro do alcance lofactor =1.6. Fora desta faixa:

> sum(env$Rlof.x.cap[ ,6] >= 1.6)
[1] 32


Este é um número insignificante de valores aberrantes moderados para um conjunto desse tamanho.

Nota. Para identificar os limites de alcance, excedendo o que a observação será tratada como um outlier, deve-se usar um conjunto de dados de treinamento. O valor das variáveis ​​do conjunto de dados de teste/validação é processado usando os parâmetros obtidos por meio do conjunto de treinamento. Quais parâmetros são estes? Estes são os limites upper = 1,5*IQR, lower = -1,5*IQR e cap = c (0,05, 0,95) percentil. Nós os usamos em nossos cálculos anteriores. Se fossem utilizados outros métodos de cálculo dos limites do intervalo e da imputação de outliers, eles devem ser definidos para o conjunto de dados de treinamento, guardados e armazenados para o processamento dos conjuntos de dados de validação e teste.

Vamos escrever a função que realizará os cálculos preliminares:

#-----prep.outlier--------------
prep.outlier <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs = c(.25, .75), 
                  na.rm = na.rm, ...)
  H <- 1.5 * IQR(x, na.rm = na.rm)
  caps <- quantile(x, probs = c(.05, .95), 
                   na.rm = na.rm, ...)
  list(lower = qnt[1] - H, upper = qnt[2] + H, 
       med = median(x), 
       cap1 = caps[1], cap2 = caps[2])
}


Calcule os parâmetros necessários para identificar e imputar os outliers. Deixe o comprimento preliminar do conjunto de treinamento ser as primeiras 4000 barras e as seguintes 2000 barras serão usadas como o conjunto de dados de teste.

evalq(
  {train <- x[1:4000, ] 
  foreach(i = 1:ncol(train), .combine = "cbind") %do% {
    prep.outlier(train[ ,i]) %>% unlist()
  } -> pre.outl
  colnames(pre.outl) <- colnames(x)
  #pre.outl %<>% t()
  },  
  env)


Vejamos o resultado:

> env$pre.outl
                   ftlm        stlm         rbci          pcci
lower.25% -0.2224942912 -0.59629203 -0.253231002 -9.902232e-02
upper.75%  0.2214486206  0.59242529  0.253529797  9.826936e-02
med       -0.0001534451  0.00282525 -0.001184966  8.417127e-05
cap1.5%   -0.1700418145 -0.40370452 -0.181326658 -6.892085e-02
cap2.95%   0.1676526431  0.39842675  0.183671973  6.853935e-02
                 v.fatl        v.satl        v.rftl        v.rstl
lower.25% -0.0900973332 -4.259328e-02 -0.0558921804 -0.2858430788
upper.75%  0.0888110249  4.178418e-02  0.0555115004  0.2889057397
med       -0.0008581219 -2.130064e-05 -0.0001707447 -0.0001721546
cap1.5%   -0.0658731640 -2.929586e-02 -0.0427927888 -0.1951978435
cap2.95%   0.0662353821  3.089833e-02  0.0411091859  0.1820803387
                 v.ftlm        v.stlm        v.pcci
lower.25% -0.1115823754 -5.366875e-02 -0.1115905239
upper.75%  0.1108670403  5.367466e-02  0.1119495436
med       -0.0003560178 -6.370034e-05 -0.0003173464
cap1.5%   -0.0765431363 -3.686945e-02 -0.0765950814
cap2.95%   0.0789209957  3.614423e-02  0.0770439553


Como podemos ver, primeiro e terceiro quartis e mediana junto com o 5º e 95º percentil são definidos para cada variável no conjunto. Isso é tudo o que é necessário para identificar e processar os outliers.

Nós precisamos de uma função para processar os outliers de qualquer conjunto de dados usando os parâmetros previamente definidos. Possíveis formas de processamento: substituição de valores para NA, substituindo os outliers pela mediana e substituindo os outliers pelo percentil 5/95.

#---------treatOutlier---------------------------------
  treatOutlier <- function(x, impute = TRUE, fill = FALSE,
                         lower, upper, med, cap1, cap2){ 
  if (impute) {
    x[x < lower] <- cap1 
    x[x > upper] <- cap2 
    return(x)
  }
  if (!fill) {
    x[x < lower | x > upper] <- NA 
    return(x)  
  } else {
    x[x < lower | x > upper] <- med
    return(x)
  }
} 


À medida que definimos os parâmetros necessários para o conjunto de treinamento, vamos processar os outliers do conjunto de treinamento, substituindo-os pelo 5º/95º percentil. Em seguida, processe os outliers do conjunto de dados de teste. Compare as distribuições nos conjuntos obtidos tendo desenhado três gráficos.

#------------
evalq(
  {
  foreach(i = 1:ncol(train), .combine = 'cbind') %do% {
    stopifnot(exists("pre.outl", envir = env))
    lower = pre.outl['lower.25%', i] 
    upper = pre.outl['upper.75%', i]
    med = pre.outl['med', i]
    cap1 = pre.outl['cap1.5%', i] 
    cap2 = pre.outl['cap2.95%', i] 
    treatOutlier(x = train[ ,i], impute = T, fill = T, lower = lower,
                 upper = upper, med = med, cap1 = cap1, cap2 = cap2) 
  } -> train.out
  colnames(train.out) <- colnames(train)
  },
  env
) 
#-------------
evalq(
  {test <- x[4001:6000, ] 
  foreach(i = 1:ncol(test), .combine = 'cbind') %do% {
    stopifnot(exists("pre.outl", envir = env))
    lower = pre.outl['lower.25%', i] 
    upper = pre.outl['upper.75%', i]
    med = pre.outl['med', i]
    cap1 = pre.outl['cap1.5%', i] 
    cap2 = pre.outl['cap2.95%', i] 
    treatOutlier(x = test[ ,i], impute = T, fill = T, lower = lower,
                 upper = upper, med = med, cap1 = cap1, cap2 = cap2) 
  } -> test.out
  colnames(test.out) <- colnames(test)
  },
  env
)
#---------------
evalq(boxplot(train, main = "train  with outliers"), env)
evalq(boxplot(train.out, main = "train.out  without outliers"), env)
evalq(boxplot(test.out, main = "test.out  without outliers"), env)
#------------------------


Outlier 8

Fig.18. Conjunto de dados de treinamento com os outliers

Outlier 9

Fig.19. Conjunto de dados de treinamento com os outliers imputados

Outlier 10

Fig.20. Conjunto de dados de teste com os outliers imputados

Nem todos os modelos são sensíveis aos outliers. Por exemplo, os modelos como a determinação de árvores (DT) e as florestas aleatórias (RF) são insensíveis a elas. 

Ao definir e processar os outliers, alguns outros pacotes podem ser úteis. São eles: “univOutl”, “mvoutlier”, “outlier”, funModeling::prep.outlier().

3.3. Eliminação da assimetria


Skewness (assimetria) é a indicação da forma de distribuição. O cálculo do coeficiente de assimetria de uma variável é uma maneira geral de avaliar isso. Geralmente, a assimetria negativa mostra que a média é menor do que a mediana e a distribuição deixou a assimetria. Assimetria positiva indica que a média é maior do que a mediana e a distribuição tem uma assimetria correta.

Se a assimetria do preditor é 0, os dados são absolutamente simétricos.
Se a assimetria do preditor for menor que -1 ou superior a +1, os dados são significativamente distorcidos.
Se a assimetria do preditor estiver entre -1 e -1/2 ou +1 e +1/2, os dados são moderadamente distorcidos.
Se a assimetria do preditor for igual a -1/2 e +1/2, os dados são próximos de simétricos.

A afinidade certa pode ser corrigida tomando logaritmos e a assimetria esquerda usando a função exponencial.

Nós estabelecemos que as distorções assimétricas, outliers e outras estão conectadas. Vamos ver como o índice de assimetria mudou após a remoção e a imputação dos outliers.  

evalq({
  sk <- skewness(x) 
  sk.out <- skewness(x.out) 
  sk.cap <- skewness(x.cap)
  }, 
  env)
> env$sk
             ftlm     stlm     rbci     pcci   v.fatl
Skewness 4.219857 1.785286 2.304655 6.491546 5.274871
           v.satl   v.rftl   v.rstl   v.ftlm    v.stlm
Skewness 2.677162 3.954098 1.568675 1.207227 0.8516043
           v.pcci
Skewness 3.031012
> env$sk.out
                ftlm        stlm        rbci       pcci
Skewness -0.04272076 -0.07893945 -0.02460354 0.01485785
             v.fatl      v.satl      v.rftl      v.rstl
Skewness 0.00780424 -0.02640635 -0.04663711 -0.04290957
                v.ftlm     v.stlm       v.pcci
Skewness -0.0009597876 0.01997082 0.0007462494
> env$sk.cap
                ftlm        stlm        rbci       pcci
Skewness -0.03329392 -0.07911245 -0.02847851 0.01915228
             v.fatl      v.satl      v.rftl      v.rstl
Skewness 0.01412182 -0.02617518 -0.03412228 -0.04596505
              v.ftlm      v.stlm      v.pcci
Skewness 0.008181183 0.009661169 0.002252508


Como você pode ver, tanto o conjunto com outliers removidos x.out e aquele com os outliers imputados x.cap são absolutamente simétricos e não requerem nenhuma correção.

Vamos avaliar a curtose também. A Curtose ou o coeficiente de pico é uma medida de pico de uma distribuição variável aleatória. A curtose de uma distribuição normal é 0. A curtose é positiva se o pico da distribuição em torno da expectativa matemática for acentuada e negativa se o pico for suave.

require(PerformanceAnalytics)
evalq({
  k <- kurtosis(x) 
  k.out <- kurtosis(x.out) 
  k.cap <- kurtosis(x.cap)
}, 
env)
> env$k
                    ftlm     stlm     rbci     pcci
Excess Kurtosis 84.61177 16.77141 45.01858 247.9795
                  v.fatl   v.satl  v.rftl   v.rstl
Excess Kurtosis 145.9547 36.99944 74.4307 13.57613
                  v.ftlm   v.stlm   v.pcci
Excess Kurtosis 86.36448 23.06635 233.5408
> env$k.out
                        ftlm       stlm       rbci
Excess Kurtosis -0.003083449 -0.1668102 -0.1197043
                       pcci      v.fatl      v.satl
Excess Kurtosis -0.05113439 -0.02738558 -0.04341552
                     v.rftl     v.rstl     v.ftlm
Excess Kurtosis -0.01219999 -0.1316499 -0.0287925
                    v.stlm      v.pcci
Excess Kurtosis -0.1530424 -0.09950709
> env$k.cap
                      ftlm       stlm       rbci
Excess Kurtosis -0.2314336 -0.3075185 -0.2982044
                      pcci     v.fatl     v.satl
Excess Kurtosis -0.2452504 -0.2389486 -0.2331203
                    v.rftl     v.rstl     v.ftlm
Excess Kurtosis -0.2438431 -0.2673441 -0.2180059
                    v.stlm     v.pcci
Excess Kurtosis -0.2763058 -0.2698028


Os picos da distribuição no conjunto de dados inicial x são muito acentuados (a curtose é muito maior do que 0) no conjunto com os outliers removidos x.out, os picos são muito próximos do ponto normal de pico. O conjunto com outliers imputados possui picos mais suaves. Ambos os conjuntos de dados não requerem correções.

Aplicação

1. O arquivo DARCH12_1.zip contém os scripts para a primeira parte do artigo (dataRaw.R, PrepareData.R, FUNCTION.R) e um diagrama que representa a sessão Rstudio com os dados iniciais Cotir.RData. Carregue os dados no Rstudio e você poderá ver todos os scripts e trabalhar com eles. Você também pode fazer o download de Git /Part_I.

2. O arquivo ACTF.zip contém o artigo de V. Kravchuk "New Adaptive Method of Following the Tendency and Market Cycles"

3. O arquivo R_intro.zip contém materiais de referência em R.

[1] A Systematic Approach on Data Pre-processing In Data Mining. COMPUSOFT, An international journal of advanced computer technology, 2 (11), November-2013 (Volume-II, Issue-XI)

[2] Outlier Detection Techniques.Hans-Peter Kriegel, Peer Kröger, Arthur Zimek. Ludwig-Maximilians-Universität München.Munich, Germany

[3] Breuning, M., Kriegel, H., Ng, R.T, and Sander. J. (2000). LOF: Identifying density-based local outliers. In Proceedings of the ACM SIGMOD International Conference on Management of Data.


Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/3486

Arquivos anexados |
DARCH12_1.zip (130.21 KB)
ATCF_k1v.zip (1928.03 KB)
R-intro.zip (15278.8 KB)
Redes Neurais Profundas (Parte II). Desenvolvimento e seleção de preditores Redes Neurais Profundas (Parte II). Desenvolvimento e seleção de preditores
O segundo artigo da série sobre redes neurais profundas considerará a transformação e seleção dos preditores durante o processo de preparação de dados para treinar um modelo.
Otimização Walk Forward em MetaTrader 5 feita com suas próprias mãos Otimização Walk Forward em MetaTrader 5 feita com suas próprias mãos
No artigo, são discutidas abordagens que permitem emular com bastante precisão a Otimização Walk Forward através do testador interno e bibliotecas auxiliares implementadas em MQL.
Examinemos na prática o método adaptativo de acompanhamento do mercado Examinemos na prática o método adaptativo de acompanhamento do mercado
A principal diferença entre ele e o sistema de negociação proposto no artigo é o uso de ferramentas matemáticas para analisar as cotações da bolsa de valores. O sistema implementa filtragem digital e estimativa espectral de séries temporais discretas. Descrevem-se os aspectos teóricos da estratégia e constrói-se o Expert Advisor para testá-la.
Classificador Bayesiano Ingênuo para sinais de um conjunto de indicadores Classificador Bayesiano Ingênuo para sinais de um conjunto de indicadores
O artigo analisa a aplicação da fórmula de Bayes para melhorar a fiabilidade dos sistemas de negociação através do uso dos sinais de vários indicadores independentes. Os cálculos teóricos são verificados com um EA universal simples, personalizado para trabalhar com indicadores exploratórios ou customizados.