Abastecimento público da Região Metropolitana de São Paulo

Trabalho final para o curso Python para usuários de R, da Curso-R

Análise exploratória
Estudos
Quarto
Python
Pandas
Seaborn
Altair
Autor

Beatriz Milz

Data de Publicação

6 de janeiro de 2023

Esse texto é o trabalho final para o curso Python para usuários de R, da Curso-R. O objetivo do trabalho é praticar as ferramentas apresentadas no curso, como usar as bibliotecas pandas e seaborn.

Introdução

Explorando dados sobre os mananciais que abastecem a Região Metropolitana de São Paulo. Estes dados são produzidos pela SABESP, e aqui utilizei os dados do pacote em R Mananciais, que disponibiliza a base dos dados atualizada diariamente em CSV.

Objetivos

Responder as seguintes perguntas:

  • Quais são os sistemas presentes na base Mananciais?

  • Qual é o sistema com a menor volume armazenado atualmente?

  • Como o volume armazenado variou ao longo de 2022?

Setup

Código
# descobrindo a versao do python
from platform import python_version
versao_python = python_version()

# escrevendo um parágrafo que apresente o valor guardado na variável versao_python

from IPython.display import display, Markdown

display(Markdown("""
Este trabalho foi desenvolvido em um computador com sistema Mac OS,
com a versão do Python {versao_python}, utilizando a IDE VS Code,
o software Quarto e a extensão do Quarto para o VS Code.
""".format(versao_python = versao_python)))

Este trabalho foi desenvolvido em um computador com sistema Mac OS, com a versão do Python 3.10.4, utilizando a IDE VS Code, o software Quarto e a extensão do Quarto para o VS Code.

Preparando o ambiente

Antes de iniciar a explorar os dados, foi preciso preparar o ambiente. Primeiro criei um virtual environment para a instalação dos pacotes em Python utilizando o seguinte código no terminal:

Código
# criando ambiente virtual chamado env
python3 -m venv env

Para utilizar o virtual environment criado, utilizei o seguinte código no terminal:

Código
# ativando o ambiente virtual criado
source env/bin/activate

Foi necessário também atualizar o pip (usado para instalar as bibliotecas), e instalar o jupyter e os pacotes:

Código
# Para instalar o jupyter
pip install jupyter


# atualizar o pip
pip install --upgrade pip


# Para instalar as bibliotecas pandas e seaborn:
pip install pandas
pip install seaborn

# Para instalar a biblioteca altair e os dados de exemplo:
pip install altair vega_datasets

Carregar bibliotecas

As bibliotecas utilizadas foram:

Código
# importar as bibliotecas usadas
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import altair as alt # importar o altair

Importar dados

Código
# salvando o link onde a base está disponível
url_mananciais = 'https://raw.githubusercontent.com/beatrizmilz/mananciais/master/inst/extdata/mananciais.csv'

# lendo o CSV, o separador é ;
mananciais = pd.read_csv(url_mananciais,  sep = ";")

Limpar/organizar os dados

Quais são as colunas disponíveis?

Código
# descobrindo as colunas e seus tipos
mananciais.info(show_counts = False)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 52250 entries, 0 to 52249
Data columns (total 8 columns):
 #   Column               Dtype 
---  ------               ----- 
 0   data                 object
 1   sistema              object
 2   volume_porcentagem   object
 3   volume_variacao      object
 4   volume_operacional   object
 5   pluviometria_dia     object
 6   pluviometria_mensal  object
 7   pluviometria_hist    object
dtypes: object(8)
memory usage: 3.2+ MB

É necessário arrumar o tipo de algumas colunas (algumas estão como texto mas deveriam ser números), e criar novas colunas que podem ser úteis posteriormente (ano, mês, data arredondada para o início do mês, etc).

Código
# funcao para converter em numero
def converter_em_numero(serie):
   x = pd.to_numeric(serie.str.replace(',', '.')) 
   return(x)


# exemplo de uso!
# converter_em_numero(mananciais['volume_porcentagem'])
Código
mananciais_arrumado = mananciais.assign(
    # convertendo a coluna data em tipo datetime
    data = pd.to_datetime(mananciais['data']),
    # daqui em diante: convertendo os valores das colunas em número
    volume_porcentagem = lambda x: converter_em_numero(x['volume_porcentagem']),
    volume_variacao = lambda x: converter_em_numero(x['volume_variacao']),
    volume_operacional = lambda x: converter_em_numero(x['volume_operacional']),
    pluviometria_dia = lambda x: converter_em_numero(x['pluviometria_dia']),
    pluviometria_mensal = lambda x: converter_em_numero(x['pluviometria_mensal']),
    pluviometria_hist = lambda x: converter_em_numero(x['pluviometria_hist'])
)
Código
# criando a coluna do mês
mananciais_arrumado['data_mes'] = pd.DatetimeIndex(mananciais_arrumado['data']).month

# criando a coluna do ano
mananciais_arrumado['data_ano'] = pd.DatetimeIndex(mananciais_arrumado['data']).year

# cria a coluna do mes/ano
mananciais_arrumado['data_mes_ano'] = mananciais_arrumado['data'].apply(lambda x : x.replace(day=1))

Agora podemos conferir as colunas e seus tipos:

Código
mananciais_arrumado.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 52250 entries, 0 to 52249
Data columns (total 11 columns):
 #   Column               Non-Null Count  Dtype         
---  ------               --------------  -----         
 0   data                 52250 non-null  datetime64[ns]
 1   sistema              52250 non-null  object        
 2   volume_porcentagem   52250 non-null  float64       
 3   volume_variacao      52250 non-null  float64       
 4   volume_operacional   52250 non-null  float64       
 5   pluviometria_dia     52250 non-null  float64       
 6   pluviometria_mensal  52250 non-null  float64       
 7   pluviometria_hist    52005 non-null  float64       
 8   data_mes             52250 non-null  int64         
 9   data_ano             52250 non-null  int64         
 10  data_mes_ano         52250 non-null  datetime64[ns]
dtypes: datetime64[ns](2), float64(6), int64(2), object(1)
memory usage: 4.4+ MB

Análise exploratória

Quais são os sistemas presentes na base Mananciais?

Código
array_mananciais = mananciais_arrumado['sistema'].unique()

lista_mananciais = array_mananciais.tolist()

texto_mananciais = ", ".join(lista_mananciais[:-1])

ultimo_sistema = lista_mananciais[-1]

display(Markdown("""
Os sistemas presentes na base são: {texto_mananciais} e {ultimo_sistema}.
""".format(texto_mananciais = texto_mananciais, ultimo_sistema = ultimo_sistema)))

Os sistemas presentes na base são: Cantareira, Alto Tietê, Guarapiranga, Cotia, Rio Grande, Rio Claro e São Lourenço.

Qual é o sistema com a menor volume armazenado atualmente?

Código
# filtrando os dados com a data mais
sistemas_atualmente = mananciais_arrumado.query("data == data.max()")

# deixando a tabela mais apresentável
# arredondando a coluna volume operacional
sistemas_atualmente["Volume operacional"] = sistemas_atualmente["volume_operacional"].round(1)

# criando uma função para adicionar a porcentagem
def adicionar_porcentagem(x):
    return f"{x} %"

# aplicando a função de adicionar porcentagem
sistemas_atualmente["Volume"] = sistemas_atualmente["volume_porcentagem"].apply(adicionar_porcentagem)

# renomeando coluna
sistemas_atualmente["Sistema"] = sistemas_atualmente["sistema"]

A seguir estão apresentados os sistemas ordenados por volume operacional (quantidade absoluta):

Código
# ordenando de forma crescente segundo o Volume operacional e selecionando as colunas desejadas
(
    sistemas_atualmente.
    filter(["Sistema", "Volume", "Volume operacional"]).
    sort_values("Volume operacional", ascending=True)
)
Sistema Volume Volume operacional
5 Rio Claro 44.7 % 6.1
3 Cotia 58.1 % 9.6
6 São Lourenço 93.6 % 83.1
4 Rio Grande 104.0 % 116.6
2 Guarapiranga 75.8 % 129.7
1 Alto Tietê 50.2 % 281.1
0 Cantareira 45.6 % 447.9

E os sistemas ordenados por volume percentual (quantidade relativa):

Código
# ordenando de forma crescente segundo o volume percentual e selecionando as colunas desejadas
(
    sistemas_atualmente.
    sort_values("volume_porcentagem", ascending=True).
     filter(["Sistema", "Volume", "Volume operacional"])
)
Sistema Volume Volume operacional
5 Rio Claro 44.7 % 6.1
0 Cantareira 45.6 % 447.9
1 Alto Tietê 50.2 % 281.1
3 Cotia 58.1 % 9.6
2 Guarapiranga 75.8 % 129.7
6 São Lourenço 93.6 % 83.1
4 Rio Grande 104.0 % 116.6

O sistema com o menor volume porcentual armazenado é o Cantareira, um sistema de reservatórios muito importante para o abastecimento público da Região Metropolitana de São Paulo.

Como o volume armazenado variou ao longo do tempo?

Para criar uma visualização que apresente o volume armazenado ao longo do tempo, primeiramente é necessário agrupar por sistema e mês/ano, e então calcular a média do valor referente ao volume. Isso nos dá a média de volume armazenado por sistema e mês/ano.

Código
mananciais_sumarizado = (
    mananciais_arrumado.
    groupby(["sistema", "data_mes_ano"], as_index = False).
    agg(media_porcentagem = ("volume_porcentagem", "mean"))
    )
mananciais_sumarizado

mananciais_sumarizado.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1722 entries, 0 to 1721
Data columns (total 3 columns):
 #   Column             Non-Null Count  Dtype         
---  ------             --------------  -----         
 0   sistema            1722 non-null   object        
 1   data_mes_ano       1722 non-null   datetime64[ns]
 2   media_porcentagem  1722 non-null   float64       
dtypes: datetime64[ns](1), float64(1), object(1)
memory usage: 40.5+ KB

Agora é possível apresentar em gráficos:

Código
alt.Chart(mananciais_sumarizado).mark_line().encode(
    x = alt.X('data_mes_ano', title = "Mês e Ano"), 
    y = alt.Y('media_porcentagem', title = 'Volume armazenado (%)'),
    color = 'sistema'
)
Código
grafico = sns.FacetGrid(mananciais_sumarizado, col = "sistema", col_wrap = 2)
grafico.map_dataframe(sns.lineplot, x = "data_mes_ano", y = "media_porcentagem", hue =  "sistema")

grafico 
<seaborn.axisgrid.FacetGrid at 0x7f55787ff700>

Como o volume do sistema Cantareira variou ao longo de 2022?

Código
# filtra dados do sistema cantareira
dados_cantareira = mananciais_sumarizado.query("sistema == 'Cantareira'")

# cria um array de verdadeiro ou falso, sendo verdadeiro os valores de 2022
ano_2022 = dados_cantareira.data_mes_ano >= np.datetime64('2022-01-01')

# filtra os dados da cantareira com o array criado acima
dados_cantareira_2022 = dados_cantareira[ano_2022]
Código
alt.Chart(dados_cantareira_2022).mark_line().encode(
    x = alt.X('data_mes_ano', title = "Mês e Ano"), 
    y = alt.Y('media_porcentagem', title = 'Volume armazenado (%)')
    )
Código
sns.lineplot(x = "data_mes_ano", y = "media_porcentagem", data = dados_cantareira_2022)
plt.show()