diff --git a/README.md b/README.md index 0993f60..5dec2d1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +Projeto prático da matéria de Recuperação da Informação do curso de Pós-graduação da Ciência da Computação da UNESP + # Recuperação da Informação Neste texto, apresentamos uma introdução ao projeto prático da matéria de recuperação da informação na UNESP. O objetivo deste projeto é desenvolver um sistema de busca que permita aos usuários encontrar documentos relevantes em uma coleção de textos. Para isso, utilizaremos conceitos e técnicas de recuperação da informação, tais como: indexação, processamento de linguagem natural, modelos de recuperação, medidas de avaliação e feedback de relevância. O projeto será dividido em quatro etapas: @@ -7,6 +9,8 @@ Neste texto, apresentamos uma introdução ao projeto prático da matéria de re 3. implementação do modelo de recuperação; 4. avaliação do sistema. +Este trabalho não tem como objetivo fornecer uma ferramenta otimizada, mas sim uma ferramenta funcional com codificação manual, sem o uso de pacotes externos, para uma melhor compreensão das técnicas apresentadas. + ## Pré-processamento dos documentos O pré-processamento de texto é uma etapa fundamental para a recuperação da informação, pois visa transformar os documentos em uma representação adequada para a análise e a busca. O pré-processamento envolve técnicas como tokenização, normalização, remoção de stopwords, stemização e lematização, que têm como objetivo reduzir a complexidade e a variabilidade dos textos. Essas técnicas facilitam a identificação de termos relevantes e a comparação entre documentos, melhorando a eficiência e a eficácia dos sistemas de recuperação da informação. @@ -21,6 +25,22 @@ Um índice invertido de texto é uma estrutura de dados que armazena as ocorrên O índice invertido é uma ferramenta essencial para a recuperação da informação, pois permite realizar consultas complexas e obter resultados relevantes em um curto espaço de tempo. +$$TF-IDF = TF(t, d) \cdot IDF(t)$$ + +Onde: + +$TF(t, d)$: representa a frequência do termo t no documento d. +$IDF(t)$: representa o inverso da frequência do documento (IDF) do termo t. + +A fórmula completa do IDF é dada por: + +$$IDF(t) = \log \left( \frac{N}{DF(t)} \right)$$ + +Onde: + +$N$ é o número total de documentos na coleção. +$DF(t)$ é o número de documentos que contêm o termo t. + ## Implementação do modelo de recuperação A recuperação da informação é o processo de encontrar e acessar informações relevantes em um grande conjunto de dados. Existem diferentes modelos computacionais que podem ser usados para representar e organizar as informações, bem como para definir e executar as consultas dos usuários. Neste texto, vamos introduzir alguns dos principais modelos de recuperação da informação, como o modelo booleano, o modelo vetorial e o modelo probabilístico. Também vamos discutir as vantagens e desvantagens de cada um deles, e como eles podem ser aplicados em diferentes contextos e domínios. @@ -29,4 +49,4 @@ A recuperação da informação é o processo de encontrar e acessar informaçõ A recuperação da informação é uma área que visa encontrar e fornecer informações relevantes para os usuários, a partir de grandes coleções de documentos. Para isso, existem diversos modelos de recuperação da informação, que se baseiam em diferentes princípios e abordagens para representar e comparar os documentos e as consultas dos usuários. A avaliação dos modelos de recuperação da informação é fundamental para verificar a sua eficácia e eficiência, bem como para identificar os seus pontos fortes e fracos. Existem diferentes formas de avaliar os modelos de recuperação da informação, tais como: a avaliação experimental, que utiliza medidas quantitativas e conjuntos de teste padronizados; a avaliação centrada no usuário, que considera as necessidades, preferências e comportamentos dos usuários; e a avaliação comparativa, que analisa as vantagens e desvantagens de diferentes modelos em relação a um critério ou objetivo específico. A escolha do método de avaliação depende do contexto e do propósito da recuperação da informação, bem como dos recursos disponíveis. A avaliação dos modelos de recuperação da informação é essencial para o desenvolvimento e aprimoramento da área, pois permite identificar os problemas existentes e propor soluções inovadoras. -Ao final do projeto, é esperado que possamos gerar rankings de similaridade de acordo com cada e-mail utilizado como input. \ No newline at end of file +Ao final do projeto, é esperado que possamos gerar rankings de similaridade de acordo com cada e-mail utilizado como input. diff --git a/notebooks/information_retrieval_emails.ipynb b/notebooks/information_retrieval_emails.ipynb index da918c0..3470670 100644 --- a/notebooks/information_retrieval_emails.ipynb +++ b/notebooks/information_retrieval_emails.ipynb @@ -5,12 +5,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Pré-Processamento dos Documentos\n", - "\n", - "A limpeza dos dados é um processo essencial para garantir a qualidade e a confiabilidade das informações armazenadas em um banco de dados. A limpeza dos dados envolve a identificação e a correção de erros, inconsistências, duplicidades e valores ausentes nos dados. A arquitetura do armazenamento é a forma como os dados são organizados, estruturados e acessados em um banco de dados. Uma das opções de arquitetura é o formato YAML, que significa YAML Ain't Markup Language. O YAML é um formato de serialização de dados que usa uma sintaxe simples e legível para representar estruturas de dados como listas, mapas, sequências e escalares. O YAML é compatível com diversas linguagens de programação e pode ser usado para armazenar dados de forma hierárquica e flexível.\n", - "\n", - "\n", - "
" + "# Recuperação da informação para conjunto de e-mails\n", + "\n", + "Foram utilizadas as bases `20_newsgroups.tar.gz` e `mini_newsgroups.tar.gz` para o projeto:\n", + "\n", + "[ICS: E-mail groups](https://kdd.ics.uci.edu/databases/20newsgroups/20newsgroups.html)\n", + "\n", + "
\n", + "

Atenção

\n", + "

A base de dados possui um total de 22.000 elementos. Destes, 2.000 são utilizados como query, e os outros 20.000 são para consulta. \n", + "

\n", + " Após a tokenização, o vocabulário pode chegar a 130.000 palavras, resultando em uma matriz com o termo para cada documento, o que pode ocupar até 30GB de RAM.\n", + "

\n", + " Portanto, é importante ter cuidado ao executar o processo, pois é necessário um grande volume de RAM para sua execução.

\n" ] }, { @@ -22,9 +33,15 @@ "# Importa os módulos necessários\n", "import os # Módulo para lidar com funções do sistema operacional\n", "import gc # Módulo para realizar coleta de lixo e gerenciamento de memória\n", + "import sys\n", "\n", "import numpy as np # Módulo para trabalhar com matrizes e funções matemáticas\n", - "import pandas as pd # Módulo para trabalhar com dataframes e séries em Python\n" + "import pandas as pd # Módulo para trabalhar com dataframes e séries em Python\n", + "\n", + "from ir.preprocessing import lemmatize_word # Importa a função de lematização de palavras\n", + "from ir.tf_idf import tfidf # Importa a função de cálculo de TF-IDF\n", + "\n", + "from sklearn.metrics.pairwise import linear_kernel" ] }, { @@ -34,14 +51,18 @@ "source": [ "
\n", "\n", - "## Estruturação dos Arquivos\n", + "## Leitura dos Arquivos\n", + "\n", + "Para a pasta da base de dados, os arquivos foram fornecidos em um formato raw, sem indicação de extensão. Cada e-mail é um arquivo dentro de uma pasta que representa um tema.\n", + "\n", + "Portanto, nesse caso, é necessário percorrer cada pasta para realizar a leitura e armazenamento da base de dados para análises futuras.\n", "\n", "
" ] }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -50,7 +71,7 @@ "0" ] }, - "execution_count": 31, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -103,212 +124,25 @@ " return database\n", "\n", "# tranformation from dict -> dataframe\n", - "base_doc = pd.DataFrame(process_files(docs))\n", + "base_doc = pd.DataFrame(process_files(docs_path))\n", "\n", - "base_doc = pd.DataFrame(process_files(doc_dir))\n", - "\n", - "# remove database from memory\n", - "gc.collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "ename": "PermissionError", - "evalue": "[Errno 13] Permission denied: '../data/emails/20_newsgroups/alt.atheism'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mPermissionError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[5], line 8\u001b[0m\n\u001b[0;32m 5\u001b[0m docs_path \u001b[39m=\u001b[39m \u001b[39m'\u001b[39m\u001b[39m../data/emails/20_newsgroups/\u001b[39m\u001b[39m'\u001b[39m\n\u001b[0;32m 7\u001b[0m \u001b[39m# Import das bases\u001b[39;00m\n\u001b[1;32m----> 8\u001b[0m database_docs \u001b[39m=\u001b[39m read_files(docs_path)\n\u001b[0;32m 9\u001b[0m database_query \u001b[39m=\u001b[39m read_files(query_path)\n\u001b[0;32m 11\u001b[0m base_docs \u001b[39m=\u001b[39m pd\u001b[39m.\u001b[39mDataFrame(database_docs)\n", - "Cell \u001b[1;32mIn[2], line 3\u001b[0m, in \u001b[0;36mread_files\u001b[1;34m(doc_dir)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mread_files\u001b[39m(doc_dir):\n\u001b[0;32m 2\u001b[0m \u001b[39m# Use a list comprehension to get a list of file paths\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m database \u001b[39m=\u001b[39m [{\u001b[39m'\u001b[39;49m\u001b[39mfilepath\u001b[39;49m\u001b[39m'\u001b[39;49m: doc_dir,\n\u001b[0;32m 4\u001b[0m \u001b[39m'\u001b[39;49m\u001b[39mfilename\u001b[39;49m\u001b[39m'\u001b[39;49m: filename,\n\u001b[0;32m 5\u001b[0m \u001b[39m'\u001b[39;49m\u001b[39mtext\u001b[39;49m\u001b[39m'\u001b[39;49m: \u001b[39mopen\u001b[39;49m(os\u001b[39m.\u001b[39;49mpath\u001b[39m.\u001b[39;49mjoin(doc_dir, filename), \u001b[39m'\u001b[39;49m\u001b[39mr\u001b[39;49m\u001b[39m'\u001b[39;49m)\u001b[39m.\u001b[39;49mread()\u001b[39m.\u001b[39;49mstrip()}\n\u001b[0;32m 6\u001b[0m \u001b[39mfor\u001b[39;49;00m filename \u001b[39min\u001b[39;49;00m os\u001b[39m.\u001b[39;49mlistdir(doc_dir)]\n\u001b[0;32m 8\u001b[0m \u001b[39mreturn\u001b[39;00m database\n", - "Cell \u001b[1;32mIn[2], line 5\u001b[0m, in \u001b[0;36m\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mread_files\u001b[39m(doc_dir):\n\u001b[0;32m 2\u001b[0m \u001b[39m# Use a list comprehension to get a list of file paths\u001b[39;00m\n\u001b[0;32m 3\u001b[0m database \u001b[39m=\u001b[39m [{\u001b[39m'\u001b[39m\u001b[39mfilepath\u001b[39m\u001b[39m'\u001b[39m: doc_dir,\n\u001b[0;32m 4\u001b[0m \u001b[39m'\u001b[39m\u001b[39mfilename\u001b[39m\u001b[39m'\u001b[39m: filename,\n\u001b[1;32m----> 5\u001b[0m \u001b[39m'\u001b[39m\u001b[39mtext\u001b[39m\u001b[39m'\u001b[39m: \u001b[39mopen\u001b[39;49m(os\u001b[39m.\u001b[39;49mpath\u001b[39m.\u001b[39;49mjoin(doc_dir, filename), \u001b[39m'\u001b[39;49m\u001b[39mr\u001b[39;49m\u001b[39m'\u001b[39;49m)\u001b[39m.\u001b[39mread()\u001b[39m.\u001b[39mstrip()}\n\u001b[0;32m 6\u001b[0m \u001b[39mfor\u001b[39;00m filename \u001b[39min\u001b[39;00m os\u001b[39m.\u001b[39mlistdir(doc_dir)]\n\u001b[0;32m 8\u001b[0m \u001b[39mreturn\u001b[39;00m database\n", - "File \u001b[1;32m~\\AppData\\Roaming\\Python\\Python311\\site-packages\\IPython\\core\\interactiveshell.py:282\u001b[0m, in \u001b[0;36m_modified_open\u001b[1;34m(file, *args, **kwargs)\u001b[0m\n\u001b[0;32m 275\u001b[0m \u001b[39mif\u001b[39;00m file \u001b[39min\u001b[39;00m {\u001b[39m0\u001b[39m, \u001b[39m1\u001b[39m, \u001b[39m2\u001b[39m}:\n\u001b[0;32m 276\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\n\u001b[0;32m 277\u001b[0m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mIPython won\u001b[39m\u001b[39m'\u001b[39m\u001b[39mt let you open fd=\u001b[39m\u001b[39m{\u001b[39;00mfile\u001b[39m}\u001b[39;00m\u001b[39m by default \u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m 278\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m 279\u001b[0m \u001b[39m\"\u001b[39m\u001b[39myou can use builtins\u001b[39m\u001b[39m'\u001b[39m\u001b[39m open.\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[0;32m 280\u001b[0m )\n\u001b[1;32m--> 282\u001b[0m \u001b[39mreturn\u001b[39;00m io_open(file, \u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n", - "\u001b[1;31mPermissionError\u001b[0m: [Errno 13] Permission denied: '../data/emails/20_newsgroups/alt.atheism'" - ] - } - ], - "source": [ - "# caminho das queries \n", - "query_path = '../data/emails/mini_newsgroups/'\n", - "\n", - "# caminho dos documentos\n", - "docs_path = '../data/emails/20_newsgroups/'\n", - "\n", - "# Import das bases\n", - "database_docs = read_files(docs_path)\n", - "database_query = read_files(query_path)\n", - "\n", - "base_docs = pd.DataFrame(database_docs)\n", - "base_query = pd.DataFrame(database_query)\n", + "base_que = pd.DataFrame(process_files(query_path))\n", "\n", "# Marcação das bases\n", - "base_docs['tag'] = 'doc'\n", - "base_query['tag'] = 'query'\n", + "base_doc['tag'] = 'doc'\n", + "base_que['tag'] = 'query'\n", + "\n", + "# Amostragem para testes\n", + "base_doc = base_doc.sample(frac=0.5, random_state=42)\n", "\n", "# junção das bases \n", - "base = pd.concat([base_docs, base_query])\n", + "base = pd.concat([base_doc, base_que])\n", "base.reset_index(drop=True, inplace=True)\n", "\n", - "del base_docs, base_query, database_docs, database_query\n", - "gc.collect()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
filepathfilenametexttag
0../data/emails/20_newsgroups/misc.forsale/70337Path: cantaloupe.srv.cs.cmu.edu!rochester!udel...doc
1../data/emails/20_newsgroups/misc.forsale/74150Path: cantaloupe.srv.cs.cmu.edu!crabapple.srv....doc
2../data/emails/20_newsgroups/misc.forsale/74720Path: cantaloupe.srv.cs.cmu.edu!das-news.harva...doc
3../data/emails/20_newsgroups/misc.forsale/74721Newsgroups: misc.forsale\\nPath: cantaloupe.srv...doc
4../data/emails/20_newsgroups/misc.forsale/74722Path: cantaloupe.srv.cs.cmu.edu!crabapple.srv....doc
...............
1095../data/emails/mini_newsgroups/misc.forsale/76927Xref: cantaloupe.srv.cs.cmu.edu misc.wanted:31...query
1096../data/emails/mini_newsgroups/misc.forsale/76936Newsgroups: misc.forsale\\nSubject: WANTED LCD ...query
1097../data/emails/mini_newsgroups/misc.forsale/76937Newsgroups: ingr.forsale,hsv.forsale,misc.fors...query
1098../data/emails/mini_newsgroups/misc.forsale/76940Newsgroups: misc.forsale\\nPath: cantaloupe.srv...query
1099../data/emails/mini_newsgroups/misc.forsale/76945Xref: cantaloupe.srv.cs.cmu.edu comp.sys.mac.h...query
\n", - "

1100 rows × 4 columns

\n", - "
" - ], - "text/plain": [ - " filepath filename \n", - "0 ../data/emails/20_newsgroups/misc.forsale/ 70337 \\\n", - "1 ../data/emails/20_newsgroups/misc.forsale/ 74150 \n", - "2 ../data/emails/20_newsgroups/misc.forsale/ 74720 \n", - "3 ../data/emails/20_newsgroups/misc.forsale/ 74721 \n", - "4 ../data/emails/20_newsgroups/misc.forsale/ 74722 \n", - "... ... ... \n", - "1095 ../data/emails/mini_newsgroups/misc.forsale/ 76927 \n", - "1096 ../data/emails/mini_newsgroups/misc.forsale/ 76936 \n", - "1097 ../data/emails/mini_newsgroups/misc.forsale/ 76937 \n", - "1098 ../data/emails/mini_newsgroups/misc.forsale/ 76940 \n", - "1099 ../data/emails/mini_newsgroups/misc.forsale/ 76945 \n", - "\n", - " text tag \n", - "0 Path: cantaloupe.srv.cs.cmu.edu!rochester!udel... doc \n", - "1 Path: cantaloupe.srv.cs.cmu.edu!crabapple.srv.... doc \n", - "2 Path: cantaloupe.srv.cs.cmu.edu!das-news.harva... doc \n", - "3 Newsgroups: misc.forsale\\nPath: cantaloupe.srv... doc \n", - "4 Path: cantaloupe.srv.cs.cmu.edu!crabapple.srv.... doc \n", - "... ... ... \n", - "1095 Xref: cantaloupe.srv.cs.cmu.edu misc.wanted:31... query \n", - "1096 Newsgroups: misc.forsale\\nSubject: WANTED LCD ... query \n", - "1097 Newsgroups: ingr.forsale,hsv.forsale,misc.fors... query \n", - "1098 Newsgroups: misc.forsale\\nPath: cantaloupe.srv... query \n", - "1099 Xref: cantaloupe.srv.cs.cmu.edu comp.sys.mac.h... query \n", - "\n", - "[1100 rows x 4 columns]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "base" + "del base_doc, base_que\n", + "\n", + "# remove database from memory\n", + "gc.collect()" ] }, { @@ -318,18 +152,18 @@ "source": [ "
\n", "\n", - "## Processamento de Texto\n", + "## Pré-Processamento de Texto\n", "\n", - "
\n", + "Para minimizar possíveis gargalos de processamento e identificação dos termos relevantes, é realizada a remoção de ruídos utilizando regex. Em seguida, é aplicada a tokenização, que consiste na transformação do texto em uma lista de palavras, a fim de possibilitar a aplicação das técnicas de TF-IDF em um modelo vetorial.\n", "\n", - "### Transformação de minúsculos\n", + "
\n", "\n", - "
" + "### Remoção de palavras e transformação de minúsculos\n" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -337,8 +171,7 @@ "# ([^\\w\\]): para encontrar todos os caracteres que não são letras, números ou barras invertidas ();\n", "# (\\S+\\d\\S+): para encontrar todos os trechos de texto que contêm um ou mais caracteres não brancos (\\S), \n", "# seguidos por um dígito (\\d), seguidos por mais um ou mais caracteres não brancos (\\S).\n", - "base['post'] = base['text'].replace(r'(\\\\[a-z])|([^\\w\\\\])|(\\S+\\d\\S+)', ' ', regex=True)\n", - "\n", + "base['post'] = base['body'].replace(r'(\\\\[a-z])|([^\\w\\\\])|(\\S+\\d\\S+)', ' ', regex=True)\n", "\n", "# Aplicando as funções str.lower() e str.strip() simultaneamente\n", "base['post'] = base['post'].apply(lambda x: x.lower().strip())\n" @@ -353,51 +186,60 @@ "\n", "### Tokenização e Lemmatizer\n", "\n", - "
" + "**Tokenização:** A tokenização de texto é o processo de dividir um texto em unidades menores, chamadas de tokens. Esses tokens podem ser palavras individuais, caracteres, frases ou até mesmo partes específicas de um texto, dependendo do contexto e das necessidades do processamento de linguagem natural. \n", + "\n", + "**Lemmatize:** A lematização de texto é um processo linguístico que visa reduzir as palavras em sua forma base ou forma lematizada. O objetivo é transformar palavras flexionadas em sua forma canônica, chamada de \"lema\" ou \"base\". Por exemplo, a lematização transforma palavras como \"correndo\" em \"correr\", \"carros\" em \"carro\" e assim por diante." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0 path cantaloupe srv c cmu edu rochester udel g...\n", - "1 path from myoakam ci ohio state edu micah r yo...\n", - "2 path from maureen l eagle newsgroup misc forsa...\n", - "3 newsgroup misc forsale path from mike diack mi...\n", - "4 path from jvinson xsoft xerox com jeffrey a vi...\n", - " ... \n", - "1095 xref cantaloupe srv c cmu edu newsgroup misc w...\n", - "1096 newsgroup misc forsale subject want lcd overhe...\n", - "1097 newsgroup ingr forsale hsv forsale misc forsal...\n", - "1098 newsgroup misc forsale path cantaloupe srv c c...\n", - "1099 xref cantaloupe srv c cmu edu path from scott ...\n", - "Name: post, Length: 1100, dtype: object" + "0 todd steve write chuck petch write now it appe...\n", + "1 boston globe wednesday april 21 col 4 bodie fo...\n", + "2 nl chicago wait til next year new york bunch o...\n", + "3 i recent had a case of shingle and my doctor w...\n", + "4 for sale 2 amiga commodore amiga best offer ra...\n", + " ... \n", + "11972 in article huston acces digex com herb huston ...\n", + "11973 i just start read thi newsgroup and haven t be...\n", + "11974 blesed are those who hunger and thirst for rig...\n", + "11975 i m curiou to know if christia ever read book ...\n", + "11976 in article prl csi dit csiro au peter lamb wri...\n", + "Name: post, Length: 11977, dtype: object" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from ir.preprocessing import lemmatize_word\n", + "base['post'] = base['post'].apply(lambda x: ' '.join([lemmatize_word(word.lower()) for word in x.split()]))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Identificação das query / docs\n", "\n", - "base['post'].apply(lambda x: ' '.join([lemmatize_word(word.lower()) for word in x.split()]))" + "Foi feita uma separação do index das query, para pode fazer uma localização do na base origina após o TF-IDF, dado que o TF-IDF reseta os index dos termos por documento" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ - "from ir import tf_idf\n", - "\n", - "weight = tf_idf.tfidf(base, 'post').iloc[1:]\n" + "d_index = base.query('tag==\"doc\"').index\n", + "q_index = base.query('tag==\"query\"').index" ] }, { @@ -405,434 +247,298 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Identificação das query / docs" + "## Processamento dos dados\n", + "\n", + "Aplicação das técnicas estatísticas no conjunto de palavras por documento\n", + "\n", + "### TF IDF\n", + "\n", + "TF-IDF (Term Frequency-Inverse Document Frequency) é uma medida estatística usada para avaliar a importância de um termo em um documento em relação a uma coleção de documentos. É amplamente utilizado em processamento de linguagem natural e recuperação de informações.\n", + "\n", + "O TF-IDF é calculado levando em consideração dois fatores principais:\n", + "\n", + "Frequência do termo (TF - Term Frequency): Mede a frequência com que um termo específico aparece em um documento. Quanto mais vezes um termo aparece, maior é sua relevância no documento.\n", + "\n", + "Frequência inversa do documento (IDF - Inverse Document Frequency): Mede a raridade de um termo em relação a uma coleção de documentos. Quanto menos frequente um termo é em outros documentos da coleção, maior é o seu valor IDF e maior será seu peso para distinguir a importância desse termo no documento atual.\n", + "\n", + "O TF-IDF é calculado multiplicando-se o TF pelo IDF para cada termo em um documento. Dessa forma, termos frequentes no documento e raros na coleção terão um valor TF-IDF mais alto, indicando sua relevância para o documento em questão.\n", + "\n", + "Essa medida é amplamente utilizada em tarefas como recuperação de informações, classificação de texto, sumarização automática e agrupamento de documentos." ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "d_index = base.query('tag==\"doc\"').index\n", - "q_index = base.query('tag==\"query\"').index" + "weights = tfidf(base, 'post').T" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ranqueamento\n", + "\n", + "O ranqueamento de documentos utilizando o TF-IDF (Term Frequency-Inverse Document Frequency) é um método utilizado para ordenar documentos em uma coleção com base na relevância em relação a uma consulta de busca.\n", + "\n", + "Nesse método, cada documento é representado por um vetor numérico, no qual cada dimensão corresponde a um termo presente na coleção de documentos. O valor de cada dimensão é calculado utilizando a fórmula do TF-IDF, que leva em consideração a frequência do termo no documento e a raridade do termo na coleção." ] }, { "cell_type": "code", - "execution_count": 145, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "import itertools\n", - "\n", - "similarity = dict()\n", - "index_matrix = dict()\n", - "rank_matrix = dict()\n", + "rank_geral = linear_kernel(weights.iloc[d_index], weights.iloc[q_index])\n", + "rank_geral = pd.DataFrame(rank_geral, index=d_index, columns=q_index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 3093/3093 - Doc: 1730/3092" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 3 function calls in 0.000 seconds\n", + "\n", + " Ordered by: internal time\n", + "\n", + " ncalls tottime percall cumtime percall filename:lineno(function)\n", + " 1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}\n", + " 1 0.000 0.000 0.000 0.000 :1()\n", + " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}" + ] + } + ], + "source": [ + "def calcular_resultados_relevantes(q_index: list, base: pd.DataFrame) -> 'resultados_relevantes[dict], resultados_sistema[dict]':\n", + " resultados_sistema = {}\n", + "\n", + " for q in q_index: \n", + " resultados_sistema[q] = rank_geral[q].sort_values(ascending=False).index\n", + "\n", + " resultados_relevantes = {}\n", + "\n", + " for q in q_index:\n", + " q_genre = base.iloc[q]['genres']\n", + "\n", + " k = []\n", + "\n", + " for d in resultados_sistema[q]:\n", + " d_genre = base.iloc[d]['genres']\n", + " \n", + " # Verifica qual lista de gêneros é menor para otimizar a comparação\n", + " if len(d_genre) > len(q_genre):\n", + " comparativo_menor = q_genre\n", + " comparativo_maior = d_genre\n", + " else:\n", + " comparativo_menor = d_genre\n", + " comparativo_maior = q_genre\n", + " \n", + " # Verifica se há pelo menos um gênero em comum entre as listas\n", + " partial_relevance = any(i in comparativo_maior for i in comparativo_menor)\n", + " \n", + " if partial_relevance:\n", + " k.append(d)\n", + " \n", + " print(f'\\rQuery: {q}/{q_index.max()} - Doc: {d}/{d_index.max()}', end='')\n", + " sys.stdout.flush()\n", "\n", - "for j in q_index:\n", - " for i in d_index: \n", - " numerator = np.sum( weight.loc[:,i] * weight.loc[: , j])\n", - " denominator = np.linalg.norm(weight.loc[:,i])*np.linalg.norm(weight.loc[:,1019])\n", - " similarity[i] = numerator/denominator\n", + " resultados_relevantes[q] = k\n", + " \n", + " return resultados_relevantes, resultados_sistema\n", "\n", + "resultados_relevantes, resultados_sistema = calcular_resultados_relevantes(q_index, base)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Métricas\n", "\n", - " rank_matrix[j] = pd.DataFrame(similarity.values(), columns=['rank']).sort_values(by='rank', ascending=False).head(10).values.tolist()\n", - " index_matrix[j] = pd.DataFrame(similarity.values(), columns=['rank']).sort_values(by='rank', ascending=False).head(10).index.to_list()\n", + "P@N: essa métrica mede a proporção de documentos relevantes presentes entre os 10 primeiros resultados retornados por um sistema de busca em resposta a uma consulta.\n", "\n", - " \n" + "MAP (Mean Average Precision): o MAP leva em consideração a precisão e a ordenação dos resultados retornados por um sistema de busca em relação a um conjunto de consultas. Ele mede a média das precisões médias de cada consulta." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def calcular_p_n_media(resultados_relevantes, resultados_sistema, n):\n", + " \"\"\"\n", + " Calcula a média da precisão P@n para um conjunto de consultas e seus resultados relevantes.\n", + "\n", + " Parâmetros:\n", + " - resultados_relevantes (dict): Um dicionário que mapeia cada consulta aos seus resultados relevantes.\n", + " - resultados_sistema (dict): Um dicionário que mapeia cada consulta aos resultados retornados pelo sistema.\n", + " - n (int): O número de resultados a considerar para o cálculo da precisão.\n", + "\n", + " Retorno:\n", + " - p_n_media (float): A média da precisão P@n para todas as consultas.\n", + "\n", + " \"\"\"\n", + " def calcular_p_n(resultados, relevantes):\n", + " \"\"\"\n", + " Calcula a precisão P@n para uma lista de resultados e seus resultados relevantes.\n", + "\n", + " Parâmetros:\n", + " - resultados (list): Uma lista de resultados retornados pelo sistema.\n", + " - relevantes (list): Uma lista de resultados relevantes para a consulta.\n", + "\n", + " Retorno:\n", + " - p_n (float): A precisão P@n.\n", + "\n", + " \"\"\"\n", + " if len(resultados) > n:\n", + " resultados = resultados[:n] # Considerar apenas os primeiros n resultados\n", + " num_relevantes = len(set(resultados) & set(relevantes)) # Contar quantos resultados relevantes foram encontrados\n", + " p_n = num_relevantes / n # Calcular a precisão P@n\n", + " return p_n\n", + "\n", + " p_n_total = 0\n", + " for consulta, relevantes in resultados_relevantes.items():\n", + " resultados = resultados_sistema.get(consulta, []) # Obtém os resultados retornados pelo sistema para a consulta\n", + " p_n = calcular_p_n(resultados, relevantes)\n", + " p_n_total += p_n\n", + "\n", + " p_n_media = p_n_total / len(resultados_relevantes)\n", + " return p_n_media\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Média do P@10: 0.719268030139934\n", + "Média do P@20: 0.6967168998923577\n", + "Média do P@50: 0.6745748116254034\n", + "Média do P@100: 0.658902045209902\n" + ] + } + ], + "source": [ + "for x in [10, 20, 50, 100]: \n", + " print(f\"Média do P@{x}: {calcular_p_n_media(resultados_relevantes, resultados_sistema, n=x)}\")" ] }, { "cell_type": "code", - "execution_count": 153, + "execution_count": null, "metadata": {}, "outputs": [ { "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
1000100110021003100410051006100710081009...1090109110921093109410951096109710981099
0[0.6422584945103841][0.668743974268336][1.008422835773131][0.6661363151210968][0.8642602181331219][0.7417012424961686][0.7315442686011049][0.9460833202189584][0.9746037822064916][0.6869123604148133]...[1.1523833456270243][0.7956243694544436][1.7802942925566625][0.5158809769289813][0.5234239788184921][0.8038496213979783][0.6360279187397326][1.1259044435676868][1.0616162379284384][0.6784846202202287]
1[0.2873172889001637][0.17456679249116952][0.6332470445844255][0.09678526898308248][0.537824913541413][0.2820702175096787][0.6513139955405113][0.3597970619791958][0.24900044829809295][0.14368626326554504]...[0.42456045151374616][0.13839258426540738][0.1920094056436893][0.4608108432879023][0.46754863207460967][0.635942460180357][0.2673113797648495][0.09064837068978648][0.19426228087688888][0.17427577670397354]
2[0.19584221062188678][0.1319897299803032][0.08491363433325547][0.08737476357264361][0.47799964699339453][0.20691840972537448][0.0713300455225047][0.18078764107798664][0.11093369090167131][0.09580043962698802]...[0.39006994534248846][0.09497709201044909][0.17705994384084703][0.1911406606344065][0.19471247373710213][0.6126542869398587][0.06788233871189489][0.07823702305427702][0.17319361461646068][0.07447944169226609]
3[0.13903116434341475][0.10146093652625415][0.08181050400129704][0.07523129301857605][0.18045913119908524][0.20260530333012666][0.054813355262948726][0.16776960486431058][0.10031171790840715][0.07826399750895882]...[0.2509003350905366][0.08889171346193057][0.16005754765559338][0.053302833660593664][0.053302833660593664][0.2514441707424639][0.06610690581400588][0.07732220562999899][0.17148587761263784][0.04757751873987604]
4[0.1129173777348391][0.08606053698831793][0.07547569629425901][0.06970411933742698][0.17135272355687187][0.20091765863852995][0.05469328989879712][0.16743762657989103][0.09811418008672529][0.07488273104320195]...[0.1456676671253771][0.08031528425526144][0.1591723994058402][0.05187299077727413][0.04876597436921601][0.24540764374264745][0.064867860088572][0.07458882712067232][0.1268769662336863][0.04675221931850179]
5[0.11038217708080131][0.08212202043548315][0.07432402899651668][0.06957535331034335][0.11414112796082569][0.09766529639479365][0.05342228639423025][0.11293055713592527][0.09499508593239105][0.07351917900522721]...[0.1356468036645224][0.07846954905194828][0.15849239426755599][0.04462161696830591][0.04472544383210234][0.2051558258313172][0.06082789393903154][0.06855422701443233][0.08964124013628569][0.043706874358644336]
6[0.10833574384967115][0.08201334401786602][0.07412645164725896][0.06759708576024981][0.09130509649851562][0.08716787810262448][0.0497899252125642][0.09487498299853164][0.08477817264550953][0.06935710726422203]...[0.13395484290588885][0.07651073480529516][0.14400058142958222][0.04329534404644248][0.04462161696830591][0.10677052218571517][0.05830025911923057][0.06718300838215913][0.08292563259802246][0.04288337427490202]
7[0.09458970277908005][0.08147133735902357][0.07118734960890093][0.06755116098175724][0.08423578168208135][0.08564850087282809][0.04712198065394311][0.08900364470414873][0.0845410509094711][0.06696048135598477]...[0.12832106795670173][0.0742473891955823][0.1337598250032541][0.03987922316585672][0.04329534404644248][0.08913041300626738][0.05705502660231897][0.06310045914518085][0.07445114613146177][0.04255318648575154]
8[0.06683185055384143][0.08107329389309223][0.06992507760853946][0.0665144106585746][0.07732918671239193][0.07767329982049115][0.04496152399683175][0.07886393345966285][0.08159272098702083][0.0655222722939256]...[0.12560417304820823][0.07411198929338968][0.1331408833577327][0.03857993879037075][0.038711425869337984][0.08897777442428674][0.05560594182068467][0.0626845924656044][0.07237739511197822][0.041613779283231046]
9[0.06139453131422424][0.07948227337943198][0.06689020592169981][0.05955785852513209][0.07517277782794342][0.07765247541664737][0.04318953773752061][0.07531732464870161][0.08098184954929952][0.06458414852590263]...[0.12278663409161311][0.07365677105558269][0.13062404036287226][0.03855871951859559][0.03855871951859559][0.08461722594983144][0.053320319118708596][0.06258022212397257][0.07103356433858925][0.04145958334073781]
\n", - "

10 rows × 100 columns

\n", - "
" - ], "text/plain": [ - " 1000 1001 1002 \n", - "0 [0.6422584945103841] [0.668743974268336] [1.008422835773131] \\\n", - "1 [0.2873172889001637] [0.17456679249116952] [0.6332470445844255] \n", - "2 [0.19584221062188678] [0.1319897299803032] [0.08491363433325547] \n", - "3 [0.13903116434341475] [0.10146093652625415] [0.08181050400129704] \n", - "4 [0.1129173777348391] [0.08606053698831793] [0.07547569629425901] \n", - "5 [0.11038217708080131] [0.08212202043548315] [0.07432402899651668] \n", - "6 [0.10833574384967115] [0.08201334401786602] [0.07412645164725896] \n", - "7 [0.09458970277908005] [0.08147133735902357] [0.07118734960890093] \n", - "8 [0.06683185055384143] [0.08107329389309223] [0.06992507760853946] \n", - "9 [0.06139453131422424] [0.07948227337943198] [0.06689020592169981] \n", - "\n", - " 1003 1004 1005 \n", - "0 [0.6661363151210968] [0.8642602181331219] [0.7417012424961686] \\\n", - "1 [0.09678526898308248] [0.537824913541413] [0.2820702175096787] \n", - "2 [0.08737476357264361] [0.47799964699339453] [0.20691840972537448] \n", - "3 [0.07523129301857605] [0.18045913119908524] [0.20260530333012666] \n", - "4 [0.06970411933742698] [0.17135272355687187] [0.20091765863852995] \n", - "5 [0.06957535331034335] [0.11414112796082569] [0.09766529639479365] \n", - "6 [0.06759708576024981] [0.09130509649851562] [0.08716787810262448] \n", - "7 [0.06755116098175724] [0.08423578168208135] [0.08564850087282809] \n", - "8 [0.0665144106585746] [0.07732918671239193] [0.07767329982049115] \n", - "9 [0.05955785852513209] [0.07517277782794342] [0.07765247541664737] \n", - "\n", - " 1006 1007 1008 \n", - "0 [0.7315442686011049] [0.9460833202189584] [0.9746037822064916] \\\n", - "1 [0.6513139955405113] [0.3597970619791958] [0.24900044829809295] \n", - "2 [0.0713300455225047] [0.18078764107798664] [0.11093369090167131] \n", - "3 [0.054813355262948726] [0.16776960486431058] [0.10031171790840715] \n", - "4 [0.05469328989879712] [0.16743762657989103] [0.09811418008672529] \n", - "5 [0.05342228639423025] [0.11293055713592527] [0.09499508593239105] \n", - "6 [0.0497899252125642] [0.09487498299853164] [0.08477817264550953] \n", - "7 [0.04712198065394311] [0.08900364470414873] [0.0845410509094711] \n", - "8 [0.04496152399683175] [0.07886393345966285] [0.08159272098702083] \n", - "9 [0.04318953773752061] [0.07531732464870161] [0.08098184954929952] \n", - "\n", - " 1009 ... 1090 1091 \n", - "0 [0.6869123604148133] ... [1.1523833456270243] [0.7956243694544436] \\\n", - "1 [0.14368626326554504] ... [0.42456045151374616] [0.13839258426540738] \n", - "2 [0.09580043962698802] ... [0.39006994534248846] [0.09497709201044909] \n", - "3 [0.07826399750895882] ... [0.2509003350905366] [0.08889171346193057] \n", - "4 [0.07488273104320195] ... [0.1456676671253771] [0.08031528425526144] \n", - "5 [0.07351917900522721] ... [0.1356468036645224] [0.07846954905194828] \n", - "6 [0.06935710726422203] ... [0.13395484290588885] [0.07651073480529516] \n", - "7 [0.06696048135598477] ... [0.12832106795670173] [0.0742473891955823] \n", - "8 [0.0655222722939256] ... [0.12560417304820823] [0.07411198929338968] \n", - "9 [0.06458414852590263] ... [0.12278663409161311] [0.07365677105558269] \n", - "\n", - " 1092 1093 1094 \n", - "0 [1.7802942925566625] [0.5158809769289813] [0.5234239788184921] \\\n", - "1 [0.1920094056436893] [0.4608108432879023] [0.46754863207460967] \n", - "2 [0.17705994384084703] [0.1911406606344065] [0.19471247373710213] \n", - "3 [0.16005754765559338] [0.053302833660593664] [0.053302833660593664] \n", - "4 [0.1591723994058402] [0.05187299077727413] [0.04876597436921601] \n", - "5 [0.15849239426755599] [0.04462161696830591] [0.04472544383210234] \n", - "6 [0.14400058142958222] [0.04329534404644248] [0.04462161696830591] \n", - "7 [0.1337598250032541] [0.03987922316585672] [0.04329534404644248] \n", - "8 [0.1331408833577327] [0.03857993879037075] [0.038711425869337984] \n", - "9 [0.13062404036287226] [0.03855871951859559] [0.03855871951859559] \n", - "\n", - " 1095 1096 1097 \n", - "0 [0.8038496213979783] [0.6360279187397326] [1.1259044435676868] \\\n", - "1 [0.635942460180357] [0.2673113797648495] [0.09064837068978648] \n", - "2 [0.6126542869398587] [0.06788233871189489] [0.07823702305427702] \n", - "3 [0.2514441707424639] [0.06610690581400588] [0.07732220562999899] \n", - "4 [0.24540764374264745] [0.064867860088572] [0.07458882712067232] \n", - "5 [0.2051558258313172] [0.06082789393903154] [0.06855422701443233] \n", - "6 [0.10677052218571517] [0.05830025911923057] [0.06718300838215913] \n", - "7 [0.08913041300626738] [0.05705502660231897] [0.06310045914518085] \n", - "8 [0.08897777442428674] [0.05560594182068467] [0.0626845924656044] \n", - "9 [0.08461722594983144] [0.053320319118708596] [0.06258022212397257] \n", - "\n", - " 1098 1099 \n", - "0 [1.0616162379284384] [0.6784846202202287] \n", - "1 [0.19426228087688888] [0.17427577670397354] \n", - "2 [0.17319361461646068] [0.07447944169226609] \n", - "3 [0.17148587761263784] [0.04757751873987604] \n", - "4 [0.1268769662336863] [0.04675221931850179] \n", - "5 [0.08964124013628569] [0.043706874358644336] \n", - "6 [0.08292563259802246] [0.04288337427490202] \n", - "7 [0.07445114613146177] [0.04255318648575154] \n", - "8 [0.07237739511197822] [0.041613779283231046] \n", - "9 [0.07103356433858925] [0.04145958334073781] \n", - "\n", - "[10 rows x 100 columns]" + "0.5882758350175267" ] }, - "execution_count": 153, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "pd.DataFrame(rank_matrix)" + "def average_precision(relevantes, recomendados):\n", + " \"\"\"\n", + " Calcula a Média de Precisão (Average Precision) para um conjunto de itens relevantes e itens recomendados.\n", + "\n", + " Parâmetros:\n", + " - relevantes (list): Uma lista contendo os itens relevantes.\n", + " - recomendados (list): Uma lista contendo os itens recomendados.\n", + "\n", + " Retorno:\n", + " - ap (float): O valor da Média de Precisão.\n", + "\n", + " \"\"\"\n", + " relevancia_cumulativa = 0\n", + " precision_cumulativa = 0\n", + " num_relevantes = len(relevantes)\n", + " ap = 0\n", + "\n", + " for i, rec in enumerate(recomendados):\n", + " if rec in relevantes:\n", + " relevancia_cumulativa += 1\n", + " precision_cumulativa += relevancia_cumulativa / (i + 1)\n", + "\n", + " if num_relevantes > 0:\n", + " ap = precision_cumulativa / num_relevantes\n", + "\n", + " return ap\n", + "\n", + "\n", + "def mean_average_precision(resultados_relevantes, resultados_sistema):\n", + " \"\"\"\n", + " Calcula a Média de Precisão (MAP) para um conjunto de consultas, seus resultados relevantes e resultados retornados pelo sistema.\n", + "\n", + " Parâmetros:\n", + " - resultados_relevantes (dict): Um dicionário que mapeia cada consulta aos seus resultados relevantes.\n", + " - resultados_sistema (dict): Um dicionário que mapeia cada consulta aos resultados retornados pelo sistema.\n", + "\n", + " Retorno:\n", + " - map (float): O valor da Média de Precisão Média (MAP) para todas as consultas.\n", + "\n", + " \"\"\"\n", + " map = 0\n", + " num_consultas = len(resultados_relevantes)\n", + "\n", + " for q in resultados_relevantes:\n", + " relevantes = resultados_relevantes[q]\n", + " recomendados = resultados_sistema[q]\n", + " ap = average_precision(relevantes, recomendados)\n", + " map += ap\n", + "\n", + " if num_consultas > 0:\n", + " map /= num_consultas\n", + "\n", + " return map\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Aplicar o MAP nas consultas\n", + "mean_average_precision(resultados_relevantes, resultados_sistema)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusão: \n", + "\n", + "O modelo vetorial apresentou um valor interessante, considerando que não foram levados em conta diversos aspectos presentes no texto. Por exemplo, nos emails, não havia apenas o texto, mas também o destinatário e remetente, organização, título, datas, entre outros.\n", + "\n", + "Realizando uma recuperação bruta das palavras, foram encontrados valores suficientemente bons para os primeiros 10 arquivos.\n", + "\n", + "Em possíveis modificações, ainda há muito espaço para melhorias." ] } ], diff --git a/notebooks/information_retrieval_movies.ipynb b/notebooks/information_retrieval_movies.ipynb index 45e5166..c9e0fab 100644 --- a/notebooks/information_retrieval_movies.ipynb +++ b/notebooks/information_retrieval_movies.ipynb @@ -5,9 +5,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Pré-Processamento dos Documentos\n", + "# Recuperação da informação para base de Filmes \n", "\n", - "A limpeza dos dados é um processo essencial para garantir a qualidade e a confiabilidade das informações armazenadas em um banco de dados. A limpeza dos dados envolve a identificação e a correção de erros, inconsistências, duplicidades e valores ausentes nos dados. A arquitetura do armazenamento é a forma como os dados são organizados, estruturados e acessados em um banco de dados. Uma das opções de arquitetura é o formato YAML, que significa YAML Ain't Markup Language. O YAML é um formato de serialização de dados que usa uma sintaxe simples e legível para representar estruturas de dados como listas, mapas, sequências e escalares. O YAML é compatível com diversas linguagens de programação e pode ser usado para armazenar dados de forma hierárquica e flexível.\n", + "Foram utilizadas as seguintes bases para o projeto\n", + "\n", + "[Disney+](https://www.kaggle.com/datasets/shivamb/disney-movies-and-tv-shows) \n", + "[HBO Max](https://www.kaggle.com/datasets/dgoenrique/hbo-max-movies-and-tv-shows) \n", + "[Netflix](https://www.kaggle.com/datasets/shivamb/netflix-shows) \n", + "[Amazon Prime](https://www.kaggle.com/datasets/shivamb/amazon-prime-movies-and-tv-shows) \n", "\n", "\n", "
" @@ -15,7 +20,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -25,7 +30,9 @@ "import sys\n", "\n", "import numpy as np # Módulo para trabalhar com matrizes e funções matemáticas\n", - "import pandas as pd # Módulo para trabalhar com dataframes e séries em Python\n" + "import pandas as pd # Módulo para trabalhar com dataframes e séries em Python\n", + "\n", + "from ast import literal_eval\n" ] }, { @@ -35,14 +42,16 @@ "source": [ "
\n", "\n", - "## Estruturação dos Arquivos\n", + "## Leitura dos Arquivos\n", + "\n", + "As bases vieram em formato CSV, portanto, só foi utilizado o pandas para leitura e feito um concat\n", "\n", "
" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -71,7 +80,11 @@ "source": [ "
\n", "\n", - "## Processamento de Texto\n", + "## Pré-Processamento de Texto\n", + "\n", + "Para minimizar possíveis gargalos de processamento e identificação dos termos relevantes, é realizada a remoção de ruídos utilizando regex. Em seguida, é aplicada a tokenização, que consiste na transformação do texto em uma lista de palavras, a fim de possibilitar a aplicação das técnicas de TF-IDF em um modelo vetorial.\n", + "\n", + "Além disso, foram feitas alguns processsos adicionais para possibilitar o processamento sem erros\n", "\n", "
\n" ] @@ -86,12 +99,11 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "from ast import literal_eval\n", - "\n", + "# Preenchimento de NAN para variaveis de gêrenos que contém listas como elementos\n", "base['genres'] = base['genres'].fillna('[]').apply(literal_eval).apply(lambda x: [i for i in x] if isinstance(x, list) else [])" ] }, @@ -100,15 +112,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "### Transformação de minúsculos\n", - "\n", - "
" + "### Remoção de palavras e transformação de minúsculos" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -131,12 +140,18 @@ "\n", "### Tokenização e Lemmatizer\n", "\n", + "**Tokenização:** A tokenização de texto é o processo de dividir um texto em unidades menores, chamadas de tokens. Esses tokens podem ser palavras individuais, caracteres, frases ou até mesmo partes específicas de um texto, dependendo do contexto e das necessidades do processamento de linguagem natural. \n", + "\n", + "**Lemmatize:** A lematização de texto é um processo linguístico que visa reduzir as palavras em sua forma base ou forma lematizada. O objetivo é transformar palavras flexionadas em sua forma canônica, chamada de \"lema\" ou \"base\". Por exemplo, a lematização transforma palavras como \"correndo\" em \"correr\", \"carros\" em \"carro\" e assim por diante.
\n", + "\n", + "### Tokenização e Lemmatizer\n", + "\n", "
" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -150,12 +165,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Identificação das query / docs" + "### Identificação das query / docs\n", + "\n", + "Foi feita uma separação do index das query, para pode fazer uma localização do na base origina após o TF-IDF, dado que o TF-IDF reseta os index dos termos por documento" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -171,34 +188,58 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### TF IDF" + "## Processamento dos dados\n", + "\n", + "Aplicação das técnicas estatísticas no conjunto de palavras por documento\n", + "\n", + "### TF IDF\n", + "\n", + "TF-IDF (Term Frequency-Inverse Document Frequency) é uma medida estatística usada para avaliar a importância de um termo em um documento em relação a uma coleção de documentos. É amplamente utilizado em processamento de linguagem natural e recuperação de informações.\n", + "\n", + "O TF-IDF é calculado levando em consideração dois fatores principais:\n", + "\n", + "Frequência do termo (TF - Term Frequency): Mede a frequência com que um termo específico aparece em um documento. Quanto mais vezes um termo aparece, maior é sua relevância no documento.\n", + "\n", + "Frequência inversa do documento (IDF - Inverse Document Frequency): Mede a raridade de um termo em relação a uma coleção de documentos. Quanto menos frequente um termo é em outros documentos da coleção, maior é o seu valor IDF e maior será seu peso para distinguir a importância desse termo no documento atual.\n", + "\n", + "O TF-IDF é calculado multiplicando-se o TF pelo IDF para cada termo em um documento. Dessa forma, termos frequentes no documento e raros na coleção terão um valor TF-IDF mais alto, indicando sua relevância para o documento em questão.\n", + "\n", + "Essa medida é amplamente utilizada em tarefas como recuperação de informações, classificação de texto, sumarização automática e agrupamento de documentos." ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "from ir.tf_idf import tfidf" + "from ir.tf_idf import tfidf\n", + "\n", + "weights = tfidf(base, 'post').T" ] }, { - "cell_type": "code", - "execution_count": 16, + "attachments": {}, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "weights = tfidf(base, 'post').T" + "## Ranqueamento\n", + "\n", + "O ranqueamento de documentos utilizando o TF-IDF (Term Frequency-Inverse Document Frequency) é um método utilizado para ordenar documentos em uma coleção com base na relevância em relação a uma consulta de busca.\n", + "\n", + "Nesse método, cada documento é representado por um vetor numérico, no qual cada dimensão corresponde a um termo presente na coleção de documentos. O valor de cada dimensão é calculado utilizando a fórmula do TF-IDF, que leva em consideração a frequência do termo no documento e a raridade do termo na coleção." ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ - "from sklearn.metrics.pairwise import linear_kernel" + "from sklearn.metrics.pairwise import linear_kernel\n", + "\n", + "q_index = base[q_index].index\n", + "d_index = base[d_index].index" ] }, { @@ -206,60 +247,455 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Ranqueamento" + "**Importante**\n", + "\n", + "A celula abaixo trás o mesmo resultado da célula seguinte, porém, com tempo de processamente extremamente maior e maior consumo de RAM. \n", + "Recomendo que só seja utilizada, caso deseje compreender o funcionamento do algoritmo e caso tenha uma boa máquina para rodar o processo" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "q_index = base[q_index].index\n", - "d_index = base[d_index].index" + "# import numpy as np\n", + "# from numba import njit, prange\n", + "# import sys\n", + "\n", + "# @njit(parallel=True)\n", + "# def calcular_similaridade_cosseno(vetor1, vetor2):\n", + "# # Verifica se os vetores têm o mesmo tamanho\n", + "# if len(vetor1) != len(vetor2):\n", + "# return 0\n", + " \n", + "# # Calcula o produto interno entre os vetores\n", + "# produto_interno = np.dot(vetor1, vetor2)\n", + " \n", + "# # Calcula a norma dos vetores\n", + "# norma_vetor1 = np.linalg.norm(vetor1)\n", + "# norma_vetor2 = np.linalg.norm(vetor2)\n", + " \n", + "# # Calcula a similaridade do cosseno\n", + "# if (norma_vetor1 * norma_vetor2) != 0: \n", + "# similaridade_cosseno = produto_interno / (norma_vetor1 * norma_vetor2)\n", + "# else: \n", + "# return 0\n", + " \n", + "# return similaridade_cosseno\n", + "\n", + "# rank_geral = {}\n", + "\n", + "# for q in q_index: \n", + "# rank = []\n", + "# for d in d_index: \n", + "# rank.append(calcular_similaridade_cosseno(weights.iloc[q].to_numpy(), weights.iloc[d].to_numpy()))\n", + "# print(f\"\\r query: {q} - doc: {d}\", end=\"\")\n", + "# sys.stdout.flush()\n", + " \n", + "# rank_geral[q] = rank\n" ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
1279111225333435...3067307030753076307930803081308430913093
067.3687550.1248030.2050290.2380010.2045410.0467620.44167813.8290396.7199630.962032...0.0690730.5051550.1441910.1248030.0608390.4757130.2905850.1856410.2544280.285274
30.28249613.3340450.34333414.4370790.4754400.0467620.3944880.4003310.40486214.536195...0.0690730.6019330.0329890.0000000.3862540.4472860.4970310.4613630.0329890.343334
413.3854970.1623720.2050303.1253620.2864820.0467626.93559713.9524420.4091030.670516...0.0690740.6299492.5181610.1623720.1166790.0896822.5088066.4704162.5192470.352836
50.28249620.5254540.32925749.2331880.5937634.70426110.1660650.6320750.47318615.323314...10.56437248.2958552.33105138.9010160.3292570.8324297.3964745.3454182.4763270.621255
60.2171328.68258021.94459615.17760618.8795420.06106522.11496713.84173933.4773282.140575...0.09020057.4836390.0000004.60578325.39963530.0523995.5084880.36194218.4992177.888895
..................................................................
30870.00000011.8990350.0467630.2239240.1872070.0359420.39845313.6502550.1606980.371556...5.02124415.2442050.1857430.1248030.0467620.0359420.1355755.13971735.7696310.271198
30880.0000007.6174850.00000010.5142860.1686470.0000000.5794450.25442819.56421312.294900...11.9419058.1807352.1453080.4105590.37177711.9419052.2749330.12480310.21719620.962194
30890.0000004.9859430.0000003.0216030.1686470.0000000.2076680.1296250.1296250.168647...0.00000047.40787968.3369700.0000000.0000000.00000051.4191690.0000002.3139540.129625
30900.2824960.3675350.2824960.49264713.8726810.0000008.7984560.42504915.1223520.530150...0.00000036.87927133.9691030.0000005.8689265.9440356.0934135.16927313.5051460.382128
30920.2171327.7868980.29521511.1616945.4366080.06209934.8291825.3811770.3502520.400540...0.07842329.5320312.8240990.2857560.7009020.3685768.2249810.38455828.5150620.286205
\n", + "

2165 rows × 929 columns

\n", + "
" + ], + "text/plain": [ + " 1 2 7 9 11 12 \n", + "0 67.368755 0.124803 0.205029 0.238001 0.204541 0.046762 \\\n", + "3 0.282496 13.334045 0.343334 14.437079 0.475440 0.046762 \n", + "4 13.385497 0.162372 0.205030 3.125362 0.286482 0.046762 \n", + "5 0.282496 20.525454 0.329257 49.233188 0.593763 4.704261 \n", + "6 0.217132 8.682580 21.944596 15.177606 18.879542 0.061065 \n", + "... ... ... ... ... ... ... \n", + "3087 0.000000 11.899035 0.046763 0.223924 0.187207 0.035942 \n", + "3088 0.000000 7.617485 0.000000 10.514286 0.168647 0.000000 \n", + "3089 0.000000 4.985943 0.000000 3.021603 0.168647 0.000000 \n", + "3090 0.282496 0.367535 0.282496 0.492647 13.872681 0.000000 \n", + "3092 0.217132 7.786898 0.295215 11.161694 5.436608 0.062099 \n", + "\n", + " 25 33 34 35 ... 3067 3070 \n", + "0 0.441678 13.829039 6.719963 0.962032 ... 0.069073 0.505155 \\\n", + "3 0.394488 0.400331 0.404862 14.536195 ... 0.069073 0.601933 \n", + "4 6.935597 13.952442 0.409103 0.670516 ... 0.069074 0.629949 \n", + "5 10.166065 0.632075 0.473186 15.323314 ... 10.564372 48.295855 \n", + "6 22.114967 13.841739 33.477328 2.140575 ... 0.090200 57.483639 \n", + "... ... ... ... ... ... ... ... \n", + "3087 0.398453 13.650255 0.160698 0.371556 ... 5.021244 15.244205 \n", + "3088 0.579445 0.254428 19.564213 12.294900 ... 11.941905 8.180735 \n", + "3089 0.207668 0.129625 0.129625 0.168647 ... 0.000000 47.407879 \n", + "3090 8.798456 0.425049 15.122352 0.530150 ... 0.000000 36.879271 \n", + "3092 34.829182 5.381177 0.350252 0.400540 ... 0.078423 29.532031 \n", + "\n", + " 3075 3076 3079 3080 3081 3084 \n", + "0 0.144191 0.124803 0.060839 0.475713 0.290585 0.185641 \\\n", + "3 0.032989 0.000000 0.386254 0.447286 0.497031 0.461363 \n", + "4 2.518161 0.162372 0.116679 0.089682 2.508806 6.470416 \n", + "5 2.331051 38.901016 0.329257 0.832429 7.396474 5.345418 \n", + "6 0.000000 4.605783 25.399635 30.052399 5.508488 0.361942 \n", + "... ... ... ... ... ... ... \n", + "3087 0.185743 0.124803 0.046762 0.035942 0.135575 5.139717 \n", + "3088 2.145308 0.410559 0.371777 11.941905 2.274933 0.124803 \n", + "3089 68.336970 0.000000 0.000000 0.000000 51.419169 0.000000 \n", + "3090 33.969103 0.000000 5.868926 5.944035 6.093413 5.169273 \n", + "3092 2.824099 0.285756 0.700902 0.368576 8.224981 0.384558 \n", + "\n", + " 3091 3093 \n", + "0 0.254428 0.285274 \n", + "3 0.032989 0.343334 \n", + "4 2.519247 0.352836 \n", + "5 2.476327 0.621255 \n", + "6 18.499217 7.888895 \n", + "... ... ... \n", + "3087 35.769631 0.271198 \n", + "3088 10.217196 20.962194 \n", + "3089 2.313954 0.129625 \n", + "3090 13.505146 0.382128 \n", + "3092 28.515062 0.286205 \n", + "\n", + "[2165 rows x 929 columns]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "rank_geral = linear_kernel(weights.iloc[d_index], weights.iloc[q_index])\n", - "rank_geral = pd.DataFrame(rank_geral, index=d_index, columns=q_index)" + "rank_geral = pd.DataFrame(rank_geral, index=d_index, columns=q_index)\n", + "rank_geral" ] }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Query: 3093/3093 - Doc: 1730/3092" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 3 function calls in 0.000 seconds\n", - "\n", - " Ordered by: internal time\n", - "\n", - " ncalls tottime percall cumtime percall filename:lineno(function)\n", - " 1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}\n", - " 1 0.000 0.000 0.000 0.000 :1()\n", - " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}" + "Query: 3093/3093 - Doc: 697/30922" ] } ], "source": [ - "import sys\n", - "import numba\n", - "\n", "def calcular_resultados_relevantes(q_index: list, base: pd.DataFrame) -> 'resultados_relevantes[dict], resultados_sistema[dict]':\n", " resultados_sistema = {}\n", "\n", @@ -305,25 +741,52 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Métricas" + "## Métricas\n", + "\n", + "P@N: essa métrica mede a proporção de documentos relevantes presentes entre os 10 primeiros resultados retornados por um sistema de busca em resposta a uma consulta.\n", + "\n", + "MAP (Mean Average Precision): o MAP leva em consideração a precisão e a ordenação dos resultados retornados por um sistema de busca em relação a um conjunto de consultas. Ele mede a média das precisões médias de cada consulta." ] }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Média do P@: 0.719268030139934\n" + "Média do P@: 0.7194833153928942\n" ] } ], "source": [ "def calcular_p_n_media(resultados_relevantes, resultados_sistema, n):\n", + " \"\"\"\n", + " Calcula a média da precisão P@n para um conjunto de consultas e seus resultados relevantes.\n", + "\n", + " Parâmetros:\n", + " - resultados_relevantes (dict): Um dicionário que mapeia cada consulta aos seus resultados relevantes.\n", + " - resultados_sistema (dict): Um dicionário que mapeia cada consulta aos resultados retornados pelo sistema.\n", + " - n (int): O número de resultados a considerar para o cálculo da precisão.\n", + "\n", + " Retorno:\n", + " - p_n_media (float): A média da precisão P@n para todas as consultas.\n", + "\n", + " \"\"\"\n", " def calcular_p_n(resultados, relevantes):\n", + " \"\"\"\n", + " Calcula a precisão P@n para uma lista de resultados e seus resultados relevantes.\n", + "\n", + " Parâmetros:\n", + " - resultados (list): Uma lista de resultados retornados pelo sistema.\n", + " - relevantes (list): Uma lista de resultados relevantes para a consulta.\n", + "\n", + " Retorno:\n", + " - p_n (float): A precisão P@n.\n", + "\n", + " \"\"\"\n", " if len(resultados) > n:\n", " resultados = resultados[:n] # Considerar apenas os primeiros n resultados\n", " num_relevantes = len(set(resultados) & set(relevantes)) # Contar quantos resultados relevantes foram encontrados\n", @@ -337,26 +800,22 @@ " p_n_total += p_n\n", "\n", " p_n_media = p_n_total / len(resultados_relevantes)\n", - " return p_n_media\n", - "\n", - "# Utilizando a função para calcular a média do P@n\n", - "p_n_media = calcular_p_n_media(resultados_relevantes, resultados_sistema, n=10)\n", - "print(f\"Média do P@: {p_n_media}\")" + " return p_n_media\n" ] }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Média do P@10: 0.719268030139934\n", - "Média do P@20: 0.6967168998923577\n", - "Média do P@50: 0.6745748116254034\n", - "Média do P@100: 0.658902045209902\n" + "Média do P@10: 0.7194833153928942\n", + "Média do P@20: 0.6968245425188377\n", + "Média do P@50: 0.6746178686759955\n", + "Média do P@100: 0.6589773950484382\n" ] } ], @@ -367,22 +826,33 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0.5882758350175267" + "0.5883161088059286" ] }, - "execution_count": 83, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def average_precision(relevantes, recomendados):\n", + " \"\"\"\n", + " Calcula a Média de Precisão (Average Precision) para um conjunto de itens relevantes e itens recomendados.\n", + "\n", + " Parâmetros:\n", + " - relevantes (list): Uma lista contendo os itens relevantes.\n", + " - recomendados (list): Uma lista contendo os itens recomendados.\n", + "\n", + " Retorno:\n", + " - ap (float): O valor da Média de Precisão.\n", + "\n", + " \"\"\"\n", " relevancia_cumulativa = 0\n", " precision_cumulativa = 0\n", " num_relevantes = len(relevantes)\n", @@ -398,7 +868,19 @@ "\n", " return ap\n", "\n", + "\n", "def mean_average_precision(resultados_relevantes, resultados_sistema):\n", + " \"\"\"\n", + " Calcula a Média de Precisão (MAP) para um conjunto de consultas, seus resultados relevantes e resultados retornados pelo sistema.\n", + "\n", + " Parâmetros:\n", + " - resultados_relevantes (dict): Um dicionário que mapeia cada consulta aos seus resultados relevantes.\n", + " - resultados_sistema (dict): Um dicionário que mapeia cada consulta aos resultados retornados pelo sistema.\n", + "\n", + " Retorno:\n", + " - map (float): O valor da Média de Precisão Média (MAP) para todas as consultas.\n", + "\n", + " \"\"\"\n", " map = 0\n", " num_consultas = len(resultados_relevantes)\n", "\n", @@ -411,11 +893,31 @@ " if num_consultas > 0:\n", " map /= num_consultas\n", "\n", - " return map\n", - "\n", + " return map\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "# Aplicar o MAP nas consultas\n", - "map_result = mean_average_precision(resultados_relevantes, resultados_sistema)\n", - "map_result" + "mean_average_precision(resultados_relevantes, resultados_sistema)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusão: \n", + "\n", + "O modelo vetorial apresentou valores interessante, considerando que não foram levados em conta diversos aspectos presentes na base de dados. Por exemplo, diretor, nota do IMDB, orçamento, genêro, PG e etc\n", + "\n", + "Realizando uma recuperação bruta das palavras, foram encontrados valores suficientemente bons.\n", + "\n", + "Para um projeto de recuperação da informação, é um fundamento funcional, porém pensando na expanção para um sistema de recomendação de filmes, existem diversos aspectos que podem e devem ser aprofundados em relação ao sistema apresentado." ] } ],