Taught in partnership with the Tutorial Education Program (PET) of the UFMG Social Sciences course on August 30 and 31, 2022.
Ministrado em parceria com o Programa de Educação Tutorial (PET) do curso de Ciências Sociais da UFMG nos dias 30 e 31 de agosto de 2022.
Introdução
Esse curso tem como objetivo facilitar o contato com a linguagem Python e suas possibilidades básicas na área de dados, além de trazer segurança e coragem para que qualquer pessoa se aventure nesse universo!
Para isso, foi utilizado um banco de dados da PNAD (Pesquisa Nacional de Amostra Domiciliar) disponibilizado neste repositório com o nome de df_Minicurso.xlsx, o qual conta com o arquivo de dicionário de variáveis (dicionario.xls).
Em um primeiro momento, tivemos a parte teórica abrangendo os seguintes temas:
-
Visão abrangente sobre Python (e R) e suas possibilidades;
-
Linha Histórica da PNAD;
-
Estrutura de Banco de dados;
-
Conceitos de Variáveis, Tipos e Estruturas de Dados;
Em seguida, tivemos a parte prática no Ambiente de Desenvolvimento do Google COLAB, disponível aqui e também a seguir.
Por isso, nada referente à instalação e configuração do Python foi necessário.
Boas Vindas
Para dar boa sorte nesse processos e testar nosso ambiente de programação, vamos imprimir "Olá, Mundo!" na nossa tela.
print('Olá, Mundo!')
Google Colab
O Colaboratory ou “Colab” é um produto do Google Research, que permite que qualquer pessoa escreva e execute código Python arbitrário pelo navegador. Não requer nenhuma configuração e é sem custo financeiro.
- Seu Notebook
Você pode criar um notebook (livro de código) em Arquivos > Novo notebook para acompanhar o curso, testar seus códigos e fazer anotações OU fazer uma cópia desse em Arquivos> Salvar uma Cópia, assim você terá acesso à esse arquivo no seu drive...
- Upload de Arquivos
O Google Colab não consegue ler um arquivo que está no nosso computador, por isso é importante colocar esse arquivo aqui dentro do nosso notebook todas as vezes que formos utilizá-los. Esse arquivo será excluído automaticamente após o encerramento do ambiente de excecução.
Para isso, clicar na pasta no canto esquerdo "Arquivos". Em seguida, clicar no primeiro item para fazer upload do arquivo que está no computador, encontrá-lo e clicar em Abrir, conforme a imagem:
Importando Biblioteca
Neste primeiro momento, importaremos apenas a Biblioteca PANDAS (com o "apelido" de pd), que é utilizada para manipulação e análise de dados, escrita em Python.
Obs: Biblioteca pode ser entendido como um conjunto de funções/ vários códigos que já foram escritos e estão disponíveis para serem usadas por qualquer pessoa ao utilizar essa linguagem
import pandas as pd
Lendo a PNAD
Agora, utilizamos uma função da biblioteca pandas para importar nosso arquivo de dados para esse ambiente
- Caso estivessemos usando Microdados:
-
Para abrir o arquivo usei a função read_fwf, porque ela "lê uma tabela de linhas formatadas de largura fixa no DataFrame" (há varias funções p/ diferentes a extensão: excel, csv, stata)
-
Já que a base de dados original não possui o separador de colunas enquanto delimitador (exemplo: " ; |), usei a propriedade width (largura) da função read_fwf para colocar as infos da coluna "Tamanho" (disponibilizadas no arquivo Dicionário da PNAD). Ela tem que ser definida antes da função, para que consiga ser lida
-
O df original não possui um cabeçalho com o nome de cada coluna, por isso, defini o nome das colunas com o atributo .columns
width_df = [copiar e colar aqui a sequência numérica da coluna "Tamanho" presente no dicionário, exemplo: 4, 1, 2, 2, 2, 9, 7, ...]
df = pd.read_fwf('C:/Users/seucaminho/Arquivo.txt', header=None, dtype=str, widths=width_df)
df.columns = [copiar e colar aqui a sequência numérica da coluna "Código da variável" presente no dicionário, exemplo: 'Ano', 'Trimestre', 'Capital', 'RM_RIDE', 'UPA', ... ]
- Nosso arquivo (neste ambiente):
- Fazer Upload do Arquivo no google Colab conforme descrito
- Copiar Caminho deste arquivo
- Usar a função pd.read_excel ler nossa base de dados
df_pnad = pd.read_excel('/content/df_Minicurso.xlsx')
Criar uma cópia do dataframe original, para garantir a integridade caso algo aconteça: ˋdf=df_pnadˋ
DataFrame / Visualização dos dados: Tabelas
Para fins didáticos, aqui o DataFrame pode ser ententido apenas como o banco de dados em si.
Essa seção é dedicada para códigos que trazem uma visão mais ampla ou até mesmo individual de cada coluna, para analisarmos se ele foi lido corretamente, também tirar frequência das variáveis; fazer cruzamentos; agrupar colunas para melhorar a visualização....
Código para ver as 5 primeiras linhas do Dataframe (pode colocar numero no parenteses para aumentar a quantidade de linhas): df_pnad.head()
Quantidade de linhas: len(df)
Quantidade de linhas e colunas: df.shape
Nome das colunas: df.columns
Banco de dados, de acordo com ascendência (ou não) em determinada coluna
df.sort_values('V2010', ascending=True).head(20)
df.sort_values('V2010', ascending=False).head(20)
Visualização de duas (ou +) colunas, lado a lado
df[['V2007','V2010']]
df[['V2007','V2010']].head()
Ver a distribuição de acordo com determinada condição
df[df['V2005']==8][['UF',V2007','V2010']]
Cruzar 2 variáveis
pd.crosstab(index=df['V2007'], columns=df['V2010'])
Cruzar 3 variáveis
pd.crosstab(df['V2005'], [(df['V2007']), df['V2010']], rownames=['Condição'], colnames=['sexo', 'cor'])
Cruzar 3 variáveis de acordo com determinadas condições
pd.crosstab(df['V2005']=='8', [(df['V2007']=='01'), df['V2010']], rownames=['Condição'], colnames=['sexo', 'cor'])
Contagem de casos de determinada coluna de acordo com a categoria
df['V2007'].value_counts()
Agrupamento de casos por atributo e a média de outra caracteristica
df.groupby('V2007')['V2009'].mean()
Panorama geral da estatística descritiva do dataframe
df.describe()
Panorama geral estatística descritiva de uma coluna ou mais colunas
df_final[['V2009', 'VD4019']].describe()
Atribuição de rótulos
Aqui, veremos como alterar o nome das colunas e o rotulos dos dados. Vale ressaltar que quando um dado é do tipo string, este deve estar entre aspas (duplas ou simples), já se for numérico, tem que ser informado sem as aspas.
Relembrando nome das colunas: df_pnad.columns
Renomear Colunas
df=df.rename(columns={
'V1022': 'Situação_do_domicílio',
'V2005': 'Condição_no_domicílio',
'V2007': 'Sexo',
'V2009': 'Idade_do_morador',
'V2010': 'Cor_ou_raça',
'V3001': 'Sabe_ler_escrever',
'V3009A': 'Curso_mais_elevado_que_frequentou',
'V3014': 'Concluiu_este_curso',
'V4001': 'Trabalhou_remunerado_dinheiro',
'V4009': 'Quantos_trabalhos',
'S01021': 'Quantos_moradores_celular',
'S01022': 'Domicílio_telefone_fixo',
'S01029': 'Algum_morador_acesso_internet',
'S07009': 'Quem_foi_o_informante_deste_módulo',
'VD3004': 'Nível_de_instrução_mais_elevado_alcançado',
'VD3005': 'Anos_de_estudo',
'VD4001' : 'Condição_em_relação_à_força_de_trabalho',
'VD4002' : 'Condição_de_ocupação',
'VD4007' : 'Posição_na_ocupação_no_trabalho',
'VD4013' : 'Faixa_das_horas_trabalhadas',
'VD4019' : 'Rendimento_mensal',
'VD4031' : 'Horas_trabalhadas_semana',
'VD4036' : 'Faixa_horas_trabalhadas_semana',
'VDI5012' : 'Faixa_de_rendimento_domiciliar_per_capita'
})
Analisar a alteração dos nomes das colunas: df.columns
Renomear Atributos
df=df.replace({
'Situação_do_domicílio' : {1:'Urbana',2:'Rural'},
'Condição_no_domicílio' : {7 : 'Genro ou nora', 8 : 'Pai, mãe, padrasto ou madrasta', 9 : 'Sogro(a)'},
'Sexo' : {1:'Homem',2:'Mulher'},
'Cor_ou_raça' : {1: 'Branca', 2: 'Preta', 3: 'Amarela', 4: 'Parda', 5: 'Indígena', 9: 'Ignorado'},
'Sabe_ler_escrever' : {1:'Sim',2:'Não'},
'Curso_mais_elevado_que_frequentou' : {1: 'Creche (disponível apenas no questionário anual de educação)', 2: 'Pré-escola', 3: 'Classe de alfabetização - CA', 4: 'Alfabetização de jovens e adultos', 5: 'Antigo primário (elementar)', 6: 'Antigo ginásio (médio 1º ciclo)', 7: 'Regular do ensino fundamental ou do 1º grau', 8: 'Educação de jovens e adultos (EJA) ou supletivo do 1º grau', 9: 'Antigo científico, clássico, etc. (médio 2º ciclo)',10: 'Regular do ensino médio ou do 2º grau',11: 'Educação de jovens e adultos (EJA) ou supletivo do 2º grau',12: 'Superior - graduação',13: 'Especialização de nível superior',14: 'Mestrado',15: 'Doutorado'},
'Concluiu_este_curso' : {1:'Sim',2:'Não'},
'Trabalhou_remunerado_dinheiro' : {1:'Sim',2:'Não'},
'Quantos_trabalhos' : {1:'Um', 2:'Dois', 3 : 'Três ou mais'},
'Domicílio_telefone_fixo' : {1:'Sim',2:'Não'},
'Algum_morador_acesso_internet' : {1:'Sim',2:'Não'},
'Nível_de_instrução_mais_elevado_alcançado' : {1: 'Sem instrução e menos de 1 ano de estudo',2: 'Fundamental incompleto ou equivalente',3: 'Fundamental completo ou equivalente',4: 'Médio incompleto ou equivalente',5: 'Médio completo ou equivalente',6: 'Superior incompleto ou equivalente',7: 'Superior completo'},
'Condição_em_relação_à_força_de_trabalho': {1: 'Pessoas na força de trabalho',2: 'Pessoas fora da força de trabalho'},
'Condição_de_ocupação': {1: 'Pessoas ocupadas',2: 'Pessoas desocupadas'},
'Posição_na_ocupação_no_trabalho' : {1: 'Empregado (inclusive trabalhador doméstico)',2: 'Empregador',3: 'Conta própria',4: 'Trabalhador familiar auxiliar'},
'Faixa_horas_trabalhadas_semana' : {1: 'Até 14 horas', 2: '15 a 39 horas', 3: '40 a 44 horas',4: '45 a 48 horas', 5: '49 horas ou mais'},
'Faixa_de_rendimento_domiciliar_per_capita' : {1: 'Até ¼ salário mínimo', 2: 'Mais de ¼ até ½ salário mínimo', 3: 'Mais de ½ até 1 salário mínimo', 4: 'Mais de 1 até 2 salários mínimos',5: 'Mais de 2 até 3 salários mínimos',6: 'Mais de 3 até 5 salários mínimos',7: 'Mais de 5 salários mínimos',9: 'Ignorado'},
})
Analisar a alteração dos nomes dos atributos: df['Sexo'].value_counts()
Comando para ver o tipo de dados de cada coluna: df.dtypes
Estrutura condicional e filtros
Criar uma variável de filtro baseada em condições, por exemplo: Se na coluna X o valor for igual a 1 e na Y for igual a 2, a variável de nome Filtro marcará Verdade (True), se não, Falso.
Criar nova variável de acordo com outras instruções (Retorna true ou false)
df['Filtro'] = ((df['UF'] == 31) & (df['Condição_no_domicílio'] == 'Pai, mãe, padrasto ou madrasta') & ((df['Idade_do_morador'] >= 18) & (df['Idade_do_morador'] <= 80)))
Verificar se a nova coluna consta na lista: df.columns
Ver a distribuição da Filtro, por coluna
df[df['Filtro']==True][['Filtro','UF','Condição_no_domicílio', 'Idade_do_morador']]
Fazer Agrupamento utilizando o método .loc. É mais utilizado para definir rapidamente instruções lógicas simples em poucas linhas quando a condição tiver um resultado binário (tanto verdadeiro quanto falso).
df.loc[(df['Idade_do_morador'] >=18 ) & (df['Idade_do_morador'] <=20), 'Faixa_Etaria'] = '18 a 20 anos'
df.loc[(df['Idade_do_morador'] >=21 ) & (df['Idade_do_morador'] <=30), 'Faixa_Etaria'] = '21 a 30 anos'
df.loc[(df['Idade_do_morador'] >=31 ) & (df['Idade_do_morador'] <=40), 'Faixa_Etaria'] = '31 a 40 anos'
df.loc[(df['Idade_do_morador'] >=41 ) & (df['Idade_do_morador'] <=50), 'Faixa_Etaria'] = '41 a 50 anos'
df.loc[(df['Idade_do_morador'] >=51 ) & (df['Idade_do_morador'] <=60), 'Faixa_Etaria'] = '51 a 60 anos'
df.loc[df['Idade_do_morador'] >= 61, 'Faixa_Etaria'] = '61 anos ou mais'
Ver a distribuição da coluna Filtro em relação às outras coluna
df[df['Filtro']==True][['Idade_do_morador','Faixa_Etaria']]
Frequência/ Contagem da Coluna com rótulos ascendentes
df['Faixa_Etaria'].value_counts(ascending=True)
Divisão de banco de dados
"Criar" um novo banco de dados baseado na coluna Filtro
Filtrar DataFrame com base em condição da coluna e salvar em um nome DataFrame
df_filter = df.loc[df['Filtro'] == True]
Analisar o shape do banco: df_filter.shape
Limpeza da base de dados
Limpar a base de dados consiste em apagar colunas ou casos não desejados.
Apagar Colunas e salvar outro DataFrame
df_filter1 = df_filter.drop(['Ano', 'Trimestre', 'UF', 'Capital', 'RM_RIDE',
'Sabe_ler_escrever', 'Curso_mais_elevado_que_frequentou', 'Concluiu_este_curso',
'Domicílio_telefone_fixo','Quem_foi_o_informante_deste_módulo',
'Anos_de_estudo', 'Faixa_horas_trabalhadas_semana'], axis=1)
Escolher Colunas e salvá-las em outro DataFrame
df_filter2=df_filter[['Ano', 'Trimestre', 'UF', 'Capital', 'RM_RIDE',
'Sabe_ler_escrever', 'Curso_mais_elevado_que_frequentou', 'Concluiu_este_curso',
'Domicílio_telefone_fixo','Quem_foi_o_informante_deste_módulo',
'Anos_de_estudo', 'Faixa_horas_trabalhadas_semana']]
Mostrar missing values no banco de dados (Se na/null = True) : df_filter1.isna()
Loop para mostrar a quantidade de null por coluna
for i in df_filter1:
print(i,df_filter1[i].isna().sum())
Trocar missings values por outro numero
df_filter1['Quantos_trabalhos'] = df_filter1['Quantos_trabalhos'].fillna(0)
Fazer cópia do DataFrame para fazer teste de apagar linhas: dfteste = df_filter1
Apagar uma linha de acordo com vazio na coluna
dfteste = dfteste[dfteste['Rendimento_mensal'].notna()]
Juntar bases de dados
Juntar / Agrupar bancos de dados, funções disponíveis: .concat(); .join() e .merge()
Juntar Bancos Filter 1 e 2 baseado na coluna index (comum entre os dois)
df_concat = pd.concat([df_filter1, df_filter2], axis=1)
Analisar shpe do banco: df_concat.shape
Exportação de base de dados
A qualquer momento é possível salvar/ exportar o banco de dados para uso posterior e em praticamente qualquer formato/ extensão (excel, csv, txt). O que muda é a função do pandas utilizada e quais atributos são possíveis de definir.
Definir colunas a ordem das colunas e quais ficam
df_final=df_filter1[['Sexo', 'Idade_do_morador', 'Faixa_Etaria', 'Cor_ou_raça',
'Faixa_de_rendimento_domiciliar_per_capita','Situação_do_domicílio',
'Quantos_moradores_celular', 'Algum_morador_acesso_internet',
'Nível_de_instrução_mais_elevado_alcançado',
'Trabalhou_remunerado_dinheiro','Quantos_trabalhos',
'Condição_em_relação_à_força_de_trabalho', 'Condição_de_ocupação',
'Posição_na_ocupação_no_trabalho', 'Faixa_das_horas_trabalhadas',
'Rendimento_mensal', 'Horas_trabalhadas_semana']]
Exportar Base de dados em tabela do excel JUPYTER A diferença é que passamos o caminho da pasta no nosso computador
df_filter.to_excel('C:/[caminho]/[arquivo].xlsx', index=False, sheet_name='base')
Exportar Base de dados em tabela do excel COLAB Aqui, só passamos o nome do arquivo.
files.download('df_FINAL_Minicurso.xlsx', index=False, sheet_name='base')
Visualização dos dados: Gráficos
Para gerar gráficos, é necessário importar as bibliotecas: Seaborn e Matplotlib. Vale ressaltar que é possível ajustar praticamente todos os aspectos visuais conforme consta nas respectivas documentações.
Obs: Para salvar os gráficos gerados como imagem (da extensão que preferir), o trecho de código é: fig.savefig('Nome do Arquivo.jpg'). Após esse processo, essa figura constará nos arquivos do colab e então basta clicar nos três pontinhos laterais e Fazer Download.
Importar bibliotecas
import matplotlib.pyplot as plt
import seaborn as sns
Relembrar colunas: df_final.columns
Plotar histograma do Matplotlib SEM formatação da distribuição por Sexo
plt.hist(df_final['Sexo'], 3)
plt.show()
Plotar histograma do Matplotlib COM formatação da distribuição por Sexo e salvá-lo
plt.title('Distribuição por Sexo', fontsize=12)
plt.xlabel('Sexo', fontsize=10)
plt.ylabel('Frequência Absoluta', fontsize=10)
plt.tick_params(labelsize=8)
plt.hist(df_final['Sexo'], 3, rwidth=0.9, color='#6fa8c7', alpha=0.7, edgecolor='black')
plt.savefig("Imagem5 - Distribuição Sexo.jpg")
plt.show()
Plotar Normal do Seaborn SEM formatação da distribuição por Idade
sns.distplot(df_final['Idade_do_morador'])
Plotar histograma do Seaborn SEM formatação da distribuição por Sexo e salvá-lo
sns.histplot(df_final['Sexo'])
fig = hist.get_figure()
fig.savefig('Imagem2 - Distribuição Sexo.png')
Plotar barplot do Seaborn COM formatação da distribuição de Cor/Raça por Sexo e salvá-lo (para as cores: usar atributo palette ou comando sns.set_theme(style="darkgrid")
brplt = sns.barplot(x="Cor_ou_raça", y="Idade_do_morador", data=df_final, palette="Greens_d");
fig = brplt.get_figure()
fig.savefig('Imagem2 - Distribuição Sexo.png')
Ver o tipo dos dados de cada coluna para avaliar adequação do gráfico: df_pnad.dtypes
Plotar boxplot do Seaborn COM formatação da distribuição de Condição de ocupação por Idade e salvá-lo
sns.set_theme(style="darkgrid")
boxplt = sns.boxplot(x ='Condição_de_ocupação', y ='Idade_do_morador', data = df)
fig = boxplt.get_figure()
fig.savefig('Imagem5 - Horas Trabalhadas vs Rendimento Mensal Sexo.jpg')
plt.show(boxplt)
Plotar scatterplot do Seaborn COM formatação da Distribuição de Horas trabalhadas por Rendimento Mensal e salvá-lo
scatt = sns.scatterplot(data=df_final, x='Horas_trabalhadas_semana', y='Rendimento_mensal', hue='Sexo', palette=['black', 'red'])
fig = scatt.get_figure()
fig.savefig('Imagem5 - Horas Trabalhadas vs Rendimento Mensal Sexo.jpg')
plt.show(scatt)
Plotar scatterplot do Seaborn COM formatação de elementos individuais da Distribuição de Horas trabalhadas por Rendimento Mensal e salvá-lo
scatt = sns.scatterplot(data=df_final, x='Horas_trabalhadas_semana', y='Rendimento_mensal', hue='Sexo', palette=['black', 'red'])
plt.title('Distribuição de Horas trabalhadas por Rendimento Mensal', fontsize=12)
plt.xlabel('Horas trabalhadas da semana', fontsize=10)
plt.ylabel('Rendimento Mensal', fontsize=10)
plt.tick_params(axis='both', which='major', labelsize=14)
fig = scatt.get_figure()
fig.savefig('Imagem6 - Horas Trabalhadas vs Rendimento Mensal Sexo.jpg')
plt.show(scatt)
Relatório
Já vimos como salvar os gráficos como imagem, agora, para salvar todo esse notebook (de extensão .ipynb), incluindo tópicos, textos, códigos e outputs (TUDO que aparece nele) em PDF, seguir o seguinte passo:
-
Clicar em Arquivos > Fazer Download > Fazer o download do .ipynb
-
Importar/ Fazer Upload desse arquivo para esse ambiente (conforme fizemos com a base de dados)
-
Rodar os trechos de código a seguir:
Fazer instalação de um pacote chamado Texlive, necessário nesse processo (duração de 60 segundos)
!sudo apt-get install texlive-xetex texlive-fonts-recommended texlive-plain-generic
Copiar o caminho do notebook que importamos (nos arquivos da barra lateral> clicar nos três pontinhos > copiar caminho), e colocar no espaço indicado CAMINHO, como exemplo: /content/Minicurso_Python.ipynb
!jupyter nbconvert --to pdf CAMINHO
Finalização
Há diversas outras possibilidades de se chegar ao mesmo resultado, desde mais simples até as mais complexas e também outras linguagens podem ser utilizadas. Como exposto na introdução, o objeto deste minicurso foi de fazer um apanhado geral de algumas possibilidades de manipulação de banco de dados que proporcionam dados mais legíveis e de fácil análise. Espero que a missão tenha sido cumprida.
Se gostou desse conteúdo, faça um Fork para deixar guardado no seu repositório do GitHub e deixe uma estrelinha, pra ele brilhar hehe
Contato:
Presente nas mídias como Angélica Bicego