Skip to content

Instantly share code, notes, and snippets.

@fabiozeh
Last active December 16, 2022 19:05
Show Gist options
  • Save fabiozeh/1e7ac7bb5c11063a7497783c26c6bb16 to your computer and use it in GitHub Desktop.
Save fabiozeh/1e7ac7bb5c11063a7497783c26c6bb16 to your computer and use it in GitHub Desktop.
Protótipo de análise bibliométrica orientada por palavras-chave sobre metadados de dissertações e teses da USP.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "8e69726f",
"metadata": {},
"source": [
"### Protótipo de Ambiente de Estudo Bibliométrico\n",
"\n",
" Este _notebook_ utiliza dados exportados da base de dissertações e teses USP para realizar uma série de buscas textuais caracterizadoras do Eixo Saúde Pública do [Programa Eixos Temáticos USP](http://proetusp.webhostusp.sti.usp.br/?q=projeto).\n",
" \n",
" Em seguida, apresenta-se um exemplo de análise automatizada na forma de gráficos da evolução anual da produção de trabalhos contendo cada um dos critérios de busca utilizados."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "b4e086a2",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import pdfplumber\n",
"import json, codecs\n",
"import re, os\n",
"import multiprocessing as mp\n",
"import matplotlib.pyplot as plt\n",
"from datetime import datetime\n",
"from dateutil import parser\n",
"\n",
"'''\n",
" Esta função recebe o dataframe construído com a base de dissertações e teses e retorna uma função que \n",
" busca um termo ou expressão regular no título, resumo e palavras-chave dos trabalhos, com o cuidado de\n",
" garantir que o termo não seja parte de outra palavra (e.g.: se o termo for 'cidade', não incluirá\n",
" ocorrências da palavra 'felicidade').\n",
"'''\n",
"def get_s(df):\n",
" def s(c):\n",
" q = f'(?:^{c}\\W+)|(?:\\W+{c}\\W+)|(?:\\W+{c}$)|(?:^{c}$)'\n",
" mask = df['titulo_original'].str.contains(q) | df['resumo_original'].str.contains(q) | df['palavra_chave'].str.contains(q)\n",
" return mask\n",
" return s\n",
"\n",
"# carregar metadados\n",
"teses = pd.read_csv(r'../../teses/teses.csv')\n",
"# arquivos = pd.read_csv(r'../../teses/teses-arquivos.csv')"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5d7163f2",
"metadata": {},
"outputs": [],
"source": [
"'''\n",
" Esta função recebe como argumento uma função de busca nos moldes da produzida por get_s e retorna um dicionário\n",
" de termos referentes ao eixo Saúde Pública, no qual as chaves explicam o teor de cada busca e os valores são\n",
" _thunks_ (funções sem argumentos) que, quando chamadas, obtêm o resultado da busca da chave em questão. Desta \n",
" maneira, atrasa-se a execução da busca para melhor controlar o feedback ao usuário na espera pela sua execução. \n",
" Para funções de busca como obtidas em get_s, o resultado da busca consistirá em listas booleanas que indicam, \n",
" para cada trabalho presente na base, se o mesmo atende ou não ao critério de busca - i.e.: máscaras de seleção.\n",
" \n",
" Obs.: o uso da função de busca como argumento torna esta função agnóstica em relação à implementação da base de\n",
" dados e do mecanismo de busca.\n",
"'''\n",
"def masks_saude(s):\n",
" m_saude = s('saúde')\n",
" m_sus = s('sus')\n",
" return {\n",
" 'Sistema(s) de Saúde': lambda: s('sistemas? de saúde'),\n",
" 'Sistema Único de Saúde / SUS': lambda: s('sistema único de saúde') | m_sus,\n",
" 'Serviços de Saúde': lambda: s('serviços de saúde'),\n",
" 'Política(s) de Saúde': lambda: s('políticas? de saúde'),\n",
" 'Financiamento + Saúde': lambda: s('financiamento') & m_saude,\n",
" 'Fundo Nacional de Saúde': lambda: s('fundo nacional de saúde'),\n",
" 'Fundo Estadual de Saúde': lambda: s('fundo estadual de saúde'),\n",
" 'Fundo Municipal de Saúde': lambda: s('fundo municipal de saúde'),\n",
" 'Financeirização + Saúde': lambda: s('financeirização') & m_saude,\n",
" 'Acumulação de Capital + Saúde': lambda: s('acumulação de capital') & m_saude,\n",
" 'Privatização + Saúde': lambda: s('privatização') & m_saude,\n",
" 'Contas + Saúde': lambda: s('contas') & m_saude,\n",
" 'Gasto + Saúde': lambda: s('gasto') & m_saude,\n",
" 'Despesas + Saúde': lambda: s('despesas') & m_saude,\n",
" 'Planos de Saúde/Seguros de Saúde': lambda: s('planos de saúde') | s('seguros de saúde'),\n",
" 'Saúde Suplementar': lambda: s('saúde suplementar'),\n",
" 'Saúde Privada': lambda: s('saúde privada'),\n",
" 'Clínicas Populares': lambda: s('clínicas populares'),\n",
" 'Serviços de Apoio ao Diagnóstico e à Terapia / SADT': lambda: s('serviços de apoio ao diagnóstico e à terapia') | s('sadt'),\n",
" 'Medicina Diagnóstica': lambda: s('medicina diagnóstica'),\n",
" 'Valores + Procedimentos + SUS': lambda: s('valores') & s('procedimentos') & m_sus,\n",
" 'Tabela SUS': lambda: s('tabela sus'),\n",
" 'Inclusão + Itens + SUS': lambda: s('inclusão') & s('itens') & m_sus,\n",
" 'Recursos Humanos em Saúde': lambda: s('recursos humanos em saúde'),\n",
" 'Distribuição de médicos': lambda: s('distribuição de médicos'),\n",
" 'Força de Trabalho + Saúde': lambda: s('força de trabalho') & m_saude,\n",
" 'Formação + Saúde': lambda: s('formação') & m_saude,\n",
" 'Complexo Econômico/Econômico-Industrial + Saúde': lambda: s('complexo econômico(?:-industrial)?') & m_saude,\n",
" 'Assistência Farmacêutica': lambda: s('assistência farmacêutica'),\n",
" 'Farmácia Popular': lambda: s('farmácia popular'),\n",
" 'Acesso a(à) Medicação': lambda: s('acesso [aà] medicação'),\n",
" 'Incorporação de Tecnologias/Tecnológica + Saúde': lambda: s('incorporação (?:de tecnologias|tecnológica)') & m_saude,\n",
" 'Avaliação + Saúde': lambda: s('avaliação') & m_saude,\n",
" 'Avaliação de Serviços de Saúde': lambda: s('avaliação de serviços de saúde'),\n",
" 'Tecnologias + Saúde': lambda: s('tecnologias') & m_saude,\n",
" 'Telessaúde': lambda: s('telessaúde'),\n",
" 'Telemedicina': lambda: s('telemedicina'),\n",
" 'Teleconsulta': lambda: s('teleconsulta'),\n",
" 'Cobertura Universal + Saúde': lambda: s('cobertura universal') & m_saude,\n",
" 'Fundo de Ações Estratégicas e Compensação': lambda: s('fundo de ações estratégicas e compensação'),\n",
" 'Educação + Saúde': lambda: s('educação') & m_saude,\n",
" 'Acesso + Saúde': lambda: s('acesso') & m_saude,\n",
" 'Prontuário Eletrônico': lambda: s('prontuário eletrônico'),\n",
" 'Secretaria de Saúde': lambda: s('secretaria de saúde'),\n",
" 'Gestão + Saúde': lambda: s('gestão') & m_saude,\n",
" 'Organização(ões) social(is) + Saúde': lambda: s('organizaç(?:ão|ões) socia(?:l|is)') & m_saude,\n",
" 'Contratualização': lambda: s('contratualização'),\n",
" 'Região de saúde': lambda: s('região de saúde'),\n",
" 'Regionalização': lambda: s('regionalização'),\n",
" 'Hierarquização': lambda: s('hierarquização'),\n",
" 'Redes de Atenção à Saúde': lambda: s('redes de atenção à saúde'),\n",
" 'Determinantes Sociais de Saúde': lambda: s('determinantes sociais de saúde'),\n",
" 'Determinação Social da Saúde': lambda: s('determinação social da saúde'),\n",
" 'Atenção Primária + Saúde': lambda: s('atenção primária') & m_saude,\n",
" 'Atenção Básica': lambda: s('atenção básica'),\n",
" 'Estratégia Saúde da Família': lambda: s('estratégia .?saúde da família.?'),\n",
" 'Assistência de Média Complexidade': lambda: s('assistência de média complexidade'),\n",
" 'Assistência de Elevada Complexidade': lambda: s('assistência de elevada complexidade'),\n",
" 'Assistência Farmacêutica': lambda: s('assistência farmacêutica'),\n",
" 'Atendimento de Doenças Raras': lambda: s('atendimento de doenças raras'),\n",
" 'Necessidades + Saúde': lambda: s('necessidades') & m_saude,\n",
" 'Mapa Assistencial': lambda: s('mapa assistencial'),\n",
" 'Desigualdades + Saúde': lambda: s('desigualdades') & m_saude,\n",
" 'Iniquidades em Saúde': lambda: s('iniq[üu]idades em saúde'),\n",
" 'Gradiente + Saúde': lambda: s('gradiente') & m_saude,\n",
" 'Condições de Saúde': lambda: s('condições de saúde'),\n",
" 'Condições de Vida': lambda: s('condições de vida'),\n",
" 'Distribuição de Água e Esgoto à População': lambda: s('distribuição de água e esgoto à população'),\n",
" 'Programa de Vacinação': lambda: s('programa de vacinação'),\n",
" 'Produção e Desenvolvimento de Vacinas': lambda: s('produção e desenvolvimento de vacinas'),\n",
" 'Controle de Pandemias': lambda: s('controle de pandemias'),\n",
" 'Prevenção e Promoção da Saúde': lambda: s('prevenção e promoção da saúde'),\n",
" 'Comunicação em Saúde': lambda: s('comunicação em saúde'),\n",
" 'Conselho de Saúde': lambda: s('conselho de saúde'),\n",
" 'Planejamento + Saúde': lambda: s('planejamento') & m_saude,\n",
" 'Regulação + Saúde': lambda: s('regulação') & m_saude,\n",
" 'Judicialização + Saúde': lambda: s('judicialização') & m_saude,\n",
" 'Complexo Regulador': lambda: s('complexo regulador'),\n",
" 'Vigilância + Saúde': lambda: s('vigilância') & m_saude,\n",
" 'Reabilitação': lambda: s('reabilitação'),\n",
" 'Protocolos Clínicos e de Regulação': lambda: s('protocolos clínicos e de regulação'),\n",
" 'Protocolos Assistenciais': lambda: s('protocolos assistenciais'),\n",
" 'Protocolos Clínicos e Diretrizes Terapêuticas': lambda: s('protocolos clínicos e diretrizes terapêuticas'),\n",
" 'Pesquisa + Saúde': lambda: s('pesquisa') & m_saude,\n",
" 'Evidência Científica + Saúde': lambda: s('evidência científica') & m_saude,\n",
" 'Custo Efetividade + Saúde': lambda: s('custo efetividade') & m_saude,\n",
" 'Controle Social + Saúde': lambda: s('controle social') & m_saude,\n",
" 'Equidade': lambda: s('equidade'),\n",
" 'Integralidade': lambda: s('integralidade'),\n",
" 'Acesso Universal': lambda: s('acesso universal'),\n",
" 'Universalidade': lambda: s('universalidade'),\n",
" 'Indicadores + Saúde': lambda: s('indicadores') & m_saude,\n",
" 'Corrupção + Saúde': lambda: s('corrupção') & m_saude,\n",
" 'Agência Nacional de Saúde Suplementar': lambda: s('agência nacional de saúde suplementar'),\n",
" 'Agência de Vigilância Sanitária': lambda: s('agência de vigilância sanitária'),\n",
" 'Produção + Saúde': lambda: s('produção') & m_saude,\n",
" 'Produção Assistencial': lambda: s('produção assistencial'),\n",
" 'Plano Plurianual': lambda: s('plano plurianual'),\n",
" 'Plano Sanitário': lambda: s('plano sanitário'),\n",
" 'Programação Pactuada Integrada': lambda: s('programação pactuada integrada'),\n",
" 'Plano + Salários + Saúde': lambda: s('plano') & s('salários') & m_saude,\n",
" 'Auditoria + Saúde': lambda: s('auditoria') & m_saude,\n",
" 'Urgência e Emergência': lambda: s('urgência e emergência'),\n",
" 'Filas de Espera + Saúde': lambda: s('filas de espera') & m_saude,\n",
" 'Mutirões + Saúde': lambda: s('mutirões') & m_saude,\n",
" 'Programa de Saúde': lambda: s('programa de saúde'),\n",
" 'Acolhimento na Saúde': lambda: s('acolhimento na saúde'),\n",
" 'Matriciamento + Saúde': lambda: s('matriciamento') & m_saude,\n",
" 'Atenção Multidisciplinar + Saúde': lambda: s('atenção multidisciplinar') & m_saude,\n",
" 'Atenção Multiprofissional + Saúde': lambda: s('atenção multiprofissional') & m_saude,\n",
" 'Rastreamento + Saúde': lambda: s('rastreamento') & m_saude,\n",
" 'Tratamento Fora do Domicílio': lambda: s('tratamento fora do domicílio'),\n",
" 'Transporte Sanitário': lambda: s('transporte sanitário'),\n",
" 'Linhas de Cuidado + Saúde': lambda: s('linhas de cuidado') & m_saude,\n",
" 'Saúde da População Negra': lambda: s('saúde da população negra'),\n",
" 'Saúde Indígena': lambda: s('saúde indígena'),\n",
" 'Saúde Sexual': lambda: s('saúde sexual'),\n",
" 'Saúde Reprodutiva': lambda: s('saúde reprodutiva'),\n",
" 'Mortes/Óbitos evitáveis': lambda: s('(?:mortes|óbitos) evitáveis'),\n",
" 'Epidemia de AIDS': lambda: s('epidemia de aids'),\n",
" 'Doenças Tropicais': lambda: s('doenças tropicais'),\n",
" 'Saúde Ambiental': lambda: s('saúde ambiental'),\n",
" 'Saúde Global': lambda: s('saúde global')\n",
" }"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "8f84d182",
"metadata": {},
"outputs": [],
"source": [
"## Conversão dos textos para caixa baixa - etapa necessária\n",
"\n",
"teses['titulo_original'] = teses['titulo_original'].str.lower()\n",
"teses['resumo_original'] = teses['resumo_original'].str.lower()\n",
"teses['palavra_chave'] = teses['palavra_chave'].str.lower()"
]
},
{
"cell_type": "markdown",
"id": "fbe61951",
"metadata": {},
"source": [
"O código abaixo exemplifica o processo de execução das buscas e agrega os resultados em um novo dicionário. A célula seguinte, para melhor exibição, insere os resultados em um DataFrame."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6d680a8a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processando Saúde Global (122/122)\n"
]
}
],
"source": [
"from IPython.display import clear_output\n",
"import sys\n",
"\n",
"s = get_s(teses)\n",
"\n",
"msks = masks_saude(s)\n",
"\n",
"res = {}\n",
"i = 1\n",
"for k,f in msks.items():\n",
" clear_output()\n",
" print(f'Processando {k} ({i}/{len(msks)})')\n",
" i += 1\n",
" sys.stdout.flush()\n",
" res[k] = f()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "a9b16f28",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Chave</th>\n",
" <th>Resultados</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Sistema(s) de Saúde</td>\n",
" <td>471</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Sistema Único de Saúde / SUS</td>\n",
" <td>1060</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Serviços de Saúde</td>\n",
" <td>1362</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Política(s) de Saúde</td>\n",
" <td>320</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Financiamento + Saúde</td>\n",
" <td>133</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>117</th>\n",
" <td>Mortes/Óbitos evitáveis</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>118</th>\n",
" <td>Epidemia de AIDS</td>\n",
" <td>22</td>\n",
" </tr>\n",
" <tr>\n",
" <th>119</th>\n",
" <td>Doenças Tropicais</td>\n",
" <td>36</td>\n",
" </tr>\n",
" <tr>\n",
" <th>120</th>\n",
" <td>Saúde Ambiental</td>\n",
" <td>105</td>\n",
" </tr>\n",
" <tr>\n",
" <th>121</th>\n",
" <td>Saúde Global</td>\n",
" <td>43</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>122 rows × 2 columns</p>\n",
"</div>"
],
"text/plain": [
" Chave Resultados\n",
"0 Sistema(s) de Saúde 471\n",
"1 Sistema Único de Saúde / SUS 1060\n",
"2 Serviços de Saúde 1362\n",
"3 Política(s) de Saúde 320\n",
"4 Financiamento + Saúde 133\n",
".. ... ...\n",
"117 Mortes/Óbitos evitáveis 8\n",
"118 Epidemia de AIDS 22\n",
"119 Doenças Tropicais 36\n",
"120 Saúde Ambiental 105\n",
"121 Saúde Global 43\n",
"\n",
"[122 rows x 2 columns]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quantidades = pd.DataFrame(list(zip(res.keys(), list(map(sum, res.values())))), columns=['Chave', 'Resultados'])\n",
"\n",
"quantidades"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "dd4228ac",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total de trabalhos: 11095\n"
]
}
],
"source": [
"from functools import reduce\n",
"todos = reduce(lambda x,y: x | y, res.values())\n",
"print(f'Total de trabalhos: {sum(todos)}')"
]
},
{
"cell_type": "markdown",
"id": "19b5c80c",
"metadata": {},
"source": [
"A soma simples de resultados por chave dá uma ideia da quantidade de trabalhos contemplados por mais de uma chave."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "97f0d187",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"27027"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum(quantidades.Resultados)"
]
},
{
"cell_type": "markdown",
"id": "0200104b",
"metadata": {},
"source": [
"#### Salvando os dados"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "c3cfed60",
"metadata": {},
"outputs": [],
"source": [
"\n",
"teses.loc[todos].to_csv('saude_v3.tsv', sep='\\t')\n",
"\n",
"quantidades.to_csv('relatorio_saude_v3.csv')\n",
"\n",
"import pickle\n",
"with open('masks_saude_v3.pkl', 'wb') as f:\n",
" pickle.dump(masks_saude, f)"
]
},
{
"cell_type": "markdown",
"id": "b39c5f73",
"metadata": {},
"source": [
"#### Geração de gráficos"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "2c3d262b",
"metadata": {},
"outputs": [],
"source": [
"import unicodedata\n",
"\n",
"teses['data'] = teses['data_defesa'].apply(parser.parse)\n",
"todas_ano = []\n",
"x = list(range(1970, 2023))\n",
"for year in range(1970, 2023):\n",
" todas_ano.append(sum((teses.data > datetime(year, 1, 1)) & (teses.data < datetime(year + 1, 1, 1))))\n",
"\n",
"if not os.path.exists(\"timelines\"):\n",
" os.makedirs(\"timelines\")\n",
"\n",
"for k,v in res.items():\n",
" trab_ano = []\n",
" for year in range(1970, 2023):\n",
" trab_ano.append(sum((teses.data.loc[v] > datetime(year, 1, 1)) & (teses.data.loc[v] < datetime(year + 1, 1, 1))))\n",
" \n",
" plt.style.use('fivethirtyeight')\n",
" fig,ax = plt.subplots(figsize=(16, 8))\n",
" \n",
" ax.set_xlabel('Ano')\n",
" ax.set_title(f'Trabalhos defendidos por ano referentes à chave \"{k}\" e total da produção USP')\n",
"\n",
" ax.plot(x, todas_ano, color='cyan', linestyle='--', linewidth=1.6)\n",
" ax.set_ylabel(\"Total de trabalhos defendidos\", color=\"cyan\")\n",
" ax.tick_params(axis='y', colors='cyan')\n",
"\n",
" ax2 = ax.twinx()\n",
" ax2.plot(x, trab_ano, color=(240/255, 104/255, 102/255, 0.6))\n",
" ax2.set_ylabel('Trabalhos sobre o tema em questão', color=(240/255, 104/255, 102/255, 0.6))\n",
" ax2.tick_params(axis='y', colors=(240/255, 104/255, 102/255, 0.6))\n",
"\n",
" fig.tight_layout()\n",
" \n",
" fname = unicodedata.normalize('NFKD', k).encode('ascii', 'ignore').decode('ascii')\n",
" fname = re.sub(r'[^\\w\\s-]', '', fname.lower())\n",
" fname = re.sub(r'[-\\s]+', '-', fname).strip('-_')\n",
" plt.savefig(f'timelines/fig_timeline_{fname}.jpg')\n",
"\n",
" plt.close()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53a3cfe4",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"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.8.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment