A essência da aprendizagem de máquina:

  • existe um padrão
  • não conseguimos descobrí-lo matematicamente (formalmente)
  • mas nós temos dados!!

Carrega Pacotes

library(tidyverse)
library(rvest)
library(GetDFPData2) 
library(yfR)

Obtém a tabela atualizada das empresas listadas na B3

df.info <- get_info_companies() 

Obtenção dos dados (Fundamentus)

O sítio da Fundamentus disponibiliza informações financeiras e fundamentalistas das empresas com ações listadas na Bovespa.

# Função para limpar os dados do site da Fundamentus -----
limpa_dados <- function(x) {
    # Limpeza dos dados da Fundamentus (http://www.fundamentus.com.br)
    # Primeiro elimina todos os caracteres não-dígitos e qualquer outro após estes
    # Depois elimina os pontos
    # Finalmente, converte vírgulas em pontos
    # Se é um valor representado com "%", divide por 100  
    z <- trimws(x)
    n_digitos <- nchar(z)
    ultimo <- substr(z, n_digitos, n_digitos)
    z <- gsub("[^0-9,.]", "", z)
    z <- gsub("\\.", "", z)
    z <- as.numeric(gsub(",", ".", z))
    if(ultimo[1] == "%") { 
        z <- z/100 
    }
    return(z)
}

# Nomes das empresas
url.detalhes <- "http://www.fundamentus.com.br/detalhes.php?papel="
empresas.b3 <- url.detalhes %>%
    read_html() %>%
    rvest::html_table(header = TRUE) %>%
    map_df(bind_cols) %>% # tranforma a lista em um dataframe
    as_tibble() # converte para um 'tibble'

# Dados fundamentalistas
url.dados <- "http://www.fundamentus.com.br/resultado.php"
dados.Fund <- url.dados %>%
    read_html() %>%
    rvest::html_table(header = TRUE) %>%
    map_df(bind_cols) %>% # tranforma a lista em um dataframe
    as_tibble() %>% # transforma para um tibble 
    mutate_at(colnames(.)[-1], limpa_dados) %>% # converte ao formato adequado utilizando a função limpa_dados()
    mutate(Nome = empresas.b3$`Nome Comercial`[match(.$Papel, empresas.b3$Papel)]) %>% 
    select(Papel, Nome, everything())

dados.Fund

Se desejar criar uma planilha Excel.

## Com o pacote 'openxlsx' - não depende do Java -------
library(openxlsx)
# Cria um arquivo vazio
arq <- createWorkbook()

# Adiciona planilhas ao arquivo
addWorksheet(arq, "Empresas")
addWorksheet(arq, "Dados fundamentalistas")

# Escreve os dados nas planilhas
writeData(arq, 
          sheet = "Empresas", 
          x = empresas.b3)
writeData(arq, 
          sheet = "Dados fundamentalistas", 
          x = dados.Fund)

# Exporta o arquivo completo
saveWorkbook(arq, "Dados/Fundamentus2.xlsx", overwrite = TRUE)

Quantos NA´s?

sum(colSums(is.na(dados.Fund[])))
## [1] 0
# Nenhum!

Estatísticas básicas das empresas.

glimpse(dados.Fund)
## Rows: 986
## Columns: 22
## $ Papel               <chr> "PMET3", "MNSA4", "CSTB4", "CFLU4", "PORP4", "CLAN…
## $ Nome                <chr> "PRO METALURG", "MANASA", "COMPANHIA SIDERÚRGICA D…
## $ Cotação             <dbl> 0.00, 0.47, 147.69, 1000.00, 2.40, 0.00, 0.42, 150…
## $ `P/L`               <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ `P/VP`              <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ PSR                 <dbl> 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0…
## $ Div.Yield           <dbl> 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.…
## $ `P/Ativo`           <dbl> 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0…
## $ `P/Cap.Giro`        <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ `P/EBIT`            <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ `P/Ativ Circ.Liq`   <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ `EV/EBIT`           <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ `EV/EBITDA`         <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.…
## $ `Mrg Ebit`          <dbl> 0.0000, 2.0815, 0.4085, 0.0888, 0.0000, 0.0000, 2.…
## $ `Mrg. Líq.`         <dbl> 0.0000, 3.6266, 0.2898, 0.1072, 0.0000, 0.0000, 3.…
## $ `Liq. Corr.`        <dbl> 0.00, 3.63, 2.60, 1.10, 0.00, 0.00, 3.63, 2.60, 0.…
## $ ROIC                <dbl> 0.0000, 0.1350, 0.2240, 0.1768, 0.0000, 0.0000, 0.…
## $ ROE                 <dbl> 0.0410, 1.4570, 0.2011, 0.3215, 0.0208, 0.0105, 1.…
## $ Liq.2meses          <dbl> 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00…
## $ `Patrim. Líq`       <dbl> 290863000, 9105000, 8420670000, 60351000, 22399000…
## $ `Dív.Brut/ Patrim.` <dbl> 0.00, 6.52, 0.14, 0.06, 0.00, 0.00, 6.52, 0.14, 0.…
## $ `Cresc. Rec.5a`     <dbl> 0.3774, 0.4111, 0.3191, 0.0814, 0.1366, 0.6396, 0.…
summary(dados.Fund)
##     Papel               Nome              Cotação               P/L          
##  Length:986         Length:986         Min.   :    0.000   Min.   :    0.00  
##  Class :character   Class :character   1st Qu.:    4.352   1st Qu.:    1.86  
##  Mode  :character   Mode  :character   Median :   12.000   Median :    7.77  
##                                        Mean   :   59.599   Mean   :  102.01  
##                                        3rd Qu.:   28.285   3rd Qu.:   17.64  
##                                        Max.   :10081.900   Max.   :35858.80  
##       P/VP               PSR              Div.Yield          P/Ativo        
##  Min.   :     0.0   Min.   :     0.00   Min.   :0.00000   Min.   :  0.0000  
##  1st Qu.:     0.5   1st Qu.:     0.09   1st Qu.:0.00000   1st Qu.:  0.0880  
##  Median :     1.2   Median :     0.68   Median :0.00000   Median :  0.3975  
##  Mean   :  1464.1   Mean   :   140.95   Mean   :0.03865   Mean   :  1.9460  
##  3rd Qu.:     2.2   3rd Qu.:     1.75   3rd Qu.:0.02438   3rd Qu.:  0.8728  
##  Max.   :723708.0   Max.   :125972.00   Max.   :3.85080   Max.   :721.2280  
##    P/Cap.Giro            P/EBIT         P/Ativ Circ.Liq       EV/EBIT        
##  Min.   :    0.000   Min.   :     0.0   Min.   :   0.000   Min.   :     0.0  
##  1st Qu.:    0.140   1st Qu.:     0.8   1st Qu.:   0.050   1st Qu.:     2.9  
##  Median :    2.200   Median :     4.9   Median :   1.210   Median :     7.8  
##  Mean   :   39.145   Mean   :   363.4   Mean   :  13.621   Mean   :   451.4  
##  3rd Qu.:    7.327   3rd Qu.:    12.3   3rd Qu.:   4.405   3rd Qu.:    17.0  
##  Max.   :15159.500   Max.   :324900.0   Max.   :6206.380   Max.   :368611.0  
##    EV/EBITDA           Mrg Ebit          Mrg. Líq.           Liq. Corr.    
##  Min.   :   0.000   Min.   :  0.0000   Min.   :   0.0000   Min.   : 0.000  
##  1st Qu.:   2.663   1st Qu.:  0.0422   1st Qu.:   0.0222   1st Qu.: 0.520  
##  Median :   6.270   Median :  0.1315   Median :   0.0988   Median : 1.295  
##  Mean   :  44.412   Mean   :  4.1470   Mean   :   6.6552   Mean   : 1.875  
##  3rd Qu.:  14.075   3rd Qu.:  0.2731   3rd Qu.:   0.2125   3rd Qu.: 2.047  
##  Max.   :7466.350   Max.   :787.0000   Max.   :1567.2900   Max.   :66.470  
##       ROIC             ROE              Liq.2meses         Patrim. Líq       
##  Min.   :0.0000   Min.   :    0.000   Min.   :0.000e+00   Min.   :0.000e+00  
##  1st Qu.:0.0279   1st Qu.:    0.067   1st Qu.:0.000e+00   1st Qu.:2.894e+08  
##  Median :0.0908   Median :    0.152   Median :0.000e+00   Median :1.152e+09  
##  Mean   :0.1567   Mean   :   28.145   Mean   :2.194e+07   Mean   :6.387e+09  
##  3rd Qu.:0.1751   3rd Qu.:    0.299   3rd Qu.:9.308e+05   3rd Qu.:4.004e+09  
##  Max.   :6.2387   Max.   :13632.000   Max.   :2.672e+09   Max.   :4.105e+11  
##  Dív.Brut/ Patrim.   Cresc. Rec.5a    
##  Min.   :    0.000   Min.   : 0.0000  
##  1st Qu.:    0.040   1st Qu.: 0.0642  
##  Median :    0.475   Median : 0.1352  
##  Mean   :   44.264   Mean   : 0.3575  
##  3rd Qu.:    1.218   3rd Qu.: 0.2891  
##  Max.   :21227.000   Max.   :63.5407
sumario.fund <- psych::describe(dados.Fund[, -c(1, 2)])
sumario.fund

Algumas questões:

  1. Quantas empresas pagaram dividendos maiores do que R$0,02 por ação?

  2. Quantas possuem PL maior do que R$ 5 Bilhões?

  3. Quais empresas apresentam um ROE maior do que 40%?

sum(dados.Fund$Div.Yield > 0.02)
## [1] 269
sum(dados.Fund$`Patrim. Líq` > 5.5e9) # 5e9 = 5.500.000.000
## [1] 207
grande.ROE <- dados.Fund %>% 
                 filter(ROE > 0.40) %>% 
                 select(Papel, Nome, ROE)
grande.ROE

Dados da Status Invest

O sítio da Status Invest possui muitas informações importantes sobre as ações listadas na BOVESPA. Por exemplo, aqui podemos selecionar as empresas do setor Consumo Cíclico, Tecido, Vestuário e Calçados e baixar um arquivo com os dados.

A função read_csv2() lê os dados no formato que gostamos: separador ‘;’ e vírgulas para os decimais.

empresas <- read_csv2('Dados/statusinvest-busca-avancada.csv')

Um exemplo

Inclui ‘Patrimônio Líquido’ e ‘Dív.Brut/ Patrim.’ nos dados da StatusInvest, buscando na Fundamentus.

empresas$PatLiq <- dados.Fund$`Patrim. Líq`[match(empresas$TICKER, dados.Fund$Papel)]
empresas$DivBruta <- dados.Fund$'Dív.Brut/ Patrim.'[match(empresas$TICKER, dados.Fund$Papel)]

summary(empresas)
##     TICKER              PRECO               DY             P/L          
##  Length:32          Min.   :  0.000   Min.   : 1.29   Min.   : -9.9200  
##  Class :character   1st Qu.:  4.325   1st Qu.: 1.73   1st Qu.: -0.8575  
##  Mode  :character   Median :  9.400   Median : 2.33   Median :  2.7050  
##                     Mean   : 19.257   Mean   : 3.87   Mean   :  6.7706  
##                     3rd Qu.: 23.145   3rd Qu.: 4.15   3rd Qu.:  7.5350  
##                     Max.   :103.610   Max.   :15.54   Max.   :101.9900  
##                                       NA's   :19                        
##       P/VP            P/ATIVOS       MARGEM BRUTA    MARGEM EBIT   
##  Min.   :-1.1300   Min.   :0.0000   Min.   :14.56   Min.   :-0.59  
##  1st Qu.: 0.0000   1st Qu.:0.0500   1st Qu.:19.35   1st Qu.: 7.34  
##  Median : 0.5550   Median :0.2800   Median :32.23   Median :10.40  
##  Mean   : 0.8459   Mean   :0.5516   Mean   :31.98   Mean   :10.94  
##  3rd Qu.: 1.6375   3rd Qu.:0.7650   3rd Qu.:40.38   3rd Qu.:14.21  
##  Max.   : 3.7600   Max.   :2.4800   Max.   :67.90   Max.   :20.81  
##                                     NA's   :2       NA's   :2      
##  MARG. LIQUIDA          P/EBIT             EV/EBIT        
##  Min.   :-83.8700   Min.   :-707.6500   Min.   :-713.650  
##  1st Qu.: -3.0750   1st Qu.:   0.6125   1st Qu.:   4.830  
##  Median :  5.3100   Median :   1.9350   Median :   8.535  
##  Mean   :  0.2687   Mean   : -18.1450   Mean   : -13.728  
##  3rd Qu.: 10.0300   3rd Qu.:   5.5250   3rd Qu.:  13.572  
##  Max.   : 25.5600   Max.   :  25.3100   Max.   :  22.370  
##  NA's   :2                                                
##  DIVIDA LIQUIDA / EBIT DIV. LIQ. / PATRI.      PSR          P/CAP. GIRO      
##  Min.   :-5.990        Min.   :-0.3000    Min.   :0.0000   Min.   : -2.2300  
##  1st Qu.: 0.230        1st Qu.: 0.0200    1st Qu.:0.0750   1st Qu.: -0.0025  
##  Median : 2.500        Median : 0.3300    Median :0.2850   Median :  0.9850  
##  Mean   : 4.119        Mean   : 0.4012    Mean   :0.8637   Mean   : 13.1116  
##  3rd Qu.: 7.480        3rd Qu.: 0.7100    3rd Qu.:0.8800   3rd Qu.:  5.5350  
##  Max.   :22.040        Max.   : 1.7800    Max.   :4.1800   Max.   :175.5700  
##                        NA's   :7          NA's   :2                          
##  P. AT CIR. LIQ.  LIQ. CORRENTE        ROE               ROA         
##  Min.   :-5.590   Min.   :0.040   Min.   :-80.560   Min.   :-47.520  
##  1st Qu.:-1.442   1st Qu.:0.940   1st Qu.: -7.433   1st Qu.: -3.020  
##  Median :-0.625   Median :1.470   Median :  6.930   Median :  3.775  
##  Mean   :-1.216   Mean   :1.911   Mean   :  1.276   Mean   :  1.359  
##  3rd Qu.:-0.110   3rd Qu.:2.380   3rd Qu.: 12.260   3rd Qu.:  7.080  
##  Max.   : 0.000   Max.   :7.000   Max.   : 26.290   Max.   : 17.130  
##                                                                      
##       ROIC         PATRIMONIO / ATIVOS PASSIVOS / ATIVOS  GIRO ATIVOS    
##  Min.   :-68.120   Min.   :-1.6700     Min.   :0.1000    Min.   :0.0000  
##  1st Qu.:  3.330   1st Qu.: 0.1400     1st Qu.:0.4675    1st Qu.:0.5200  
##  Median :  8.060   Median : 0.4550     Median :0.5300    Median :0.7300  
##  Mean   :  2.075   Mean   : 0.1584     Mean   :0.8347    Mean   :0.6959  
##  3rd Qu.: 11.158   3rd Qu.: 0.5325     3rd Qu.:0.8500    3rd Qu.:0.9300  
##  Max.   : 19.540   Max.   : 0.9000     Max.   :2.6700    Max.   :1.2000  
##                                                                          
##  CAGR RECEITAS 5 ANOS CAGR LUCROS 5 ANOS LIQUIDEZ MEDIA DIARIA
##  Min.   :-7.540       Min.   :-26.63     Min.   :     1900    
##  1st Qu.:-0.530       1st Qu.: 10.32     1st Qu.:     8960    
##  Median : 8.130       Median : 34.56     Median :    43022    
##  Mean   : 5.352       Mean   : 30.89     Mean   :  9400429    
##  3rd Qu.:10.410       3rd Qu.: 54.47     3rd Qu.:   204408    
##  Max.   :13.540       Max.   : 59.07     Max.   :109503606    
##  NA's   :3            NA's   :21         NA's   :4            
##       VPA                LPA             PEG Ratio        VALOR DE MERCADO   
##  Min.   :-3571.28   Min.   :-240.610   Min.   :-1.23000   Min.   :8.804e+06  
##  1st Qu.:    2.71   1st Qu.:  -2.955   1st Qu.:-0.02000   1st Qu.:6.294e+07  
##  Median :    6.35   Median :   0.360   Median : 0.00500   Median :1.739e+08  
##  Mean   : -161.74   Mean   : -10.537   Mean   :-0.02031   Mean   :1.594e+09  
##  3rd Qu.:   12.13   3rd Qu.:   1.035   3rd Qu.: 0.06000   3rd Qu.:5.437e+08  
##  Max.   : 1048.02   Max.   : 128.530   Max.   : 0.60000   Max.   :1.250e+10  
##                                                                              
##      PatLiq             DivBruta    
##  Min.   :1.028e+08   Min.   :0.000  
##  1st Qu.:1.939e+08   1st Qu.:0.135  
##  Median :3.386e+08   Median :0.560  
##  Mean   :1.066e+09   Mean   :0.853  
##  3rd Qu.:1.326e+09   3rd Qu.:0.900  
##  Max.   :5.733e+09   Max.   :3.510  
##  NA's   :2           NA's   :2
colSums(is.na(empresas))
##                TICKER                 PRECO                    DY 
##                     0                     0                    19 
##                   P/L                  P/VP              P/ATIVOS 
##                     0                     0                     0 
##          MARGEM BRUTA           MARGEM EBIT         MARG. LIQUIDA 
##                     2                     2                     2 
##                P/EBIT               EV/EBIT DIVIDA LIQUIDA / EBIT 
##                     0                     0                     0 
##    DIV. LIQ. / PATRI.                   PSR           P/CAP. GIRO 
##                     7                     2                     0 
##       P. AT CIR. LIQ.         LIQ. CORRENTE                   ROE 
##                     0                     0                     0 
##                   ROA                  ROIC   PATRIMONIO / ATIVOS 
##                     0                     0                     0 
##     PASSIVOS / ATIVOS           GIRO ATIVOS  CAGR RECEITAS 5 ANOS 
##                     0                     0                     3 
##    CAGR LUCROS 5 ANOS LIQUIDEZ MEDIA DIARIA                   VPA 
##                    21                     4                     0 
##                   LPA             PEG Ratio      VALOR DE MERCADO 
##                     0                     0                     0 
##                PatLiq              DivBruta 
##                     2                     2
sum(colSums(is.na(empresas)))
## [1] 66
sumario.StatInv <- psych::describe(empresas[, -1])

empresas <- empresas %>% 
    mutate_all(~replace(., is.na(.), 0))
# poderia ter substituído pelo valor médio, ou por uma regressão

“Vendo” alguns dados.

moda <- function(v) {
    # cálculo da moda de um conjunto de dados (não existe no R)
    uniqv <- unique(v)
    uniqv[which.max(tabulate(match(v, uniqv)))]
}

grafico <- function(df, .var, binwidth = 10, mostra = TRUE) {
        nome_var <- deparse(substitute(.var))
        nome_df <- deparse(substitute(df))
        nome <- substr(nome_var, nchar(nome_df)+1, nchar(nome_var))
        x <- seq(min(.var), max(.var), length.out = 100)
        normal <- data.frame(x = x, y = dnorm(x, mean(.var), sd(.var)))

        g <- ggplot(df, aes(x = .var, y = ..density..))  +
                geom_histogram(binwidth = binwidth, color = "black", fill = "lightblue")  +
                xlab(nome) +
                geom_vline(xintercept = mean(.var), color = "darkgreen", 
                           linetype = "dashed", lwd = 1) +
                geom_vline(xintercept = median(.var), color = "darkred", 
                           linetype = "dashed", lwd = 1) +
                geom_vline(xintercept = moda(.var), color = "black", 
                           linetype = "dashed", lwd = 1) +
                geom_rug(aes(x = .var, y = 0), color = 'darkred', position = position_jitter(height = 0)) +
                geom_density(color = "darkblue", lwd = 1) +
                geom_line(data = normal, aes(x = x, y = y), color = "darkred") # uma curva Normal
        if(mostra) print(g)
        return(invisible(g))
}

library(gridExtra)

g1 <- grafico(empresas, empresas$`P/L`, binwidth = 2, mostra = TRUE)

g2 <- grafico(empresas, empresas$`EV/EBIT`, binwidth = 2, mostra = FALSE)
g3 <- grafico(empresas, empresas$ROA, binwidth = 2, mostra = FALSE)
g4 <- grafico(empresas, empresas$`P/EBIT`, binwidth = 2, mostra = FALSE)
g5 <- grafico(empresas, empresas$ROIC, binwidth = 2, mostra = FALSE)
g6 <- grafico(empresas, empresas$ROE, binwidth = 2, FALSE)

grid.arrange(g1, g2, g3, g4, g5, g6, nrow = 2)

Não parece que algumas aproximações pela distribuição Normal sejam válidas aqui.

outliers <- boxplot(empresas$'P/L', main = 'Boxplot de P/L')$out

(emp.out <- empresas$TICKER[empresas$'P/L' %in% outliers])
## [1] "ALPA4" "DOHL3" "HGTX3"

O modelo de Benjamin Graham.

Benjamin Graham é um dos maiores investidores de todos os tempos e, muito provavelmente, um dos personagens mais influentes da área.

O preço justo de uma ação é uma das premissas da análise fundamentalista, que consiste em avaliar as perspectivas de uma determinada companhia, ou seja, analisar a situação financeira dela e até onde ela pode chegar no longo prazo. Graham estabeleceu alguns modelos, entre eles a seleção de ações de acordo com o valor de alguns indicadores. A seguinte função retorna TRUE se a empresa atinge os valores mínimos passados em seus parâmetros.

is.graham <- function(df, 
                      pl = 9,             # Patrimônio líquido
                      pvp = 1.2,          # Preço / valor patrimonial
                      l.corr = 1.5,       # Índice de liquidez corrente (at. Circ. / Passivo Circ.)
                      roe = 0,            # Retorno sobre o patrimônilo líquido
                      roic = 0,           # Retorno sobre o capital investido (inclui dívidas) -> EBIT - (Ativos-Fornecedores-Caixa)
                      mrg.liq = 0,        # Lucro líquido / receita líquida
                      marg.ebit = 0,      # EBIT (lucro operacional) / receita líquida
                      div.brut = 1.1,     # Dívida bruta / PL
                      pat.liq = 0,        # Patrimõnio Líquido
                      cresc.rec.5a = 0) { # Crescimento da receita líquida (5 anos)
    
    selecao <- df$'P/L' < pl &
               df$'P/VP' < pvp &
               df$'LIQ. CORRENTE' > l.corr & 
               df$ROE > roe &
               df$ROIC > roic &
               df$'MARG. LIQUIDA' > mrg.liq &
               df$'MARGEM EBIT' > marg.ebit &
               df$DivBruta < div.brut &
               df$PatLiq > pat.liq &
               df$'CAGR RECEITAS 5 ANOS' > cresc.rec.5a
    
    return(selecao)
}

Selecionemos as empresas listadas de acordo com o padrão de Graham.

empresas.graham <- empresas %>% 
    filter(is.graham(., pl = 12, l.corr = 1.0))

# ou, em R básico
#empresas.graham <- empresas[is.graham(empresas, pl = 12, l.corr = 1.0), ]

empresas.graham

Um breve “aperitivo” de Machine Learning.

Ações que fazem parte do índice IBOVESPA (atuais).

### Ações que fazem parte do índice IBOVESPA (atuais)
ibovespa <- yf_index_composition('IBOV')

# Ações listadas na Fundamentus que estão no Ibovespa
dados.Fund.ibov <- dados.Fund %>% 
    filter(Papel %in% ibovespa$ticker)

Calcula o dividendo mediano (metade das empresas pagam este valor ou mais dividendos por ação). Cria-se uma coluna com o valor “1” neste caso.

med.dividendo.ibov <- median(dados.Fund.ibov$Div.Yield)
dados.Fund.ibov$dividendo <- ifelse(dados.Fund.ibov$Div.Yield > med.dividendo.ibov, 1, 0)

Podemos fazer o mesmo para todas as empresas listadas na B3.

med.dividendo <- median(dados.Fund$Div.Yield)
dados.Fund$dividendo <- ifelse(dados.Fund$Div.Yield > med.dividendo, 1, 0)

Uma rede neural simples

# Normalização dos dados 

# 1. todos com média zero e desvio-padrão um
#dados.scaled <- as.data.frame(scale(dados.Fund[, -c(1, 2, 3, 7)], scale = TRUE))
dados.scaled <- as.data.frame(scale(dados.Fund[, -c(1, 2, 3, 7)], scale = TRUE))

# 2. normalização Max-Min - todos entre zero e um (vamos utilizar este modelo aqui)
normaliza <- function(x) {
    return((x - min(x)) / (max(x) - min(x)))
}

# Retirando algumas variáveis ("Papel", "Nome", "Cotação" e "Div.Yield" )
maxmindf <- as.data.frame(lapply(dados.Fund[, -c(1, 2, 3, 7)], normaliza))

# Segregando dados para o modelo (trainset) 80% e para testar o modelo (testset)

# Utilizando o pacote caret para manter o equilibrio entre 0 e 1´s
library(caret)
set.seed(1234)
indices <- createDataPartition(maxmindf$dividendo,
                               p = 0.8,
                               list = FALSE,
                               times = 1)
treinamento <- maxmindf[indices, ]
teste <- maxmindf[-indices, ]

prop.table(table(treinamento$dividendo))
## 
##         0         1 
## 0.6413181 0.3586819
prop.table(table(teste$dividendo))
## 
##         0         1 
## 0.6548223 0.3451777
# Uma Rede Neural Simples 
library(neuralnet)

# Selecionando dividendo como variável dependente 

formula <- dividendo ~ . # todas as variáveis ?

nn <- neuralnet(formula = formula,
                data = treinamento,
                hidden = c(10,4),
                linear.output = FALSE,
                threshold = 0.05)

# Testando os resultados
nn.resultados <- compute(nn, teste)

#Acurária da rede neural
resultados <- data.frame(actual = teste$dividend, prediction = nn.resultados$net.result)

library(gmodels)
CrossTable(round(resultados$actual, digits = 0), 
           round(resultados$prediction, digits = 0))
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## | Chi-square contribution |
## |           N / Row Total |
## |           N / Col Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  197 
## 
##  
##                                      | round(resultados$prediction, digits = 0) 
## round(resultados$actual, digits = 0) |         0 |         1 | Row Total | 
## -------------------------------------|-----------|-----------|-----------|
##                                    0 |       110 |        19 |       129 | 
##                                      |     9.679 |    16.804 |           | 
##                                      |     0.853 |     0.147 |     0.655 | 
##                                      |     0.880 |     0.264 |           | 
##                                      |     0.558 |     0.096 |           | 
## -------------------------------------|-----------|-----------|-----------|
##                                    1 |        15 |        53 |        68 | 
##                                      |    18.362 |    31.878 |           | 
##                                      |     0.221 |     0.779 |     0.345 | 
##                                      |     0.120 |     0.736 |           | 
##                                      |     0.076 |     0.269 |           | 
## -------------------------------------|-----------|-----------|-----------|
##                         Column Total |       125 |        72 |       197 | 
##                                      |     0.635 |     0.365 |           | 
## -------------------------------------|-----------|-----------|-----------|
## 
## 
# matriz de confusão
result.round <- sapply(resultados, round, digits = 0)
result.round.df <- data.frame(result.round)

(tabela <- table(result.round.df$actual, result.round.df$prediction))
##    
##       0   1
##   0 110  19
##   1  15  53
source(paste0(dirname(getwd()),'/Matriz de Confusao.R'))
mc <- confusionMatrix(tabela, positive = '1')

plot_matconf(mc)

Rede Neural - Dividendos?

Rede Neural - Dividendos?

Árvore de Decisão

library(rattle)
library(rpart.plot)
library(RColorBrewer)

fit_dividendos_tree <- rpart(dividendo ~ P.L + PSR + P.Cap.Giro + ROE + Mrg..Líq.,
                             data = treinamento,
                             method = "class")
fit_dividendos_tree
## n= 789 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
##   1) root 789 283 0 (0.64131812 0.35868188)  
##     2) P.L< 5.410109e-05 200  11 0 (0.94500000 0.05500000) *
##     3) P.L>=5.410109e-05 589 272 0 (0.53820034 0.46179966)  
##       6) P.L>=0.0002760829 339 123 0 (0.63716814 0.36283186)  
##        12) Mrg..Líq.< 6.358109e-05 231  72 0 (0.68831169 0.31168831)  
##          24) PSR>=4.163624e-06 148  39 0 (0.73648649 0.26351351) *
##          25) PSR< 4.163624e-06 83  33 0 (0.60240964 0.39759036)  
##            50) P.L>=0.0004510748 52  14 0 (0.73076923 0.26923077) *
##            51) P.L< 0.0004510748 31  12 1 (0.38709677 0.61290323)  
##             102) P.L< 0.0003074559 7   1 0 (0.85714286 0.14285714) *
##             103) P.L>=0.0003074559 24   6 1 (0.25000000 0.75000000) *
##        13) Mrg..Líq.>=6.358109e-05 108  51 0 (0.52777778 0.47222222)  
##          26) ROE>=2.816168e-05 12   0 0 (1.00000000 0.00000000) *
##          27) ROE< 2.816168e-05 96  45 1 (0.46875000 0.53125000)  
##            54) P.Cap.Giro>=0.0006464593 40  16 0 (0.60000000 0.40000000)  
##             108) ROE< 6.451731e-06 11   1 0 (0.90909091 0.09090909) *
##             109) ROE>=6.451731e-06 29  14 1 (0.48275862 0.51724138)  
##               218) Mrg..Líq.>=0.000120367 9   2 0 (0.77777778 0.22222222) *
##               219) Mrg..Líq.< 0.000120367 20   7 1 (0.35000000 0.65000000) *
##            55) P.Cap.Giro< 0.0006464593 56  21 1 (0.37500000 0.62500000) *
##       7) P.L< 0.0002760829 250 101 1 (0.40400000 0.59600000)  
##        14) ROE>=5.731001e-05 15   2 0 (0.86666667 0.13333333) *
##        15) ROE< 5.731001e-05 235  88 1 (0.37446809 0.62553191)  
##          30) PSR>=1.43008e-05 41  14 0 (0.65853659 0.34146341)  
##            60) P.Cap.Giro< 0.0001550183 19   3 0 (0.84210526 0.15789474) *
##            61) P.Cap.Giro>=0.0001550183 22  11 0 (0.50000000 0.50000000)  
##             122) ROE>=2.274061e-05 8   1 0 (0.87500000 0.12500000) *
##             123) ROE< 2.274061e-05 14   4 1 (0.28571429 0.71428571) *
##          31) PSR< 1.43008e-05 194  61 1 (0.31443299 0.68556701)  
##            62) ROE< 9.991197e-06 43  19 0 (0.55813953 0.44186047)  
##             124) P.Cap.Giro>=0.0001246743 14   0 0 (1.00000000 0.00000000) *
##             125) P.Cap.Giro< 0.0001246743 29  10 1 (0.34482759 0.65517241)  
##               250) P.L< 0.0001415273 7   1 0 (0.85714286 0.14285714) *
##               251) P.L>=0.0001415273 22   4 1 (0.18181818 0.81818182) *
##            63) ROE>=9.991197e-06 151  37 1 (0.24503311 0.75496689) *
fit_prune <- prune(fit_dividendos_tree, cp = 0.03)
fit_prune
## n= 789 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
##  1) root 789 283 0 (0.6413181 0.3586819)  
##    2) P.L< 5.410109e-05 200  11 0 (0.9450000 0.0550000) *
##    3) P.L>=5.410109e-05 589 272 0 (0.5382003 0.4617997)  
##      6) P.L>=0.0002760829 339 123 0 (0.6371681 0.3628319) *
##      7) P.L< 0.0002760829 250 101 1 (0.4040000 0.5960000)  
##       14) ROE>=5.731001e-05 15   2 0 (0.8666667 0.1333333) *
##       15) ROE< 5.731001e-05 235  88 1 (0.3744681 0.6255319)  
##         30) PSR>=1.43008e-05 41  14 0 (0.6585366 0.3414634) *
##         31) PSR< 1.43008e-05 194  61 1 (0.3144330 0.6855670) *
fancyRpartPlot(fit_dividendos_tree)

fancyRpartPlot(fit_prune)

previsao.dividendos <- predict(fit_dividendos_tree)

Análise de Grupamentos (Clusters)

norm <- scale(dados.Fund.ibov[, -c(1:2)], center = TRUE) # normaliza os dados antes de calcular as distâncias
rownames(norm) <- dados.Fund.ibov$Papel

library(cluster)

clusters <- hclust(dist(norm), method = 'complete')

clusters2 <- hclust(dist(norm, method = 'euclidean'), method = "ward.D2")
plot(x = clusters2, 
     labels = dados.Fund.ibov$Papel, 
     main = 'Clusters',
     ylab = 'Altura',
     col = 'darkblue')

wss <- nrow(norm) * sum(apply(norm, 2, var))

num.clusters.max <- 25

for (i in 2:num.clusters.max) {
    wss[i] <- sum(kmeans(norm, centers = i)$withinss)
}

plot(1:num.clusters.max, 
     wss, 
     col = 'darkred',
     main = 'Curva do cotovelo (elbow curve)',
     type = "b", 
     xlab = "Número de Clusters", 
     ylab = "Soma dos Quadrados - Within")

library(factoextra)
library(dendextend)
library(igraph)

dist <- dist(norm , method = "euclidean")

hc <- hclust(d = dist, 
             method = "ward.D2")

num.clusters <- 10
fviz_dend(hc, 
          k = num.clusters, 
          cex = 0.8,
          title = paste0('Dendograma com ', num.clusters, ' clusters'),
          k_colors = 'startrek',
          type = 'phylogenic', 
          repel = TRUE)

fviz_dend(hc, k = num.clusters, 
          cex = 0.8,
          title = paste0('Dendograma com ', num.clusters, ' clusters'),
          k_colors = 'startrek',
          type = 'rectangle', 
          repel = TRUE)

fviz_dend(clusters2, 
          k = num.clusters, 
          cex = 0.5, 
          k_colors = 'uchicago',
          color_labels_by_k = TRUE, 
          ggtheme = theme_gray())

k-médias

fviz_nbclust(norm, 
             FUNcluster = kmeans, 
             method = "wss", 
             k.max = 10) + 
    geom_vline(xintercept = 10, linetype = 2)

km.res <- kmeans(norm, 
                 centers = 10, 
                 nstart = 25)
print(km.res)
## K-means clustering with 10 clusters of sizes 11, 25, 1, 25, 1, 1, 3, 1, 12, 8
## 
## Cluster means:
##       Cotação        P/L       P/VP        PSR   Div.Yield     P/Ativo
## 1   0.6848670 -0.1186502  1.5931849  0.5966564 -0.40285300  1.85346120
## 2  -0.5946481  0.5845733 -0.3925551 -0.1577991 -0.55791070 -0.25271139
## 3  -0.5146810 -0.2731574  4.9340310 -0.7376414  0.02799878 -0.33824568
## 4  -0.1113657 -0.3080757 -0.1556809 -0.4232167  0.34876030 -0.34224455
## 5  -0.9741427  1.5099635 -0.5005506  0.7900540 -0.61489080  0.09409975
## 6   0.1544381 -0.3555786 -0.4806619 -0.8716070  2.82420611  0.60174859
## 7   1.7759366 -0.3440666 -0.4193385 -0.4130386  3.71935135 -0.20668110
## 8  -1.1488571 -0.2652340 -0.3762464  0.2098610 -0.19561499 -0.71606105
## 9   0.7037352 -0.2540450 -0.4222389 -0.5072205 -0.18862706 -0.63664625
## 10 -0.1465726 -0.2678177 -0.1338531  1.9871588 -0.15951068  0.38801025
##     P/Cap.Giro      P/EBIT P/Ativ Circ.Liq    EV/EBIT   EV/EBITDA    Mrg Ebit
## 1   0.26914985 -0.10662517     -0.09904890 -0.1066553 -0.01572028 -0.07282534
## 2  -0.27925038 -0.10639240     -0.10272952 -0.1064178 -0.08877634 -0.35611641
## 3  -0.38287960 -0.10699087     -0.11674707 -0.1069086 -0.20897418 -0.68956331
## 4  -0.15699921 -0.10696834     -0.11592027 -0.1068977 -0.13658145  0.16855355
## 5   5.20066595  9.27422189     -0.11366243  9.2742253  0.86295010 -1.12359822
## 6   1.05680143 -0.09680078     -0.06618324 -0.0983115  8.78435632 -1.12359822
## 7   0.01051151 -0.10703794     -0.11671683 -0.1070077 -0.30031477  1.57124631
## 8  -0.40417923 -0.10679366      9.26562600 -0.1067514 -0.13914112  0.07830131
## 9  -0.27047697 -0.10690040     -0.11796555 -0.1068562 -0.23090212 -0.84822155
## 10  0.71117149 -0.10660284     -0.08093921 -0.1066076  0.02243082  1.72669104
##     Mrg. Líq.  Liq. Corr.       ROIC         ROE  Liq.2meses Patrim. Líq
## 1  -0.2215008 -0.08530456  0.2498402  0.02642156 -0.05858178  -0.2793928
## 2  -0.3389845 -0.14124432 -0.4321343 -0.60040339 -0.24006810  -0.3505912
## 3  -0.6175891  0.03344225  1.4015254  3.97741669 -0.32905363  -0.4883153
## 4  -0.0257196  0.05893705  0.5440410  0.53453966 -0.29453943  -0.2865995
## 5  -0.6621605 -0.45442115 -1.1776534 -0.97510022  0.43758171   0.2043757
## 6  -0.7369254  3.44061730 -1.1416992  2.56749290 -0.40597314  -0.3871171
## 7   0.8495919 -0.25507912  2.1001631  1.04509136  4.31901080   4.3250606
## 8   0.1521058 -0.36786474 -0.6404566 -0.47624620 -0.22097384  -0.3464419
## 9  -0.5196998 -0.84392500 -0.9884537 -0.45834856  0.23327312   0.7635098
## 10  2.1382877  1.40457447  0.1966661 -0.17158729 -0.15353791  -0.2645889
##    Dív.Brut/ Patrim. Cresc. Rec.5a  dividendo
## 1         -0.1685880   -0.11441606 -0.6327376
## 2         -0.1341853    0.10409040 -0.9943019
## 3          7.5885806   -0.04666141  0.9943019
## 4          0.3248024   -0.06197669  0.8352136
## 5         -0.4583754    1.15791618 -0.9943019
## 6         -0.5650754   -0.93747588  0.9943019
## 7         -0.3101810   -0.16504258  0.9943019
## 8         -0.2716504   -0.20490717  0.9943019
## 9         -0.4680080   -0.12692111  0.1657170
## 10        -0.3322249    0.28188042  0.4971510
## 
## Clustering vector:
##  MGLU3  EMBR3  HAPV3  RAIL3  NTCO3 IGTI11  CASH3  COGN3  BRFS3  VIIA3  CVCB3 
##      2      2      5      2      2      2      2      2      2      2      4 
##  IRBR3  AZUL4  GOLL4  MRFG3  BRAP4  USIM5  GOAU4  GGBR4  PETR4  JBSS3  PETR3 
##      2      2      2      4      6      4      4      4      7      4      7 
##  PCAR3  VALE3  BRKM5  BBAS3  CSNA3  SUZB3 KLBN11  CPLE6  ENBR3  JHSF3  DXCO3 
##      2      7      4      9      4      4      4      4      4     10      4 
##  ITSA4 ENGI11 TAEE11  CSAN3  BBDC3 SANB11  CCRO3  CPFE3  VBBR3  CYRE3  QUAL3 
##     10      4     10      4      9      9      4      4      2      4      4 
##  EQTL3  BBDC4  UGPA3  CMIG4  PRIO3  ITUB4  MRVE3  EZTC3  BEEF3  TIMS3  BBSE3 
##      2      9      4      4     10      9      2     10      3      4      1 
##  CIEL3  VIVT3  BPAN4  SBSP3  FLRY3  ASAI3  BRML3 BPAC11  CRFB3  B3SA3  LCAM3 
##      8      9      9      9      4      1     10      9      2     10      4 
##  ABEV3  ELET3  EGIE3  ELET6  HYPE3  ENEV3  MULT3  ECOR3  LREN3 SULA11  SOMA3 
##      1      9      4      9      1      2     10      2      1      2      2 
##  ALPA4  RENT3  AMER3  WEGE3  TOTS3  RADL3  RDOR3  PETZ3 BIDI11  YDUQ3  LWSA3 
##      1      1      9      1      1      1      1      2      2      2      2 
## 
## Within cluster sum of squares by cluster:
##  [1] 101.74543 209.66266   0.00000 151.15266   0.00000   0.00000  33.11929
##  [8]   0.00000  56.47886 155.01812
##  (between_SS / total_SS =  61.3 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
clusplot(norm, 
         km.res$cluster, 
         main = 'Representação 2D dos clusters',
         color = TRUE, 
         shade = TRUE,
         labels = 2, 
         lines = 0)

options(ggrepel.max.overlaps = 30)
fviz_cluster(km.res, data = norm,
             pallete = 'rickandmorty',
             ellipse.type = "euclid", # elipse de concentração
             star.plot = TRUE,# adiciona segmentos dos centróides
             repel = TRUE, # evita sobreposição de rótulos
             ggtheme = theme_minimal()
)