Skip to content

Instantly share code, notes, and snippets.

@duducosmos
Created August 28, 2018 13:28
Show Gist options
  • Save duducosmos/93f168000c3c4a673a82e6b74270a9e5 to your computer and use it in GitHub Desktop.
Save duducosmos/93f168000c3c4a673a82e6b74270a9e5 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Classificador Naïve Bayes\n",
"\n",
"\n",
"É um método de aprendizagem de máquinas, baseado em inferências estatíticas sobre a probabilidade de um elemento pertencer a uma classe.\n",
"\n",
"1. É utilizado quando existe uma disponilibidade de conjunto de treinamento grande ou moderado.\n",
"\n",
"2. Os atributos que descrevem as instâncias forem condicionalmente independetes dada as classes.\n",
" - Tem sucesso na aplicação de diagnósticos médicos ;\n",
" - classificação de documentos textuais.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"\n",
"1. Aplicado a tarefa de aprendizagem onde:\n",
"\n",
" - Cada instância x é descrita por uma conjunção de valores de atributos\n",
"\n",
" - A função alvo $f(x)$ pode assumir qualquer valor de um conjunto $V$\n",
"\n",
" - Um conjunto de exemplos de treinamento da função alvo é fornecido \n",
"\n",
" - uma nova instancia é descrita pela tupla de valores de atributos $<a_{1}, a_{2}, ...,a_{n}>$\n",
"\n",
"2. A tarefa é predizer o valor alvo (ou classe) para essa nova instância."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. A solução para classificar uma nova instância cosnsite em:\n",
" - atribuir o valor alvo mais provável ($c_{MAP}$) dados os valores dos atributos $<a_{1}, a_{2}, ...,a_{n}>$ que descrevem a instância.\n",
" - $C_{MAP} = \\underset{c_{j} \\in C}{\\mathrm{arg max}}~P(c_{j}|a_{1}, a_{2},...,a_{n})$\n",
" - Essa expressão pode ser reescrita em termos do teorema de Bayes."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"<center>\n",
" $C_{MAP} = \\underset{c_{j} \\in C}{\\mathrm{arg max}}~P(c_{j}|a_{1}, a_{2},...,a_{n})$\n",
" <br>\n",
" <br>\n",
" $C_{MAP} = \\underset{c_{j} \\in C}{\\mathrm{arg max}}~\\frac{P(a_{1}, a_{2},...,a_{n}| c_{j})}{P(a_{1}, a_{2}, ...,a_{n})}$\n",
" <br>\n",
" <br>\n",
" $C_{MAP} = \\underset{c_{j} \\in C}{\\mathrm{arg max}}~P(a_{1}, a_{2},...,a_{n}| c_{j})P(c_{j})$\n",
" <br>\n",
" <br>\n",
"</center>\n",
"- Precisamos estimar os dois termos da equação acima, baseando-se nos dados de treinamento.\n",
" - $P(c_{j})$, que é fácil de estimar.\n",
" - $P(a_{1}, a_{2},...,a_{n}| c_{j})$, mais complicado"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. O classificador Naïve Bayes é baseado na suposição simplificadora de que os valores dos atributos são condicionalmente independentes dado o valor alvo.\n",
"2. Com isso, temos que a probabilidade de observar a conjunção de atributos $a_{1}, a_{2},...,a_{n}$ é somente o produto das probabilidades para os atributos individuais:\n",
"<center>$P(a_{1}, ...,a_{n}) = \\underset{i}{\\Pi}~P(a_{i}|c_{j})$</center>\n",
"3. Com isso, temos o classificador Naïve Bayes:\n",
"<center>$c_{NB} = \\underset{c_{j} \\in C}{\\mathrm{arg max}}~P(c_{j})\\underset{i}{\\Pi}~P(a_{i}|c_{j})$</center>\n",
" - com $C_{NB}$ indicando o valor alvo fornecido pelo algoritmo Naïve Bayes."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Assim, o algoritmo Naïve Bayes envolve:\n",
" - Aprendizagem: os termos $P(c_{j})$ e $P(a_{i}|c_{j})$ são estimados baseado nas suas frequências no conjunto de treinamento.\n",
" - Estas probabilidades \"aprendidas\" são então utilizadas para classificar uma nova instância aplicando a equação vista anteriormente $c_{NB}$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"O algoritmo de Naïve Bayes pode ser descrito como:\n",
"\n",
"```\n",
"Treinamento_Naïve_Bayes(Conjunto de exemplo)\n",
" Para Cada valor algo (classe) cj:\n",
" P'(cj) <- estimar P(cj)\n",
" Para cada valor de atributo ai de cada atributo a:\n",
" P'(ai|cj) <- estimar P(ai|cj)\n",
"Classica_Naïve_Baues(xt):\n",
"```\n",
"<center>$c_{NB} = \\underset{c_{j} \\in C}{\\mathrm{arg max}}~P(c_{j})\\underset{i}{\\Pi}~P(a_{i}|c_{j})$</center>\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Classificar Textos\n",
"\n",
"1. Utilizado para:\n",
" - Aprender quais notícias são interressantes\n",
" - Aprender a classificar páginas WEB por assunto\n",
" - Em atendimento ao cliente, definir a ordem de prioridade, de acordo com o e-mail do cliente..."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Contexto\n",
" - Considere um espaço de instâncias X consistindo de todos os documentos de texto possíveis.\n",
" - Dados exemplos de treinamento, de alguma função alvo $f(x)$ que pode assumir valores de um conjunto finito C.\n",
" - A tarefa de aprendizagem é aprender, a partir dos exemplos de treinamento, a predizer o valor alvo para os documentos de texto subsequentes.\n",
" -Considere a função alvo como sendo documentos interessantes e não interessantes, ou mensagens que passam sentimentos positivos, negativos ou neutros."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Representação de texto arbitrário\n",
" - Dado um documento de texto, este parágrafo, por exemplo, definimos um atributo para cada posição de palavra no documento e definimos o valor do atributo como sendo a palavra em português encontrada nessa posição\n",
" - O parágrafo anterior pode ser descrito por 34 valores de atributos correspondendo a 34 posições de palavras.\n",
" - O valor do primeiro atributo é a palavra \"Dado\" e do segundo é a palavra \"um\" e assim por diante."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Nesse caso, a suposição da independência condicional Naïve Bayes:\n",
"<center>$P(doc |c_{j}) = \\prod\\limits_{i=1}^{tamanho(doc)} P(a_{i}=w_{k}|c_{j})$</center>\n",
"em que $P(a_{i}=w_{k}|c_{j})$ é a probabilidade que a palavra na posição $i$ é $w_{k}$ dado $c_{j}$.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Classificador Naïve Bayes de textos em Python\n",
"\n",
"1. Utilizaremos a biblioteca scikit-learning, de aprendizagem de máquina, para criar o classificador."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Vamos usar o módulo classificador Naive Bayes para modelos multinomial(Multiclasses) - MultinomialNB.\n",
"2. Vamos usar também o módulo CountVectorizer, que converte uma coleção de textos de um documento numa matrix de tokens contáveis.\n",
"3. Usaremos o módulo metric , o qual inclui funções de pontuação, métricas de avaliação de execução do código,..\n",
"4. O módulo joblib, que permite fazer a persistência do modelo treinado."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"from sklearn.naive_bayes import MultinomialNB\n",
"from sklearn.feature_extraction.text import CountVectorizer\n",
"from sklearn import metrics\n",
"from sklearn.externals import joblib"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Nosso dado de treinamento estará em um arquivo CSV (valores separados por vírgula), em que a primeira coluna representa o texto e a segunda coluna o sentimento associado ao texto (Positivo, +1, Negativo, -1, Neutro, 0).\n",
"2. O arquivo CSV pode ser criado, usando o excel, em seguida exportamos o dado para o formato csv.\n",
"3. Para acessar o csv em Python, usamos o módulo csv.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Vamos criar uma função que converta a palavra Positivo para 1, Negativo para -1 e a palavra Neutro para 0.\n",
"2. Faremos uma função inversa, que dado o número, converta na palavra"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"def sentN(x):\n",
" if(x == 'positivo'):\n",
" return 1\n",
" elif(x == 'negativo'):\n",
" return -1\n",
" else:\n",
" return 0\n",
"def nSent(x):\n",
" if(x == 1):\n",
" return 'positivo'\n",
" elif(x == -1):\n",
" return 'negativo'\n",
" else:\n",
" return 'neutro'"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 'quem nao foi ver ainda essa maravilha de filme na moral .. vao . vcs nao irao se arrepender que filme meuza migos'\n",
" 'eu odeio esse filme' 'que merda de filme' 'odeio essa bosta de filme'\n",
" 'que lixo de filme' 'odeio filme de terror'\n",
" 'que filme de merda esse dos transformers'\n",
" 'odeio esse filme dos minions q porra chataaaa' 'que filme mais chato'\n",
" 'filme chato sem graca']\n",
"[ 1 -1 -1 -1 -1 -1 -1 -1 -1 -1]\n"
]
}
],
"source": [
"import csv\n",
"from numpy import array\n",
"with open('./Dados/filmes.csv', 'r') as dados_de_treinamento:\n",
" conjunto_de_treinamento = array(list(csv.reader(dados_de_treinamento)))\n",
" \n",
"textos = conjunto_de_treinamento[:,0]\n",
"print(textos[:10])\n",
"sentimentos = array([sentN(i) for i in conjunto_de_treinamento[:,1]])\n",
"print(sentimentos[:10])"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Vamos converter o código anterior numa função, que recebe o nome do arquivo contendo o texto de treinamento e que retorne uma matrix contendo o conjunto de dados de treinamento"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"def conjunto_de_treinamento(arquivoDeTreinamento):\n",
" with open('./Dados/filmes.csv', 'r') as dados_de_treinamento:\n",
" conjunto_de_treinamento = array(list(csv.reader(dados_de_treinamento)))\n",
" textos = conjunto_de_treinamento[:,0]\n",
" sentimentos = array([sentN(i) for i in conjunto_de_treinamento[:,1]])\n",
" conjunto_de_treinamento[:,1] = sentimentos\n",
" return conjunto_de_treinamento\n",
" \n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Algumas palavras, como a, o, com, uma, não agregam muito ao se fazer analize de sentimentos de um texto, essas palavras são extremamente comuns, ou seja, muito frequentes em textos.\n",
"2. Tais palavras são chamadas de \"palavras de parada\" (Stop Words). \n",
"3. Em geral, não as consideramos quando queremos trabalhar um texto.\n",
"4. Para facilitar o processamento do texto, iremos também remover algumas acentuações.\n",
"5. Além disso, as conjugações das palavras pode não ser muito importantes ao fazer análise do texto, a raíz das palavras acabam trazendo o significado mais importante, ao se fazer a classificação de textos.\n",
"6. Nesse caso, usaremos um processo de decomposição de palavras chamada stemming. "
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"E:\\Python\\winpython\\Notebooks\\IAC/modulos\n"
]
}
],
"source": [
"\n",
"import os\n",
"import sys\n",
"nb_dir = os.path.join(os.path.split(os.getcwd())[0],'IAC/modulos')\n",
"print(nb_dir)\n",
"if nb_dir not in sys.path:\n",
" sys.path.append(nb_dir)\n",
"from stemmingPT import *"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[['nao ver maravilh moral vao vcs nao irao arrepender meuz mig' '1']\n",
" ['odeio' '-1']\n",
" ['merd' '-1']\n",
" ['odeio bost' '-1']\n",
" ['lix' '-1']\n",
" ['odeio terror' '-1']\n",
" ['merd transformers' '-1']\n",
" ['odeio minions porr chataa' '-1']\n",
" ['chat' '-1']\n",
" ['chat grac' '-1']]\n"
]
}
],
"source": [
"\n",
"\n",
"def conjunto_de_treinamento(arquivoDeTreinamento):\n",
" with open('./Dados/filmes.csv', 'r') as dados_de_treinamento:\n",
" conjunto_de_treinamento = array(list(csv.reader(dados_de_treinamento)))\n",
" \n",
" textos = conjunto_de_treinamento[:,0] \n",
" textos = [' '.join(ti.lower().split('.')).split(\" \") for ti in textos]\n",
" \n",
" func = lambda txt: ' '.join([i for i in [suffixRemoval(ti) for ti in txt] if i != None])\n",
" textos = array([func(ti) for ti in textos]) \n",
" sentimentos = array([sentN(i) for i in conjunto_de_treinamento[:,1]])\n",
" conjunto_de_treinamento[:,0] = textos\n",
" conjunto_de_treinamento[:,1] = sentimentos\n",
" \n",
" return conjunto_de_treinamento\n",
"\n",
"dados_treinamento = conjunto_de_treinamento('./Dados/filmes.csv')\n",
"print(dados_treinamento[:10])"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"1. Iremos decompor o texto em bigramas, que constitui na quebra de palavras em sequencias de dois subconjuntos.\n",
"2. Um bigrama ou digrama é um conjunto de duas letras, duas sílabas ou duas palavras. Os bigramas são utilizados comumente como base para a análise estatística do texto.\n",
"3. Usaremos os bigramas para calcular os valores de $P(a_{i}=w_{k}|c_{j})$"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"def split_into_lemmas(dado):\n",
" bigram_vectorizer = CountVectorizer(ngram_range=(1, 3), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
" analyze = bigram_vectorizer.build_analyzer()\n",
" an = analyze(dado)\n",
" return an"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Vamos extrair as $a_i$ características dos dados de treinamento"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"def caracteristicas_dos_dados(dados):\n",
" vectorizer = CountVectorizer(stop_words=pt_stopwords, \n",
" analyzer=split_into_lemmas,\n",
" strip_accents='ascii')\n",
" caracteristicas = vectorizer.fit_transform([r[0] for r in dados])\n",
" sents = [int(r[1]) for r in dados]\n",
" return caracteristicas, sents, vectorizer"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Podemos agora criar a função que irá fazer a classificação dos dados"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [],
"source": [
"def classificador_navie_bayes(arquivo_dados_de_treinamento, \n",
" fracao_teste = 0.2,\n",
" arquivo_modelo=\"./navebayes.pkl\", \n",
" arquivo_vectorizer='./vectorizer.pkl'):\n",
" modelo_foi_salvo = os.path.isfile(arquivo_modelo)\n",
" dados = conjunto_de_treinamento(arquivo_dados_de_treinamento)\n",
" \n",
" para_treino = int(dados.shape[0] - dados.shape[0] * fracao_teste)\n",
" para_teste = dados[para_treino:]\n",
" dados = dados[:para_treino]\n",
" if(modelo_foi_salvo):\n",
" nb = joblib.load(arquivo_modelo)\n",
" vectorizer = joblib.load(arquivo_vectorizer)\n",
" else: \n",
" caracteristicas, sents, vectorizer = caracteristicas_dos_dados(dados)\n",
" nb = MultinomialNB()\n",
" nb.fit(caracteristicas, sents)\n",
" joblib.dump(nb, arquivo_modelo)\n",
" joblib.dump(vectorizer, arquivo_vectorizer)\n",
" \n",
" return nb, vectorizer.transform, para_teste\n",
" \n",
" "
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"sentimento, vectorize, para_testes = classificador_navie_bayes('./Dados/filmes.csv')\n",
"teste_sent = sentimento.predict(vectorize(para_testes[:,0]))\n",
"print(teste_sent[:5])\n",
"print(para_testes[:5])"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Trabalho\n",
"\n",
"1. Usando o classificador Naïve Bayes, para texto, desenvolva o projeto de um software para determinar automaticamente as prioridades de tarefas, que são enviadas ao suporte, por e-mail. \n",
" - Defina quatro níveis de prioridade. \"Muito Baixa\", \"Baixa\", \"Alta\", \"Muito Alta\".\n",
" - Toda vez que uma prioridade de nível \"Alta\" ou \"Muito Alta\" forem reconhecidas, um e-mail para o gerente de suporte deve ser enviado, caso a prioridade reconhecida for \"Muito Baixa\" o \"Baixa\", um e-mail, designando a tarefa, deve ser enviada para o grupo de estagiários.\n",
" - Faça um projeto com os requisitos para esse software, ou seja, quais as sequências de passos lógicos o programa deve executar.\n",
" - Pesquise na internet e crie uma pequena base de dados, de treinamento, com os pedidos típicos para o suporte. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment