Uploaded by fercastronandes

Study Cas - Datascience

advertisement
UNIVERSIDADE FEDERAL DE GOIÁS
ESCOLA DE ENGENHARIA ELÉTRICA, MECÂNICA E DE COMPUTAÇÃO
CURSO DE GRADUAÇÃO EM ENGENHARIA DE COMPUTAÇÃO
Datascience para o Mercado Financeiro
Modelos de Machine Learning
Lara Portilho Marques
Fernanda de Castro
Fernandes
Orientador: Thyago Carvalho
Marques
Goiânia
Novembro/2022
Índice
●
●
●
Big Data Analytics
Modelos Supervisionados
○ KNN
○ SVM
○ Naive Bayes
○ Random Forest
○ Redes Neurais Artificiais
Modelos Não supervisionado
○ Processamento de linguagem natural
○ Redes Neurais Profundas
○ K-Means Clustering
○ Agglomerative Clustering
○ DBSCAN
Big Data Analytics
Pode ser definido como os datasets cujo tamanho ou tipo estão além da habilidade
de um banco de dados relacional tradicional de captura, gerenciamento e processamento
de dados com baixa latência. Esses datasets incluem dados estruturados,
semi-estruturados e não estruturados, de diferentes fontes e tamanhos.Tais dados vêm de
diferentes fontes, como dispositivos móveis, redes sociais, IoT, gerando um altíssimo
volume de informações.
Há várias utilizações do Big Data Analytics, como fonte de tomadas de decisão,
modelagem e predição de possíveis consequências futuras, fortalecimento da inteligência
de mercado (B.I). Outro benefício é a redução de custo e aumento da eficiência operacional,
tendo em vista que um processamento flexível de dados pode ser mais econômico ao
armazenar e analisar grandes volumes de dados.
Aprendizado Supervisionado x Aprendizado Não Supervisionado
Antes de falar sobre os tipos de aprendizado de máquina, é preciso definir o que é o
Machine Learning (aprendizado de máquina ou ML). É definido por um sistema
computacional que deve realizar uma tarefa, aprendendo a partir de uma experiência,
enquanto procura melhorar sua performance.
Em outras palavras, um algoritmo pode aprender a realizar algo partindo de um
grande volume de inputs (dados), que representam as experiências da máquina. O
aprendizado visa um generalismo que se encaixe na maioria dos casos, obtendo uma boa
performance, e para isso, quanto mais dados melhor.
Sabendo disso, pode-se passar para os tipos de Machine Learning. O primeiro é o
aprendizado supervisionado: tenta-se prever uma variável dependente a partir de outras
variáveis independentes. No treinamento de modelos supervisionados, o dataset utilizado
contém a resposta desejada, seja a classificação a ser prevista ou o dado faltante buscado.
O outro tipo abordado neste documento é o aprendizado não supervisionado. Este
tipo trabalha com problemas em que a posse de dados anotados (com resposta) são
inviáveis, seja pelo custo ou pela mera impossibilidade de obtenção. Algumas soluções para
tais problemas são a observação em busca de padrões de repetição, de associação entre
ações, em suma, a observação para captar alguma regra associativa entre os dados
presentes.
Modelos Supervisionados
KNN (K-Nearest Neighbors)
KNN é um tipo de algoritmo de aprendizagem supervisionada usado no campo de
data mining e machine learning. Ele funciona como um classificador no qual o aprendizado
é baseado em quão similar um dado ou vetor é de outro.
É usado principalmente em problemas de classificação e de regressão. Sua
modelagem matemática é feita pelo cálculo da distância entre os grupos já conhecidos e o
novo objeto que se deseja inserir no dataset. Com isso, pode-se prever o comportamento
de tal objeto, tendo como base a análise de um número pré determinado de amostras com
menor distância do novo ponto. Esse número K de vizinhos é definido no treinamento do
modelo e dá nome ao algoritmo.
Algumas das aplicações de KNN no mundo real são sistemas de recomendação,
como o utilizado pelo YouTube, Netflix e outros serviços de streaming. Também como
ferramenta de busca por documentos semanticamente semelhantes, sendo eficaz em busca
de plágio, por exemplo. Detecção de fraudes de cartão de crédito por reconhecimento de
padrões de comportamento, análise de escore de crédito para empréstimos, predição de
preços de ações, são alguns dos múltiplos usos cotidianos de KNN.
São vantagens desse modelo a sua simplicidade na implementação e teoria,
trazendo bons resultados em várias aplicações. Enquanto isso, suas desvantagens são a
sensibilidade a ruídos nos dados e o custo computacional (tanto em complexidade de tempo
quanto de espaço), dado que a cada adição, deve-se calcular a distância entre todos os
outros exemplos (o algoritmo memoriza o treinamento, toda nova predição usa toda a base
para realizar as comparações esperadas). Entretanto, isso pode ser minimizado pela
criação de um centróide para cada grupo catalogado. Além disso, o algoritmo não é
sensível aos outliers, pontos de uma classe que são mais próximos de outra classe do que
com a original, parecendo ser da outra.
O cálculo da distância é simples, podendo ser a clássica distância euclidiana ou
outras, como a Manhattan, Hamming, Minkowski, Chebyshev, dentre outras. Algumas das
fórmulas de distância bastante utilizadas:
Distância Euclidiana:
Distância Manhattan: Sendo ‘a’ e ‘b’ vetores de N dimensões, a distância manhattan
é calculada pela soma dos módulos das diferenças entre cada posição dos vetores.
Distância Minkowski: É uma distância pensada para espaços vetoriais de valores
reais. É entendida como uma generalização das duas distâncias anteriormente comentadas,
pois quando p=1, obtemos o resultado da Manhattan, e quando p=2, obtemos a distância
euclidiana.
Passos para implementação:
1. Ler o dataset que será usado, ver a quantidade de pontos existentes e quantas
características são relevantes para o modelo.
2. Separar o dataset em inputs e targets, sendo o target a coluna que se deseja prever,
enquanto o input serão todas as outras colunas.
3. Dividir os dados presentes no dataset para o treinamento e testagem. Com isso,
pode-se ter noção de como o modelo performa com dados não vistos.
4. Construção e treinamento do modelo, definindo o K para maior acurácia. Sugestão:
escolher K ímpar ou primo a quantidade de grupos conhecidos.
5. Testagem e checagem da acurácia.
Observação: existe um método de validação do modelo que se chama
Cross-Validation, que é a divisão do dataset em P partes. Uma parte será usada para
treinamento e as outras serão os grupos de testagem, resultando numa métrica de acurácia.
Então o processo é repetido até que todas as partes tenham sido usadas no treinamento do
modelo. Com esse método, temos mais conhecimento de como o modelo se porta com
novos dados, visto que o processo de divisões no dataset tem influência na performance do
modelo.
KNN para classificação:
# KNN
library(caret)
library(pROC)
library(mlbench)
# Example-1 Classification
data <read.csv('https://raw.githubusercontent.com/bkrai/Statistical-Modeling-a
nd-Graphs-with-R/main/binary.csv')
str(data)
data$admit[data$admit == 0] <- 'no'
data$admit[data$admit == 1] <- 'yes'
data$admit <- factor(data$admit)
data$rank <- factor(data$rank)
# Data partition
set.seed(1234)
ind <- sample(2, nrow(data), replace = T, prob=c(.7, .3))
training <- data[ind==1, ]
test <- data[ind==2, ]
# K-NN
trControl <- trainControl(method = "repeatedcv", #repeated
cross-validation
number = 10, # number of resampling
iterations
repeats = 3, # sets of folds to for repeated
cross-validation
classProbs = TRUE,
summaryFunction = twoClassSummary) #
classProbs needed for ROC
set.seed(1234)
fit <- train(admit ~ .,
data = training,
tuneGrid
= expand.grid(k = 1:50),
method = "knn",
tuneLength = 20,
metric
= "ROC",
trControl = trControl,
preProc = c("center", "scale")) # necessary task
# Model performance
fit
plot(fit)
varImp(fit)
pred <- predict(fit, newdata = test )
confusionMatrix(pred, test$admit, positive = 'yes' )
SVM - Support Vector Machine
É um algoritmo de aprendizado de máquina supervisionado que pode ser usado
para desafios de classificação ou regressão, com maior foco no treinamento e classificação
de um dataset. Uma SVM trabalha com a construção de hiperplanos em um espaço
n-dimensional para classificar ou regredir dados.
Aqui, cada item de dados é plotado como um ponto no espaço n-dimensional (n é o
número de recursos que você tem) com o valor de cada recurso ocupando a posição de
uma coordenada. Então, buscamos o hiperplano que melhor diferencia as duas classes.
Os vetores de suportes que dão nome ao algoritmo são as coordenadas de
observação individual, com a SVM sendo, de certa forma, uma fronteira que separa as
classes. Para definir o melhor hiperplano, procuramos o que tem a melhor margem de
distância entre a fronteira e os grupos.
Entretanto, resta saber como lidar com os outliers, os pontos de uma classe que se
encontram no território de outra. A SVM tem um recurso de ignorar pontos ou valores muito
discrepantes e ainda encontrar o hiperplano que tem margem máxima, portanto sendo
robusto a outliers.
Há também casos em que o plano linear a qual estamos acostumados a pensar não
aceita um vetor de suporte que realmente classifique o dataset. Para isso, há o truque de
kernel, uma ferramenta advinda da álgebra linear para a transformação do espaço vetorial
em outra base a fim de que consigamos segregar corretamente os dados no espaço. Essa
conversão entre os espaços de entrada dimensional baixa para um outro de nível superior
serve para a conversão de problemas não separáveis para separáveis. A ferramenta usada
são funções chamadas de núcleo.
Por fim, as estimativas de probabilidade não são oferecidas diretamente, sendo
necessário calcular por validações cruzadas.
Vantagens:
● Boa funcionalidade com margens de separação claras entre os grupos;
●
●
Eficaz quando o número de dimensões é maior que o número de amostras;
Uso de subconjuntos de pontos de treinamento na função de decisão(vetores de
suporte), tendo uma certa eficiência em termos de memória;
Desvantagens:
● Desempenho aquém quando se há um grande conjunto de dados já que será
necessário um grande tempo para treinamento do modelo;
● Não funciona muito bem com conjuntos de dados mais sujos, com maior ruído, onde
as classes estão mais sobrepostas;
Modelagem matemática de SVM
Um hiperplano é definido pela equação w.x + b = 0, sendo derivada de vetores
bidimensionais x = (x1,x2) e w = (a, -1), entretanto ela vale para qualquer número de
dimensões.
O classificador usado para fazer predições é chamado de função hipótese h:
Pontos acima ou no hiperplano serão classificados como classe +1, e pontos abaixo
do hiperplano serão classificados como classe -1.
Buscando encontrar métricas que não sofram variações de escala e que sejam a
melhor métrica de comparação possível, usamos o conceito de margem geométrica:
Os problemas de encontrar possíveis valores para ‘w’ e para ‘b’ são chamados de
problemas de otimização, o que significa que buscamos o valor máximo de M:
SVM para classificação:
# Support Vector Machine
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Importing the datasets
datasets = pd.read_csv('Social_Network_Ads.csv')
X = datasets.iloc[:, [2,3]].values
Y = datasets.iloc[:, 4].values
# Splitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_Train, X_Test, Y_Train, Y_Test = train_test_split(X, Y, test_size =
0.25, random_state = 0)
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
X_Train = sc_X.fit_transform(X_Train)
X_Test = sc_X.transform(X_Test)
# Fitting the classifier into the Training set
from sklearn.svm import SVC
classifier = SVC(kernel = 'linear', random_state = 0)
classifier.fit(X_Train, Y_Train)
# Predicting the test set results
Y_Pred = classifier.predict(X_Test)
# Making the Confusion Matrix
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(Y_Test, Y_Pred)
# Visualising the Training set results
from matplotlib.colors import ListedColormap
X_Set, Y_Set = X_Train, Y_Train
X1, X2 = np.meshgrid(np.arange(start = X_Set[:, 0].min() - 1, stop =
X_Set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_Set[:, 1].min() - 1, stop =
X_Set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(),
X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(Y_Set)):
plt.scatter(X_Set[Y_Set == j, 0], X_Set[Y_Set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Support Vector Machine (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
# Visualising the Test set results
from matplotlib.colors import ListedColormap
X_Set, Y_Set = X_Test, Y_Test
X1, X2 = np.meshgrid(np.arange(start = X_Set[:, 0].min() - 1, stop =
X_Set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_Set[:, 1].min() - 1, stop =
X_Set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(),
X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(Y_Set)):
plt.scatter(X_Set[Y_Set == j, 0], X_Set[Y_Set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Support Vector Machine (Test set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
Naive Bayes
Naive Bayes, também chamado de Idiot Bayes, é um algoritmo de classificação para
problemas binomiais ou multinomiais. Naive, em inglês, significa inocente e, o motivo dessa
nomenclatura se deve à sua premissa: as variáveis de um problema são independentes e
de igual importância para o resultado, algo que não acontece com tanta frequência no
mundo real. Ele utiliza cálculos probabilísticos baseados no Teorema de Bayes:
P(A|B) = P(B|A) x P(A) / P(B)
onde P(A) é a probabilidade de A acontecer, P(B) é a probabilidade de B acontecer, P(B|A)
é a probabilidade de de B acontecer sendo que A já aconteceu e P(A|B) o inverso.
Para demonstrar com maior facilidade o teorema, utilizaremos o seguinte exemplo:
●
●
●
●
1000 maçãs foram colhidas e pesadas
30% das maçãs pesavam menos de 140 gramas
60% das maçãs leves estavam impróprias para o consumo
20% das maçãs pesadas estavam com impróprias para o consumo
Com base nessas informações, qual a probabilidade de, caso uma maçã seja imprópria
para o consumo, ela pese menos de 140 gramas?
Primeiramente, transformaremos as variáveis para os termos da equação
P(A) = prob. de ser leve
P(B) = prob. de ser imprópria para consumo
P(A|B) = prob. de ser leve sendo que é confirmado que é imprópria
P(B|A) = prob. de ser imprópria sendo que é confirmado que é leve
Assim: P(leve|imprópria) = P(imprópria|leve) x P(leve) / P(imprópria)
Sabendo que a probabilidade de de uma maçã ser imprópria para o consumo é a soma das
probabilidades de ela ser leve e imprópria e de ser pesada e imprópria, temos:
P(leve|imprópria) = 0,6 x 0,3 / (0,6 x 0,3 + 0,2 x 0,7)
P(leve|imprópria) = 0,18 / (0,18 + 0,14)
P(leve|imprópria) = 0,5625
Logo, a probabilidade de ela ser leve sabendo-se que é imprópria para o consumo é de
56,25%.
No modelo, é feita uma tabela de frequências para cada variável e, assim, calculada
cada probabilidade.
Os jogadores vão jogar (play) se estiver com com sol (sunny)?
P(sim|sol) = P(sol|sim) x P(sim) / P(sol)
P(sim|sol) = 3/9 x 9/14 / 5/14
P(sim|sol) = 0,599999999 = 60%
Vantagens:
● Simples e rápido com bom desempenho;
● Necessita de apenas um pequeno número de dados para uma boa precisão;
● Quando o modelo já é compatível com independência das variáveis, o modelo é
melhor do que os de regressão;
Desvantagens:
● Modelo raramente representa o mundo real onde todas as variáveis são
independentes;
● Caso uma variável não seja observada, a sua frequência será 0 e não será possível
realizar as estimativas;
Usos:
● Classificação de textos;
● Predições de real time;
● Sistemas de recomendação;
Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Importing the dataset
dataset = pd.read_csv('Social_Network_Ads.csv')
X = dataset.iloc[:, [2, 3]].values
y = dataset.iloc[:, -1].values
# Splitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size =
0.20, random_state = 0)
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
# Training the Naive Bayes model on the Training set
from sklearn.naive_bayes import GaussianNB
classifier = GaussianNB()
classifier.fit(X_train, y_train)
# Predicting the Test set results
y_pred = classifier.predict(X_test)
# Making the Confusion Matrix
from sklearn.metrics import confusion_matrix, accuracy_score
ac = accuracy_score(y_test,y_pred)
cm = confusion_matrix(y_test, y_pred)
Random Forest
O Random Forest é um modelo de classificação e regressão amplamente utilizado
em machine learning devido a sua flexibilidade e facilidade de uso. Em suma, essa técnica
utiliza a combinação de várias árvores de decisão para gerar um único resultado.
As árvores de decisão, em inglês decision trees, iniciam com uma condição que
analisa e “guia” uma um dado ou amostra para um certo grupo, que por sua vez passa
também por uma outra condição e, assim, vai filtrando esse dado até chegar a uma
conclusão final. Por exemplo: é necessário descobrir se o público irá comprar um certo
celular. Então esse celular passa por uma árvore de decisão. A primeira condição é o preço,
se for barato o celular será comprado, se for caro, passa para outra condição, e assim
sucessivamente. No final, a árvore retorna o valor, neste caso se vai ou não ser comprado.
O Random Forest é a junção de diversas árvores de decisão, cada qual com uma
amostra de dados diferente. Para ser usada como um algoritmo de classificação, a moda
dos resultados de todas as árvores é escolhida, enquanto que, para a regressão, é a média
dos resultados. Seguindo o exemplo dos celulares, agora é necessário saber qual modelo
de celular as pessoas mais irão gostar. Assim, junta-se todos os modelos de uma empresa
e são separados diferentes amostras de forma aleatória contendo um número x de
aparelhos. Cada amostra então passa por uma árvore diferente, que gera como resposta
um único modelo de celular. Por fim, os resultados são analisados e aquele que tiver maior
frequência será declarado como o mais popular.
Vantagens:
● Em comparação com árvores de decisão simples, o Random Forest minimiza o risco
de sobreajuste;
● Flexibilidade para trabalhar com regressão ou classificação;
● Modelo robusto que aguenta grande volume de dados;
Desvantagens:
● Problemas de alta complexidade não funcionam tão bem nesse modelo;
● Ele precisa de um volume de dados maior do que alguns outros modelos;
Usos:
● Instituições bancárias para determinar aprovação de crédito;
● Clinicamente para diagnosticar doenças;
● Preferência de produtos em e-commerces;
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Importing the datasets
datasets = pd.read_csv('Social_Network_Ads.csv')
X = datasets.iloc[:, [2,3]].values
Y = datasets.iloc[:, 4].values
# Splitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_Train, X_Test, Y_Train, Y_Test = train_test_split(X, Y, test_size =
0.25, random_state = 0)
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
X_Train = sc_X.fit_transform(X_Train)
X_Test = sc_X.transform(X_Test)
# Fitting the classifier into the Training set
from sklearn.ensemble import RandomForestClassifier
classifier = RandomForestClassifier(n_estimators = 200, criterion =
'entropy', random_state = 0)
classifier.fit(X_Train,Y_Train)
# Predicting the test set results
Y_Pred = classifier.predict(X_Test)
# Making the Confusion Matrix
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(Y_Test, Y_Pred)
# Visualising the Training set results
from matplotlib.colors import ListedColormap
X_Set, Y_Set = X_Train, Y_Train
X1, X2 = np.meshgrid(np.arange(start = X_Set[:, 0].min() - 1, stop =
X_Set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_Set[:, 1].min() - 1, stop = X_Set[:, 1].max() + 1,
step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(),
X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(Y_Set)):
plt.scatter(X_Set[Y_Set == j, 0], X_Set[Y_Set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Random Forest Classifier (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
# Visualising the Test set results
from matplotlib.colors import ListedColormap
X_Set, Y_Set = X_Test, Y_Test
X1, X2 = np.meshgrid(np.arange(start = X_Set[:, 0].min() - 1, stop =
X_Set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_Set[:, 1].min() - 1, stop = X_Set[:, 1].max() + 1,
step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(),
X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(Y_Set)):
plt.scatter(X_Set[Y_Set == j, 0], X_Set[Y_Set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Random Forest Classifier (Test set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
# Random Forest Classifier
Redes Neurais Artificiais
O que são redes neurais?
É um método de inteligência artificial que ensina computadores a processar
dados se inspirando no cérebro humano. Dentro da machine learning, é um tipo de
processo de aprendizado profundo, que usa nós (neurônios) interconectados em estruturas
de camadas, tal qual o cérebro humano faz com os neurônios e seus links. Elas criam
sistemas adaptativos em que os computadores aprendem com os erros e continuamente
corrigem seus processos de solução de problemas, aumentando a precisão de suas
respostas.
Redes neurais artificiais costumam ser compostas por camadas de um nó, contendo
uma camada de entrada, pelo menos uma camada oculta de processamento e uma única
camada de saída. As conexões entre neurônios possuem pesos e limites associados, os
quais são constantemente corrigidos à medida que o modelo é treinado e aprende como
chegar de forma mais eficiente em um resultado suficientemente próximo de um output
desejado.
Além disso, redes neurais podem ajudar computadores a tomar decisões mais
inteligentes com menor assistência humana, tendo em vista que o aprendizado deles em
como compreender e relacionar os modelos e dados de entrada/saída de forma complexa e
não linear. Assim, são capazes de realizar generalizações e inferências sobre dados não
estruturados, ainda que não recebam treinamento explícito para aquelas atividades. Por
exemplo, uma rede neural saberia que a Av. Castelo Branco é um lugar e que Castelo
Branco era o nome de uma pessoa.
Alguns de seus usos:
● Diagnóstico médico feito por classificação de imagem
● Marketing direcionado por filtros de mídias sociais e análise de dados
comportamentais
● Previsões financeiras feitas pelo processamento de dados históricos
● Previsões de demandas de energia e carga elétrica
● Processo e controle de qualidade
● Identificação de compostos químicos
● Visão Computacional
● Reconhecimento de voz
● Processamento de linguagem natural
● Mecanismos de recomendação
Vantagens e desvantagens das RNA’s:
Vantagens:
● Armazena as informações em toda a rede, e não num banco
de dados. O sumiço de alguma informação não atrapalha o
funcionamento da rede visto que ela já vai ter aprendido com
aquele pedaço de dado.
● Consegue trabalhar com conhecimento incompleto, tendo
outputs ainda que a performance caia a depender da
importância da informação
● Tem tolerância a falhas, a corrupção de neurônios da RNA não
trava a geração de outputs.
●
Tem memória distribuída. Para que o aprendizado da RNA
aconteça, é preciso determinar exemplos para ensinar a rede
de acordo com os outputs desejados. O sucesso dela é
proporcional às instâncias selecionadas, e a rede pode
produzir outputs falsos, caso o evento não possa ser mostrado
para a rede em todos seus aspectos.
● A corrupção da rede é gradual, dado que ao longo do tempo
ela se torna mais lenta. Ela não para abruptamente.
● Capaz de realizar aprendizado de máquina.
● Capaz de realizar processamento paralelo, fazendo mais de
um “trabalho” por vez.
Desvantagens:
● Depende de um hardware poderoso, capaz de realizar
processamento paralelo, de acordo com a estrutura da RNA.
● Incapacidade de explicar o comportamento da rede ao
solucionar um problema. Não há dicas de como ou porque
chegou àquela solução. Logo, há menos confiança na rede.
● Alto ciclo de tentativas e erros acontecem tentando chegar na
estrutura ideal da rede neural, tomando um tempo
considerável.
● Necessidade de tradução do problema para valores numéricos
a fim de ser introduzido para a RNA, dependendo, portanto, da
habilidade do usuário para o funcionamento do mecanismo.
● Duração da rede desconhecida. A queda dos valores de erros
nos testes significa apenas que a etapa de treinamento foi
concluída, não dizendo se foram os resultados mais propícios.
Modelagem matemática
Uma rede neural é definida como uma função multivariável composta por tantas
funções quanto camadas existem nesta rede. O domínio e o contradomínio são conjuntos
reais da mesma dimensão do input e output, respectivamente.
Cada uma dessas funções que compõem a função geral são funções compostas
pela combinação linear de um input ‘x’ com um peso ou coeficiente ‘w’, mais um viés ‘b’
(bias), tudo isso multiplicado por um coeficiente ‘a’ chamado de função de ativação, igual
em cada função intermediária.
O fator de ativação varia de acordo com a natureza do objetivo que se quer atingir.
Por exemplo, em regressões, usa-se a função identidade como ativação. Logo, só existe a
combinação linear na função.
Em tarefas de classificação binárias, o fator de ativação é o sigmóide, uma função
cujos valores variam entre 0 e 1.
Para facilitar a associação entre o modelo matemático e a estrutura da rede neural:
os nós de input são o parâmetro “x” da função f(x), a camada de output representa o próprio
valor de f(x), as camadas ocultas são representadas pelas funções intermediárias, e por fim,
os links entre os nós, ou sinapses, para continuar a analogia entre o modelo e a
organização de um cérebro, são representados pelos pesos “w”.
Treinamento de uma ANN para predição da taxa de churn em um banco, criado por
u/TatevKaren:
#----------------------- Artificial Neural Network for classification
--------------------#
#importing required libraries
import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from
from
from
from
sklearn.preprocessing import LabelEncoder
sklearn.model_selection import train_test_split
sklearn.preprocessing import StandardScaler
sklearn.metrics import confusion_matrix, accuracy_score
#----------------------- Data Pre-processing ----------------------#
# Checking the tensorflow version
print(tf.__version__)
# Loading the data
bank_data = pd.read_csv("Artificial_Neural_Network_Case_Study_data.csv")
# Taking all rows and all columns in the data except the last column as
X (feature matrix)
#the row numbers and customer id's are not necessary for the modelling
so we get rid of and start with credit score
X = bank_data.iloc[:,3:-1].values
print("Independent variables are:", X)
#taking all rows but only the last column as Y(dependent variable)
y = bank_data.iloc[:, -1].values
print("Dependent variable is:", y)
# Transforming the gender variable, labels are chosen randomly
le = LabelEncoder()
X[:,2] = le.fit_transform(X[:,2])
print(X)
# Transforming the geography column variable, labels are chosen
randomly, the ct asks for argument [1] the index of the target vb
ct = ColumnTransformer(transformers = [('encoder',
OneHotEncoder(),[1])], remainder = 'passthrough')
X = np.array(ct.fit_transform(X))
print(X)
# Splitting the data into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size =
0.2, random_state = 0)
#printing the dimensions of each of those snapshots to see amount of
rows and columns i each of them
print(X_train.shape, X_test.shape)
print(y_train.shape, y_test.shape)
# Data Scaling/normalization of the features that will go to the NN
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
#----------------------- Building the model -----------------------#
# Initializing the ANN by calling the Sequential class fromm keras of
Tensorflow
ann = tf.keras.models.Sequential()
#--------------------------------------------------------------------------------# Adding "fully connected" INPUT layer to the Sequential ANN by calling
Dense class
#--------------------------------------------------------------------------------# Number of Units = 6 and Activation Function = Rectifier
ann.add(tf.keras.layers.Dense(units = 6, activation = 'relu'))
#--------------------------------------------------------------------------------# Adding "fully connected" SECOND layer to the Sequential AMM by calling
Dense class
#--------------------------------------------------------------------------------# Number of Units = 6 and Activation Function = Rectifier
ann.add(tf.keras.layers.Dense(units = 6, activation = 'relu'))
#--------------------------------------------------------------------------------# Adding "fully connected" OUTPUT layer to the Sequential ANN by calling
Dense class
#--------------------------------------------------------------------------------# Number of Units = 1 and Activation Function = Sigmoid
ann.add(tf.keras.layers.Dense(units = 1, activation = 'sigmoid'))
#----------------------- Training the model -----------------------#
# Compiling the ANN
# Type of Optimizer = Adam Optimizer, Loss Function = crossentropy for
binary dependent variable, and Optimization is done w.r.t. accuracy
ann.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics =
['accuracy'])
# Training the ANN model on training set (fit method always the same)
# batch_size = 32, the default value, number of epochs = 100
ann.fit(X_train, y_train, batch_size = 32, epochs = 100)
#----------------------- Evaluating the Model ---------------------#
# the goal is to use this ANN model to predict the probability of the
customer leaving the bank
# Predicting the churn probability for single observations
#Geography: French
#Credit Score:600
#Gender: Male
#Age: 40 years old
#Tenure: 3 years
#Balance: $60000
#Number of Products: 2
#with Credit Card
#Active member
#Estimated Salary: $50000
print(ann.predict(sc.transform([[1, 0, 0, 600, 1, 40, 3, 60000, 2, 1, 1,
50000]])))
print(ann.predict(sc.transform([[1, 0, 0, 600, 1, 40, 3, 60000, 2, 1, 1,
50000]])) > 0.5)
# this customer has 4% chance to leave the bank
#show the vector of predictions and real values
#probabilities
y_pred_prob = ann.predict(X_test)
#probabilities to binary
y_pred = (y_pred_prob > 0.5)
print(np.concatenate((y_pred.reshape(len(y_pred),1),
y_test.reshape(len(y_test),1)), 1))
#Confusion Matrix
confusion_matrix = confusion_matrix(y_test, y_pred)
print("Confusion Matrix", confusion_matrix)
print("Accuracy Score", accuracy_score(y_test, y_pred))
Modelos Não Supervisionado
Redes Neurais Profundas
Redes neurais profundas, assim como as redes neurais artificiais, usam de camadas
e mais camadas de neurônios matemáticos para processar fala humana e para visão
computacional, que é a classificação e reconhecimento de objetos em imagens ou vídeos.
Como é dividida em camadas, a primeira recebe o nome de Input Layer (camada de input),
as camadas intermediárias de processamento são chamadas de Hidden Layers (camadas
ocultas), e a última camada se chama Output Layer (camada de saída). Cada uma dessas
camadas contém um tipo simples de função de ativação.
Conceito
As redes neurais profundas ( também chamadas de DNN) fazem parte da
grande família de algoritmos e métodos de Machine Learning (aprendizado de máquina)
baseado em redes neurais artificiais com feature learning. Esse aprendizado pode ser
supervisionado ou não, sendo nesse caso não supervisionado, o que permite que o modelo
aprenda padrões enquanto observa os casos de treinamento.
As redes neurais que abordaremos aqui serão as redes neurais
convolucionais (também chamada de CNN), um tipo de DNN bastante utilizado. Por ser
uma rede neural, seu funcionamento visa imitar o aprendizado do cérebro humano.
Alguns dos usos mais comuns de CNN são para reconhecimento ou
classificação de objetos em imagens. São exemplos práticos disso: programas que
interpretam caligrafia ou documentos impressos, o algoritmo de reconhecimento de rostos
no Google Fotos (pasta “Pessoas”, “Paisagens” etc), o ensino de um sistema de navegação
de carros sem motoristas que precisam diferenciar pessoas, objetos e outros carros com
alta precisão a fim de não colocar vidas em perigo.
O funcionamento de redes neurais profundas é idêntico ao das redes neurais
artificiais, contendo apenas mais hidden layers, tendo em vista que uma rede neural artificial
geralmente contém até 3 camadas. Algumas CNN 's chegam a ter até 100 camadas.
Classes de problemas e usos
São aplicações das redes neurais convolucionais o reconhecimento de
imagens e vídeos, classificação e segmentação de imagem, sistemas de recomendação,
processamento de linguagem natural, interfaces cérebro-máquina, análise de imagens
médicas e no mercado financeiro.
A CNN realmente brilha quando o problema é classificação de imagens, por
ter um pré-processamento relativamente baixo comparado a outros algoritmos. Como ele
aprende a otimizar os filtros que compõem as imagens pelo aprendizado automatizado, ao
invés de usar a famigerada “mão na massa”, funcionando como uma grande vantagem.
Definição teórica e modelagem matemática
Redes neurais convolucionais são tipos especialistas de redes neurais que
utilizam a convolução como operação matemática ao processar os sinais de input ao invés
de compactar todas as entradas num vetor ou matriz para realização dos cálculos
necessários.
Esse processo faz uso de uma janela de análise dos pixels da imagem de entrada,
chamado também de kernel. A imagem é formada por vários filtros (pense em uma imagem
colorida por RGB, ela conteria 3 filtros da mesma imagem em cada uma das cores
principais). O kernel desliza sobre a imagem, aplicando a função convolução nos pixels da
imagem, passando apenas pelo seu espaço de análise.
Após a convolução, o dado processado passa para outra camada, que pode ser uma
camada de pooling, conexão total, não linearidade, tudo para classificar melhor o objeto. O
pooling funciona como redutor das dimensões da imagem por combinar os outputs de vários
neurônios em um único nó. Essas aglomerações ou clusters podem ser máximos ou
médios, usando os valores máximos locais dos neurônios ou os valores médios locais dos
neurônios para realizar a aglomeração.
A conexão total é a conexão de cada nó de uma camada a cada nó de uma outra
camada. Ajuda na classificação da imagem. Já a não linearidade são camadas de operação
da CNN que aproximam funções não lineares ou consegue prever a classe de uma função
que não segue um processo de decisão linear. Essa camada visa deixar a CNN mais
robusta, sendo capaz de realizar Data Augmentation, pela definição de uma matriz peso
extra.
Data Augmentation é nada mais que o processo de aumentar a quantidade e a
diversidade dos dados do dataset. Pensando numa imagem de uma cadeira, a data
augmentation seriam imagens editadas dessa mesma cadeira, por diferentes vistas, cores,
iluminação, distorção, e até diferentes tipos de cadeira.
Vantagens e Desvantagens
As vantagens deste algoritmo são os resultados precisos que ele
proporciona, podendo ser para modelos preditivos, interpretação de imagens e textos.
Desvantagens são a complexidade de treinamento do modelo, ainda mais com a maior
quantidade de camadas, a possibilidade de overfitting do modelo, a análise de seus
neurônios não dá um entendimento de como o aprendizado e análise são feitos.
Uso do dataset MNIST para reconhecimento de dígitos escritos à mão:
#importações dos pacotes necessarios
import tensorflow as tf
from tensorflow.keras import layers,models
from tensorflow import keras
import numpy as np
#carrega o dataset
(X_train, y_train) , (X_test, y_test) = keras.datasets.mnist.load_data()
#Scaling e teste do dataset
X_train = X_train / 255
X_test = X_test / 255
X_train[0]
X_train.shape
X_train = X_train.reshape(-1,28,28,1)
X_train.shape
X_test = X_test.reshape(-1,28,28,1)
X_test.shape
#Criando e treinando a CNN
convolutional_neural_network = models.Sequential([
layers.Conv2D(filters=25, kernel_size=(3, 3), activation='relu',
input_shape=(28,28,1)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
])
convolutional_neural_network.compile(optimizer='adam',
loss='sparse_categorical_crossentropy', metrics=['accuracy'])
convolutional_neural_network.fit(X_train, y_train, epochs=10)
#avaliando o modelo CNN
convolutional_neural_network.evaluate(X_test, y_test)
#Fazendo predicoes
y_predicted_by_model = convolutional_neural_network.predict(X_test)
y_predicted_by_model[0]
#getting probability score for each class digits
np.argmax(y_predicted[0])
y_predicted_labels = [np.argmax(i) for i in y_predicted]
y_predicted_labels[:5]
Processamento de linguagem natural
Algoritmos de processamento de linguagem natural (NLP) visam construir máquinas
que entendam e respondam por texto ou voz da mesma forma que um humano responderia.
É uma área bastante desafiadora, considerando as quase infinitas possibilidades de
formação de um discurso escrito ou falado, além dos regionalismos, divergências entre os
indivíduos falantes, emoções, ironias, dentre outros.
Conceito
É um ramo da inteligência artificial que permite às máquinas compreender,
manipular e até gerar linguagem humana. Ferramentas desse tipo já estão entranhadas na
sociedade, como o corretor ortográfico automático do celular, as assistentes virtuais, os
chatbox, filtros de spam no email, tradução automática de legendas no YouTube.
A compreensão de texto buscada com o NLP é a capacidade de reconhecer
o contexto, realizar análise sintática, léxica, morfológica e semântica, criar resumos, realizar
varreduras atrás de pedaços de informações, interpretar e analisar sentimentos e até
aprender conceitos advindos dos textos processados.
Usos
São usos da NLP: traduções de textos, sites, legendas automáticas de
vídeos, tradução simultânea, interpretação de sentimentos.
Outros usos interessantes são a otimização de mecanismos de pesquisa, a
análise de mídias sociais, moderação de conteúdos, agilizar o processo de organização de
documentos relevantes ao meio jurídico, seguradoras.
Definição teórica e modelagem matemática
Ferramentas NLP funcionam com a vetorização do texto, transformando o
texto em algo que a máquina consiga compreender. Um dos usos mais populares é a
análise de sentimento do texto. Se quisermos usar a análise de sentimentos em tweets, por
exemplo, como seria feito?
Existe uma api oficial do Twitter que nos permite coletar dados para construir
nosso dataset de textos de tweets. Alguns processamentos já podem ser feitos com os
dados crus, como a extração de emoções em hashtags (#sadreacts), tradução de emojis
em texto puro ( :thumbs_up: é a representação escrita do emoji do joinha). Com isso,
conseguimos mapear os termos e obter algumas indicações de emoções nas quais eles se
encaixam.
Com isso, passamos para o pré-processamento dos textos. Para isso, há a
remoção de caracteres especiais, de repetições e de stop words, e a conversão de
caracteres maiúsculos para minúsculo. Após esse tratamento inicial dos dados,
transformamos o texto em vetores para que o modelo de aprendizado consiga trabalhar.
Para os dados de saída, usando um classificador binário, quanto mais
positivo um tweet, maior será seu resultado, e por dedução, quanto mais negativo, menor
(mais próximo de zero) será o resultado.
Usando a relação entre termos e sentimentos e os resultados dados pelo
modelo classificador, conseguimos metrificar a emoção passada pelo tweet que usa um
emoji triste e o tweet que tem a hashtag #sadreacts.
Com esse dataset, conseguimos construir um modelo capaz de descobrir a
emoção mais presente num texto, ferramenta que teria grande uso nas agências de
marketing.
Vantagens e Desvantagens
As vantagens deste algoritmo são o aprendizado constante e a grande
quantidade de dados que podem ser processados de uma vez. E uma das desvantagens é
a falta de otimização da interpretação de formas mais complexas de comunicação, como
gírias, ambiguidades, ironias etc.
Pré-processamento do texto:
import re
import nltk
from time import time
from emoji import demojize
def preprocess(texts, quiet=False):
start = time()
# Lowercasing
texts = texts.str.lower()
# Remove special chars
texts = texts.str.replace(r"(http|@)\S+", "")
texts = texts.apply(demojize)
texts = texts.str.replace(r"::", ": :")
texts = texts.str.replace(r"'", "'")
texts = texts.str.replace(r"[^a-z\':_]", " ")
# Remove repetitions
pattern = re.compile(r"(.)\1{2,}", re.DOTALL)
texts = texts.str.replace(pattern, r"\1")
# Transform short negation form
texts = texts.str.replace(r"(can't|cannot)", 'can not')
texts = texts.str.replace(r"n't", ' not')
# Remove stop words
stopwords = nltk.corpus.stopwords.words('english')
stopwords.remove('not')
stopwords.remove('nor')
stopwords.remove('no')
texts = texts.apply(
lambda x: ' '.join([word for word in x.split() if word not in
stopwords])
)
if not quiet:
print("Time to clean up: {:.2f} sec".format(time() - start))
return texts
Tokenização:
import pickle
from tensorflow.keras.preprocessing.text import Tokenizer
num_words = 10000
tokenizer = Tokenizer(num_words=num_words, lower=True)
tokenizer.fit_on_texts(dataset.cleaned_data.text)
file_to_save = Path('../datasets/sentiment_analysis/tokenizer.pickle').resolve()
with file_to_save.open('wb') as file:
pickle.dump(tokenizer, file)
Modelo LSTM e CNN:
from
from
from
from
tensorflow.keras.layers
tensorflow.keras.layers
tensorflow.keras.layers
tensorflow.keras.models
import
import
import
import
Input, Embedding, SpatialDropout1D, LSTM
GlobalAveragePooling1D, GlobalMaxPooling1D
Bidirectional, Conv1D, Dense, concatenate
Model
input_dim = min(tokenizer.num_words, len(tokenizer.word_index) + 1)
num_classes = len(data.label.unique())
embedding_dim = 500
input_length = 100
lstm_units = 128
lstm_dropout = 0.1
recurrent_dropout = 0.1
spatial_dropout=0.2
filters=64
kernel_size=3
input_layer = Input(shape=(input_length,))
output_layer = Embedding(
input_dim=input_dim,
output_dim=embedding_dim,
input_shape=(input_length,)
)(input_layer)
output_layer = SpatialDropout1D(spatial_dropout)(output_layer)
output_layer = Bidirectional(
LSTM(lstm_units, return_sequences=True,
dropout=lstm_dropout, recurrent_dropout=recurrent_dropout)
)(output_layer)
output_layer = Conv1D(filters, kernel_size=kernel_size, padding='valid',
kernel_initializer='glorot_uniform')(output_layer)
avg_pool = GlobalAveragePooling1D()(output_layer)
max_pool = GlobalMaxPooling1D()(output_layer)
output_layer = concatenate([avg_pool, max_pool])
output_layer = Dense(num_classes, activation='softmax')(output_layer)
model = Model(input_layer, output_layer)
Análise de Score de Sentimento
data_dict = {}
query_dict = {
'query': [],
'mean': [],
'max': [],
'min': [],
'std': [],
'count': [],
'emotion': []
}
dir_files = os.listdir(dataset_dir)
with tqdm(total=len(dir_files)) as t:
for filename in dir_files:
dataset = pd.read_csv(os.path.join(dataset_dir, filename))
cleaned_texts = preprocess(dataset.text, quiet=True)
query = re.findall(r'(#[^.]+|:.+:)', filename)[0]
predict_sequences = [text.split() for text in cleaned_texts]
list_tokenized_predict = tokenizer.texts_to_sequences(predict_sequences)
x_predict = pad_sequences(list_tokenized_predict, maxlen=100)
result = model.predict(x_predict)
emotion = relations[query]
query_dict['query'].append(query)
query_dict['mean'].append(np.mean(result))
query_dict['max'].append(np.amax(result))
query_dict['min'].append(np.amin(result))
query_dict['count'].append(len(dataset))
query_dict['std'].append(np.std(result))
query_dict['emotion'].append(emotion)
if emotion in data_dict:
data_dict[emotion] = np.concatenate([data_dict[emotion], result])
else:
data_dict[emotion] = result
t.update()
Impressão da relação entre os sentimentos
df = pd.DataFrame(data=query_dict)
for emotion in df.emotion.unique():
display(df[df.emotion == emotion])
emotion_dict = {
'emotion': [],
'mean': [],
'max': [],
'min': [],
'std': [],
'count': []
}
for emotion, result in data_dict.items():
emotion_dict['emotion'].append(emotion)
emotion_dict['mean'].append(np.mean(result))
emotion_dict['max'].append(np.amax(result))
emotion_dict['min'].append(np.amin(result))
emotion_dict['std'].append(np.std(result))
emotion_dict['count'].append(len(result))
emotion_df = pd.DataFrame(data=emotion_dict)
display(emotion_df)
K-Means Clustering
O K-Means Clustering é um algoritmo não supervisionado utilizado para problemas
de classificação. Ele funciona à base de clusterização, ou seja, agrupamento de dados
semelhantes entre si. Em suma, primeiramente é escolhido uma quantidade K de clusters, e
depois K pontos aleatórios para servirem como centróides. Após cálculos matemáticos, o
centróide é ajustado até que a média das distâncias entre o centróide e os outros pontos de
seu cluster se tornem constantes.
Demonstrando um exemplo matemático, temos o seguinte grupo: S = {3, 4, 5, 11, 12,
13, 21, 26, 31}. Queremos dividir esse grupo em dois clusters, ou seja, K = 2. Os seguintes
passos são tomados:
1. São escolhidos aleatoriamente K = 2 valores para serem os centróides dos clusters.
Selecionamos 5 e 13 para serem esses valores, e os denominaremos de C1 = 5 e
C2 = 13;
2. Agrupamos os valores mais próximos de cada centróide de acordo com a distância
euclidiana em dois clusters: G1 = {3, 4, 5} em relação a C1 e G2 = {11, 12, 13, 21,
26, 31} em relação a C2;
3. Após isso, é feita uma média de G1 e G2: M1 =
11 + 12 + 13 + 21 + 26 + 31
6
3+4+5
3
= 4 e M2 =
= 19;
4. São refeitos os clusters, agora utilizando M1 e M2 como novos centróides: G1 = {3,
4, 5, 11} e G2 = {12, 13, 21, 26, 31}
5. Repete-se o passo 3 para encontrar novas médias (nesse caso, os valores são
arredondados): M1 =
3 + 4 + 5 + 11
4
= 5,75 = 6 e M2 =
12 + 13 + 21 + 26 + 31
5
= 20,6 = 21;
6. Continua-se o processo, repetindo as etapas 4 e 5 até que M1 e M2 se tornem
constantes: G1 = {3, 4, 5, 11, 12, 13} e G2 = {21, 26, 31};
7. M1 =
3 + 4 + 5 + 11 + 12 + 13
6
= 8 e M2 =
21 + 26 + 31
3
= 26;
8. G1 = {3, 4, 5, 11, 12, 13} e G2 = {21, 26, 31};
9. A partir deste ponto, como as médias não serão alteradas, os grupos também não
serão alterados, o que resulta em dois clusters bem definidos;
Vantagens:
● Facilidade na implementação do código;
● Consegue lidar com uma grande quantidade de dados por ter baixa complexidade;
● Facilmente adaptável para outros exemplos;
Desvantagens:
● Não lida bem com clusters de formatos variados;
● Não lida bem com ruídos, já que todos os pontos entram dentro de um cluster;
● O número de clusters deve ser definido previamente;
Casos de uso:
● Identificação de locais de crime;
● Detecção de fraudes;
● Classificação de documentos;
import
import
import
import
import
import
numpy as np
random
matplotlib.pyplot as plt
copy
os
imageio
class KMeans:
def __init__(self, n_cluster=3, random_state=721):
self.n_cluster = n_cluster
self.random_state = random_state
def fit(self, dataset):
self.X = dataset.iloc[:, [0, 1]] # not use feature labels
self.m = self.X.shape[0] # number of training examples
self.n = self.X.shape[1] # number of features.
initial_centroids = self.initialize_centroids()
self.plot_initial_centroids(initial_centroids)
self.clustering(initial_centroids)
def initialize_centroids(self):
initial_centroids = []
random.seed(self.random_state)
for i in range(self.n_cluster):
initial_centroids.append(np.ravel(self.X.iloc[(random.randint(0, self.m
- 1)), :]))
return np.array(initial_centroids)
def plot_initial_centroids(self, initial_centroids):
plt.scatter(self.X.iloc[:,0], self.X.iloc[:,1], c='#000000', s=7,
label='Data Points')
plt.scatter(initial_centroids[:, 0], initial_centroids[:, 1],
marker='*', s=120, c='r', label='Initial Centroids')
plt.title('Initial Random Cluster Centers')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.draw()
def clustering(self, centroids):
old_centroids = np.zeros(centroids.shape)
stopping_criteria = 0.0001
self.iterating_count = 0
self.objective_func_values = []
while self.euclidean_distance(old_centroids, centroids) >
stopping_criteria:
clusters = np.zeros(len(self.X))
# Assigning each value to its closest cluster
for i in range(self.m):
distances = []
for j in range(len(centroids)):
distances.append(self.euclidean_distance(self.X.iloc[i, :],
centroids[j]))
cluster = np.argmin(distances)
clusters[i] = cluster
# Storing the old centroid values to compare centroid moves
old_centroids = copy.deepcopy(centroids)
# Finding the new centroids
for i in range(self.n_cluster):
points = [self.X.iloc[j, :] for j in
range(len(self.X)) if clusters[j] == i]
centroids[i] = np.mean(points, axis=0)
# calculate objective function value for current cluster
centroids
self.objective_func_values.append([self.iterating_count,
self.objective_func_calculate(clusters, centroids)])
self.plot_centroids(centroids, clusters)
self.iterating_count += 1
self.plot_objective_function_values()
def plot_centroids(self, centroids, clusters):
colors = ["#4C72B0", "#DD8452", "#55A868", "#C44E52", "#8172B3",
"#937860", "#DA8BC3", "#8C8C8C", "#CCB974", "#64B5CD"]
fig, ax = plt.subplots()
for i in range(self.n_cluster):
points = np.array([self.X.iloc[j, :] for j in
range(len(self.X)) if clusters[j] == i])
ax.scatter(points[:, 0], points[:, 1], s=7, c=colors[i],
label='Cluster {}'.format(i + 1))
ax.scatter(centroids[:, 0], centroids[:, 1], marker='*', s=120,
c='#000000', label='Centroids')
plt.title('k-Means Clustering\n( Iteration count = {} Objective
Function value = {:.2f} )'
.format((self.iterating_count + 1),
np.array(self.objective_func_values)[self.iterating_count, 1]))
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.draw()
def euclidean_distance(self, a, b):
return np.sqrt(np.sum((np.array(a) - np.array(b))**2))
def objective_func_calculate(self, clusters, centroids):
"""Calculate objective function value for current centroids"""
# Calculate objective function value
distances_from_centroids = []
for i in range(self.n_cluster):
points = np.array([self.X.iloc[j, :] for j in
range(len(self.X)) if clusters[j] == i])
for k in range(len(points)):
distances_from_centroids.append(self.euclidean_distance(points[k, :],
centroids[i]))
return sum(distances_from_centroids)
def plot_objective_function_values(self):
"""This function plot graph of objective function value for each
iteration """
plt.figure()
plt.plot((np.array(self.objective_func_values)[:, 0] + 1),
np.array(self.objective_func_values)[:, 1], 'bo')
plt.plot((np.array(self.objective_func_values)[:, 0] + 1),
np.array(self.objective_func_values)[:, 1], 'k')
plt.title('Objective Function')
plt.xlabel('Iteration Number')
plt.ylabel('Objective Function Value')
plt.draw()
def save_figures(self, path):
"""Save all figures plotted with matplotlib to path directory"""
# create folder for png files
if not os.path.isdir(path):
os.makedirs(path)
# plt.get_fignums returns a list of existing figure numbers.
# then we save all existing figures
for i in plt.get_fignums():
plt.figure(i)
plt.savefig(os.path.join(path, "figure_{}.png".format(i)),
format='png')
# close all figure to clear figure numbers
plt.close("all")
print("Figures for the dataset saved in {}".format(path))
def create_gif(self,path):
"""Scan path folder, create list from file names in folder,
sort these png file names in list, add each png file to images
list
and create animation from these png files in images list """
# create folder for gif file
if not os.path.isdir(os.path.join(path, "animation")):
os.makedirs(os.path.join(path, "animation"))
png_dir = path
images = []
file_names = []
# add each png file name in path file_names list
for file_name in os.listdir(png_dir):
if file_name.endswith('.png'):
file_names.append(file_name)
# sort file names according to last digits
sorted_file_names = sorted(file_names, key=lambda y:
int((y.split('_')[1]).split('.')[0]))
# add each file in sorted file names to images list
for i in range(len(sorted_file_names)):
file_path = os.path.join(png_dir, sorted_file_names[i])
images.append(imageio.imread(file_path))
# remove last png file (objective function figure) from images
list
images.pop()
# save gif file to animation folder
imageio.mimsave(os.path.join(path,'animation/animation.gif'),
images, duration=0.5)
print("Animation of figures saved in {}
directory.".format(os.path.join(path,'animation')))
Agglomerative Clustering
O Clustering Aglomerativo é um algoritmo de machine learning do tipo não
supervisionado utilizado para problemas de classificação. Ele funciona construindo uma
hierarquia entre clusters, de forma a criar uma árvore, que pode ser representada por um
dendograma. Esse algoritmo também é conhecido como AGNES (Agglomerative Nesting), e
é um dos dois tipos de clustering hierárquico, sendo o outro o Divisive Clustering, que
funciona de maneira oposta ao agglomerative.
Esse método inicia assumindo que cada dado é um cluster próprio. Sucessivamente
ele compara os clusters entre si e aglomera os que são mais parecidos, até que todos os
dados estejam sob um único cluster. Essa estrutura pode ser visualizada como uma árvore
na qual os dados são as folhas, os nós são clusters de tamanhos variados e o cluster geral
(dataset completo) é a raiz. Os clusters podem ser obtidos ao cortar essa árvore em
qualquer altura.
Inicialmente, é feito o preparo dos dados, colocando eles em uma matriz onde as
linhas representam indivíduos, e as colunas sendo as variáveis, similar a um banco de
dados. Após isso, é feita a comparação de cada dado. Pode ser utilizado, por exemplo, a
distância euclidiana:
Utilizando a fórmula, encontramos uma distância d entre cada dado, e podemos criar
uma matriz na qual o elemento aij representa a distância euclidiana entre os elementos i e j.
Depois da matriz, o algoritmo associa e aglomera os indivíduos com a menor distância entre
eles em um único cluster. Esse processo acontece repetidamente até que os últimos dois
clusters se juntam em um que contém todos os dados.
Para a classificação dos grupos, o algoritmo coleta os clusters formados entre a
primeira e a última execução, tendo assim, por exemplo, N grupos separados por
semelhança entre os elementos contidos neles.
Vantagens:
● Facilidade na implementação e na utilização;
● A quantidade de clusters depende apenas de onde a árvore é cortada, não sendo
necessário definir a quantidade;
Desvantagens:
● Não é possível voltar no algoritmo, caso um elemento seja designado para um
cluster, ele é imutável;
● É um algoritmo de alta complexidade, com pelo menos O(n2logn);
● Sensível a ruídos, já que eles também entram na hierarquia;
Usos:
● Árvores genéticas e de evoluções;
● Encontrar a origem de uma doença;
● Comparar grupos de pessoas com base em características;
import numpy as np
import weakref
from collections import defaultdict
from data_reader import DataReader
from similarity import computeDistance
from time import time
import math
from pathlib import Path
import pickle
import pprint
from matplotlib import pyplot as plt
from scipy.cluster.hierarchy import dendrogram
import sys
# Pretty Printer Object for printing with indenting
pp = pprint.PrettyPrinter(indent = 4)
# decorator fuction for calculating runtime
def timer(func):
def wrapper(*args):
t = time()
res=func(*args)
print('Finished in', time()-t, 'sec')
return res
return wrapper
# Class for keeping track of Union Operations and updating the linkage
matrix
class UnionTracker:
factor = 1
def __init__(self, points):
'''initializer function for UnionTracker'''
self.points = points
assert self.points > 1, "Number of points should be greater than
0, {} was provided".format(self.points)
self.linkage_matrix = np.zeros((self.points-1, 4))
def union(self, A, B, dist, pts, iteration):
'''Create a Union Entry in the linkage Matrix'''
self.linkage_matrix[iteration][0] = A
self.linkage_matrix[iteration][1] = B
self.linkage_matrix[iteration][2] = dist*UnionTracker.factor
self.linkage_matrix[iteration][3] = pts
class Cluster:
''' Cluster class for creating and maintaining the clusters for the
heirarchical clustering'''
ClusterCount = 0
_instances = defaultdict()
maxClusters = 0
def __init__(self, key=None, seq=None):
''' Initialization of clusters '''
self._id = Cluster.ClusterCount
self.initID = self._id
Cluster.ClusterCount+=1
Cluster.maxClusters += 1
self.clusterMembers = dict()
self._instances[self.initID] = weakref.ref(self)
self.factor = 1
if key is not None:
self.addMember(key, seq)
def __del__(self):
''' Destructor for the Cluster Object'''
Cluster._instances.pop(self.initID, None)
def incrementFactor(self, factor=1):
''' Increment Multiplication Factor'''
self.factor += factor
def addMember(self, key, seq):
''' Add memebers (data points) to the cluster, in form of
dictionary where the dna sequence is the value'''
self.clusterMembers[key] = seq
def destroy(self):
''' Explcit destructor call '''
self.__del__()
def updateID(self, iteration):
''' Update the id of the cluster after merge operation to n+i
where i is the iteration number'''
self._id = Cluster.maxClusters + iteration
@property
def memberCount(self):
'''returns the number of members in the cluster currently '''
return len(self.clusterMembers.keys())
@property
def sequences(self):
''' Returns the Member DNA sequences in the cluster '''
return [self.clusterMembers[key] for key in
self.clusterMembers.keys()]
@classmethod
def getClusterById(cls, clusterID):
''' Fetch cluster object by referencing its id from the Cluster
weak reference storage '''
ref = cls._instances[clusterID]
obj = ref()
return obj
@classmethod
def generateInitialDistanceMatrix(cls, test = False):
''' Generate the initial nxn distance matrix by computing
Distance between each DNA sequence '''
# For Testing Purpose
if test == True:
cls.simMatrix =
np.array([[0,9,3,6,11],[9,0,7,5,10],[3,7,0,9,2],[6,5,9,0,8],[11,10,2,8,0
]], dtype=float)
# Actual Dataset Implementation
else:
pickleFilePath = Path('data/simMat_3.pkl')
if pickleFilePath.exists():
# Load Pickle File storing the simMatrix
with open(pickleFilePath, 'rb') as file:
cls.simMatrix = pickle.load(file)
else:
# Compute Distance among DNA Sequence
cls.simMatrix = np.ones((cls.ClusterCount,
cls.ClusterCount))
for cID in range(cls.ClusterCount):
clusterA = cls.getClusterById(cID)
for _cID in range(cID, cls.ClusterCount):
clusterB = cls.getClusterById(_cID)
seq1 = clusterA.sequences[0]
seq2 = clusterB.sequences[0]
similarity_1 = computeDistance(seq1, seq2)
cls.simMatrix[cID, _cID] = similarity_1
cls.simMatrix[_cID, cID] = similarity_1
print("similarity between {} and {} =
{}\r".format(cID, _cID, similarity_1), end='', flush=True)
sys.stdout.flush()
print('')
# Save The Pickle File
with open(pickleFilePath, 'wb') as file:
pickle.dump(cls.simMatrix, file)
# Normalize the Matrix
# minval = np.amin(cls.simMatrix, axis=(0,1))
# maxval = np.amax(cls.simMatrix, axis=(0,1))
# cls.simMatrix = ((cls.simMatrix-minval)/(maxval-minval))
@classmethod
def getClusters(cls):
for key in cls._instances.keys():
ref = cls._instances[key]
obj = ref()
if obj is not None:
yield obj
else:
cls._instances.pop(key, None)
@classmethod
def currentClusterCount(cls):
''' Returns the currently existent clusters'''
return len(cls._instances.keys())
# Class method to find the minimum distance cluster pair
@classmethod
def findMinDistance(cls):
''' Find the clusters most similar to each other i.e. with the
least distance among them '''
minDistance = 1*math.inf
clusterA = None
clusterB = None
for rowNumber in range(0,cls.simMatrix.shape[0]-1):
for colNumber in range(rowNumber+1,
cls.simMatrix.shape[1]):
if cls.simMatrix[rowNumber, colNumber] < minDistance:
minDistance = cls.simMatrix[rowNumber,
colNumber]
clusterA = rowNumber
clusterB = colNumber
return clusterA, clusterB, minDistance
@classmethod
def mergeSimilarClusters(cls, mergedRC, toDelete, iteration, dist,
heuristic = 'Centroid'):
''' Cluster merging and new CLuster Creation based on the preset
Heuristic
Available Heuristic Values are,
- Centroid
- Max
- Min
'''
outdated_m = mergedRC
outdated_d = toDelete
delCluster = cls.getClusterById(outdated_d)
toDelete = delCluster._id
mergedCluster = cls.getClusterById(outdated_m)
mergedRC = mergedCluster._id
d_mem = delCluster.memberCount
m_mem = mergedCluster.memberCount
if heuristic == 'Centroid': #Compute using Centroid Calculation
rowSum = (cls.simMatrix[outdated_m, :]*m_mem +
cls.simMatrix[outdated_d, :]*d_mem)/(m_mem+d_mem)
elif heuristic == 'Max':
#Compute using Max Calculation
rowStack = np.vstack((cls.simMatrix[outdated_m, :],
cls.simMatrix[outdated_d, :]))
rowSum = np.amax(rowStack, axis=0)
elif heuristic == 'Min':
#Compute using Min Calculation
rowStack = np.vstack((cls.simMatrix[outdated_m, :],
cls.simMatrix[outdated_d, :]))
rowSum = np.amin(rowStack, axis=0)
#Update the new row
cls.simMatrix[:, outdated_m]
cls.simMatrix[outdated_m, :]
cls.simMatrix[:, outdated_d]
cls.simMatrix[outdated_d, :]
=
=
=
=
rowSum
rowSum
1*math.inf
1*math.inf
#Merge Data Points into the cluster
for key in delCluster.clusterMembers.keys():
mergedCluster.addMember(key,
delCluster.clusterMembers[key])
mergedCluster.updateID(iteration)
mergedCluster.incrementFactor()
print('Union ({} - {}), distance {}'.format(toDelete, mergedRC,
dist))
# Delete the redundant clusters explicityly
delCluster.destroy()
return mergedRC, toDelete, mergedCluster.memberCount,
mergedCluster.factor
# Driver Function to execute the Heirarchical Clustering
@timer
def main():
test = False
heuristic = 'Centroid'
reader = DataReader()
data = reader.loadData()
dataArray = reader.getDataArray()
if test == True:
clusters = [Cluster(dataPoint, data[dataPoint]) for dataPoint in
list(data.keys())[:5]]
else:
clusters = [Cluster(dataPoint, data[dataPoint]) for dataPoint in
list(data.keys())[:]]
Cluster.generateInitialDistanceMatrix(test)
Uni = UnionTracker(len(clusters))
print('')
iteration = 0
while(Cluster.currentClusterCount() > 1):
clsA, clsB, dist = Cluster.findMinDistance()
mergedRC = min(clsA, clsB)
toDelete = max(clsA, clsB)
newIDm, newIDd, pts, factor =
Cluster.mergeSimilarClusters(mergedRC, toDelete, iteration, dist,
heuristic=heuristic)
Uni.union(newIDd, newIDm, dist, pts, iteration)
iteration += 1
labels = list(data.keys())
drawDendrogram(Uni, labels, heuristic)
def drawDendrogram(UniObj, labels, heuristic):
''' Generate the dendrogram using te UniObject's linkage matrix '''
plt.title("Dendrogram - Agglomerative Clustering -" + heuristic)
dendrogram(UniObj.linkage_matrix, show_leaf_counts = True,
show_contracted = True, labels = labels)
plt.show()
if __name__ == "__main__":
main()
DBSCAN
DBSCAN, sigla para Density-based spatial clustering of applications with noise
(Clusterização Espacial Baseada em Densidade de Aplicações com Ruído) é um algoritmo
não supervisionado de classificação baseado em separar clusters de acordo com a
densidade dos dados. Ele foi proposto por Martin Ester, Hans-Peter Kriegel, Jörg Sander e
Xiaowei Xu em 1996.
O DBSCAN funciona ao agrupar pontos que estão próximos uns aos outros em um
mesmo cluster. Não é definido uma quantidade de clusters nem há uma quantidade limite
para eles. Existem dois parâmetros que devem ser analisados para definir um cluster:
1. ε (epislon ou eps): A distância entre o ponto de origem e o ponto a ser analisado;
2. MinPts: A quantidade mínima de pontos ao redor do ponto original;
Qualquer ponto que não esteja próximo a outro é considerado um ruído (outlier).
Para que o algoritmo funcione, é necessário fazer uma boa estimativa dos parâmetros. Para
o MinPts, devem ser analisados alguns fatores do dataset, como o tamanho, quantidade de
ruído, etc:
●
●
●
Quanto maior o dataset, maior deverá ser o MinPts;
Quanto mais ruído, maior deverá ser o MinPts;
De modo geral, esse parâmetro deve ser igual ou maior que a quantidade de
dimensões do dataset, sendo MinPts = 4 para 2 dimensões, e MinPts = 2 x
número de dimensões para 3 ou mais dimensões;
Para a distância, normalmente valores de tamanho reduzido são preferíveis, porém
ele deve ser escolhido com base na distância dos dados. Um método para encontrar o
parâmetro é calcular a média da distância entre um ponto e uma quantidade k de vizinhos,
no qual k = MinPts. Essas médias são então plotadas em um gráfico de k-distância em
ordem crescente, como na figura abaixo. O valor para eps será onde há a maior curvatura.
Vantagens:
● Não necessita especificar o número de clusters antes da análise do dataset;
● Ideal para formas arbitrárias de clusters;
● Consegue detectar ruídos no dataset, de modo que o resultado não é influenciado
por eles;
Desvantagens:
● Em certos casos, não é muito fácil determinar o eps, sendo necessário
conhecimento do método e uma análise mais profunda do dataset;
● Caso os clusters possuam densidades diferentes, o DBSCAN terá dificuldades em
categorizar os clusters, podendo sinalizar ruídos falsos ou aglomerar ruídos dentro
de um cluster;
Usos:
● Pode ser utilizado em qualquer área, como biologia, marketing, sistemas de
gerenciamento, arqueologia, medicina…
● Utilizado para separar dados em diversos grupos, como tipos de cliente, sintomas de
doenças, recomendações de produtos;
import numpy as np
import math
UNCLASSIFIED = False
NOISE = None
def _dist(p,q):
return math.sqrt(np.power(p-q,2).sum())
def _eps_neighborhood(p,q,eps):
return _dist(p,q) < eps
def _region_query(m, point_id, eps):
n_points = m.shape[1]
seeds = []
for i in range(0, n_points):
if _eps_neighborhood(m[:,point_id], m[:,i], eps):
seeds.append(i)
return seeds
def _expand_cluster(m, classifications, point_id, cluster_id, eps,
min_points):
seeds = _region_query(m, point_id, eps)
if len(seeds) < min_points:
classifications[point_id] = NOISE
return False
else:
classifications[point_id] = cluster_id
for seed_id in seeds:
classifications[seed_id] = cluster_id
while len(seeds) > 0:
current_point = seeds[0]
results = _region_query(m, current_point, eps)
if len(results) >= min_points:
for i in range(0, len(results)):
result_point = results[i]
if classifications[result_point] == UNCLASSIFIED or \
classifications[result_point] == NOISE:
if classifications[result_point] == UNCLASSIFIED:
seeds.append(result_point)
classifications[result_point] = cluster_id
seeds = seeds[1:]
return True
def dbscan(m, eps, min_points):
"""Implementation of Density Based Spatial Clustering of
Applications with Noise
See https://en.wikipedia.org/wiki/DBSCAN
scikit-learn probably has a better implementation
Uses Euclidean Distance as the measure
Inputs:
m - A matrix whose columns are feature vectors
eps - Maximum distance two points can be to be regionally related
min_points - The minimum number of points to make a cluster
Outputs:
An array with either a cluster id number or dbscan.NOISE (None)
for each
column vector in m.
"""
cluster_id = 1
n_points = m.shape[1]
classifications = [UNCLASSIFIED] * n_points
for point_id in range(0, n_points):
point = m[:,point_id]
if classifications[point_id] == UNCLASSIFIED:
if _expand_cluster(m, classifications, point_id, cluster_id,
eps, min_points):
cluster_id = cluster_id + 1
return classifications
def test_dbscan():
m = np.matrix('1 1.2 0.8 3.7 3.9 3.6 10; 1.1 0.8 1 4 3.9 4.1 10')
eps = 0.5
min_points = 2
assert dbscan(m, eps, min_points) == [1, 1, 1, 2, 2, 2, None]
Bibliografia
Tipos de Aprendizado
https://lamfo-unb.github.io/2017/07/27/tres-tipos-am/
SVM
https://www.inf.ufpr.br/dagoncalves/IA07.pdf
https://towardsdatascience.com/support-vector-machine-introduction-to-machine-learning-al
gorithms-934a444fca47
https://www.digitalhouse.com/br/blog/maquina-de-vetores-de-suporte/
https://shuzhanfan.github.io/2018/05/understanding-mathematics-behind-support-vector-mac
hines/
https://github.com/mahesh147/Support-Vector-Machine/blob/master/support_vector_machin
e.py
Naive Bayes
https://www.analyticsvidhya.com/blog/2017/09/naive-bayes-explained/
https://www.digitalhouse.com/br/blog/naive-bayes/
https://www.organicadigital.com/blog/algoritmo-de-classificacao-naive-bayes/
Random Forest
https://www.ibm.com/cloud/learn/random-forest#toc-benefits-a-VrBNAC3d
https://towardsdatascience.com/understanding-random-forest-58381e0602d2
Redes Neurais
https://www.ibm.com/br-pt/cloud/learn/neural-networks
https://aws.amazon.com/pt/what-is/neural-network/
https://www.deeplearningbook.com.br/o-que-sao-redes-neurais-artificiais-profundas/
https://sites.icmc.usp.br/andre/research/neural/
https://www.linkedin.com/pulse/artificial-neural-networks-advantages-disadvantages-maad-m
-mijwel
https://towardsdatascience.com/how-to-define-a-neural-network-as-a-mathematical-functionf7b820cde3f
https://www.kdnuggets.com/2020/02/deep-neural-networks.html
https://www.tutorialspoint.com/python_deep_learning/python_deep_learning_deep_neural_n
etworks.htm
https://towardsdatascience.com/a-laymans-guide-to-deep-neural-networks-ddcea24847fb
https://github.com/TatevKaren/artificial-neural-network-business_case_study
https://github.com/semicolon123/ML-DL-projects/blob/main/Convolutional_Neural_Network_f
or_Classification_of_handwritten_digits.ipynb
K-Means Clustering
https://aprenderdatascience.com/k-means-clustering-agrupamento-k-means/
https://developers.google.com/machine-learning/clustering/algorithm/advantages-disadvanta
ges
https://www.linkedin.com/pulse/k-means-clustering-its-use-case-security-domain-anudeep-n
alla/
Agglomerative Clustering
https://www.datanovia.com/en/lessons/agglomerative-hierarchical-clustering/
https://www.educba.com/hierarchical-clustering-agglomerative/?source=leftnav
DBSCAN
https://towardsdatascience.com/how-dbscan-works-and-why-should-i-use-it-443b4a191c80
https://www.maxwell.vrac.puc-rio.br/24787/24787_6.PDF
https://medium.com/@tarammullin/dbscan-parameter-estimation-ff8330e3a3bd
https://towardsdatascience.com/dbscan-clustering-explained-97556a2ad556
NLP
https://medium.com/neuronio-br/da-an%C3%A1lise-de-sentimentos-para-o-reconhecimentode-emo%C3%A7%C3%B5es-uma-hist%C3%B3ria-pln-171f27734c56
https://www.oracle.com/br/artificial-intelligence/what-is-natural-language-processing/
https://en.wikipedia.org/wiki/Natural_language_processing
https://monkeylearn.com/natural-language-processing/
https://www.ibm.com/cloud/learn/natural-language-processing
https://github.com/rmohashi/emotion-from-tweet
Download