Módulos Essenciais de Python

Luciano Magalhães Luciano Magalhães   |  schedule Agosto, 2024  |   view_object_track Ciência de Dados


A ciência de dados abrange um conjunto diversificado de técnicas e ferramentas que permitem a extração de conhecimento e insights valiosos a partir de dados. Python, com sua vasta coleção de bibliotecas, é uma escolha popular para cientistas de dados. Além dos módulos comuns como NumPy, Pandas, Matplotlib e Scikit-learn, existem outros módulos que podem ser utilizados para análises mais avançadas e específicas.

Neste artigo apresento alguns módulos adicionais para ciência de dados utilizando o conjunto de dados House Prices do Kaggle. Esses módulos incluem:

Dask: Para manipulação e análise de dados em grande escala.
XGBoost: Para modelos de gradient boosting.
SHAP: Para interpretar modelos de machine learning.
Plotly: Para visualizações interativas.
TensorFlow: Para deep learning.

In [1]:
# suprimir avisos (warnings)
import warnings
warnings.filterwarnings("ignore")

1. Dask: Manipulação e Análise de Dados em Grande Escala

Quando lidamos com grandes volumes de dados, o Pandas pode não dar conta do recado, especialmente quando a memória é limitada. É aqui que o Dask entra em cena. Imagine dividir seu conjunto de dados em blocos menores e trabalhar com eles como se fosse o Pandas, mas com uma vantagem: o Dask distribui esse trabalho em vários núcleos do seu processador, ou até em diferentes máquinas. Isso significa que você pode processar grandes bases de dados sem se preocupar com a falta de memória.

Exemplo:

No exemplo abaixo, usamos o Dask para carregar e analisar um conjunto de dados de forma eficiente, mostrando como ele calcula estatísticas descritivas rapidamente, mesmo com grandes volumes de informação:

In [2]:
import dask.dataframe as dd

# URL do conjunto de dados
url = "https://raw.githubusercontent.com/ageron/handson-ml/master/datasets/housing/housing.csv"

# Carregando o conjunto de dados usando Dask
dados_casas_dask = dd.read_csv(url)

# Calculando estatísticas descritivas
descricao_dask = dados_casas_dask.describe()

# executa operações de forma eficiente em grandes conjuntos de dados
descricao_dask_computed = descricao_dask.compute()

# Exibindo o resultado das estatísticas descritivas
print(descricao_dask_computed)
          longitude      latitude  housing_median_age   total_rooms  \
count  20640.000000  20640.000000        20640.000000  20640.000000   
mean    -119.569704     35.631861           28.639486   2635.763081   
std        2.003532      2.135952           12.585558   2181.615252   
min     -124.350000     32.540000            1.000000      2.000000   
25%     -121.800000     33.930000           18.000000   1447.750000   
50%     -118.490000     34.260000           29.000000   2127.000000   
75%     -118.010000     37.710000           37.000000   3148.000000   
max     -114.310000     41.950000           52.000000  39320.000000   

       total_bedrooms    population    households  median_income  \
count    20433.000000  20640.000000  20640.000000   20640.000000   
mean       537.870553   1425.476744    499.539680       3.870671   
std        421.385070   1132.462122    382.329753       1.899822   
min          1.000000      3.000000      1.000000       0.499900   
25%        296.000000    787.000000    280.000000       2.563400   
50%        435.000000   1166.000000    409.000000       3.534800   
75%        647.000000   1725.000000    605.000000       4.743250   
max       6445.000000  35682.000000   6082.000000      15.000100   

       median_house_value  
count        20640.000000  
mean        206855.816909  
std         115395.615874  
min          14999.000000  
25%         119600.000000  
50%         179700.000000  
75%         264725.000000  
max         500001.000000  

Utilizando o método compute()em Dask, as operações que foram configuradas de forma paralela são executadas e o resultado é coletado. Isso difere do Pandas, onde todas as operações são realizadas de forma sequencial e em um único núcleo. O Dask, portanto, é ideal para cenários em que o tempo de processamento e a capacidade de memória são críticos, como em grandes bases de dados corporativas.

Benefícios Adicionais:

Dask também é altamente compatível com outras bibliotecas do ecossistema Python, como NumPy e Scikit-learn, facilitando a integração em pipelines de dados já existentes. Além disso, sua capacidade de escalar de um laptop para um cluster distribuído sem alterar o código subjacente o torna uma ferramenta flexível e poderosa para cientistas de dados.

Ao usar o Dask, você aproveita melhor os recursos do seu computador, garantindo que as análises sejam feitas de maneira eficiente, sem comprometer a performance, mesmo com grandes quantidades de dados.


2. XGBoost: Modelos de Gradient Boosting¶

Gradient Boosting é uma técnica que combina o aprendizado sequencial de modelos fracos, geralmente árvores de decisão, para construir um modelo forte. No XGBoost, cada árvore é treinada para corrigir os erros do conjunto anterior, e as previsões são ajustadas iterativamente. A importância dessa abordagem é que ela minimiza o erro ao longo das iterações, resultando em um modelo final que é uma combinação ponderada de todas as árvores. Isso o torna altamente eficaz para tarefas como regressão e classificação, especialmente em conjuntos de dados com ruído e outliers.

In [3]:
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import pandas as pd

# Carregando o conjunto de dados usando pandas
dados_casas = pd.read_csv(url)

# Preparando os dados
X = dados_casas[["total_rooms"]]
y = dados_casas["median_house_value"]
X_treino, X_teste, y_treino, y_teste = train_test_split(X, y, test_size=0.3, random_state=42)

# Treinando um modelo XGBoost
modelo_xgb = xgb.XGBRegressor(objective ='reg:squarederror', n_estimators=100)
modelo_xgb.fit(X_treino, y_treino)

# Faz previsões
y_pred_xgb = modelo_xgb.predict(X_teste)

# Avaliando o modelo
rmse = mean_squared_error(y_teste, y_pred_xgb, squared=False)
print("RMSE do Modelo XGBoost:", rmse)
RMSE do Modelo XGBoost: 113329.45682157896

Gradient Boosting é uma técnica utilizada para melhorar a precisão de modelos preditivos combinando vários modelos simples, como árvores de decisão. No XGBoost, cada árvore é treinada para corrigir os erros das previsões anteriores, resultando em um modelo final que é uma soma ponderada de todas as árvores. Essa metodologia é eficaz para lidar com dados complexos, onde ruídos e outliers podem dificultar a precisão das previsões.

Ao aplicar o XGBoost, é fundamental ajustar os hiperparâmetros, como a profundidade das árvores (max_depth), a taxa de aprendizado (learning_rate), e o número de iterações (n_estimators). Esses ajustes garantem que o modelo não apenas capture as nuances dos dados, mas também evite o overfitting, mantendo a capacidade de generalização para novos dados.

No código apresentado, o modelo inicial alcançou um RMSE de aproximadamente 113329.46, sugerindo uma boa precisão inicial. No entanto, há espaço para otimização, e no próximo passo, utilizaremos o GridSearchCV para refinar esses hiperparâmetros e melhorar ainda mais o desempenho do modelo.

In [4]:
from sklearn.model_selection import GridSearchCV

# Defini os hiperparâmetros que serão otimizados
param_grid = {
    'learning_rate': [0.01, 0.1, 0.2],# Taxa de aprendizado, controla o quanto cada nova árvore contribui para corrigir os erros das árvores anteriores
    'max_depth': [3, 5, 7],           # Profundidade máxima das árvores, controlando a complexidade do modelo
    'subsample': [0.6, 0.8, 1.0],     # Fração das amostras usadas para treinar cada árvore. Usar menos de 1.0 (100%) ajuda a prevenir overfitting
    'n_estimators': [100, 200, 300]   # Número de árvores a serem construídas no modelo, controlando o número de iterações
}

# Instancia o modelo XGBoost
modelo_xgb = xgb.XGBRegressor(objective='reg:squarederror', random_state=42)

# Configura o GridSearchCV / validação cruzada com 5 divisões, e critério de avaliação será o erro quadrático médio negativo - scoring
grid_search = GridSearchCV(estimator=modelo_xgb, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error', verbose=1)

# Executa a busca pelos melhores hiperparâmetros
grid_search.fit(X_treino, y_treino)

# Exibi os melhores parâmetros encontrados
print("Melhores Hiperparâmetros:", grid_search.best_params_)

# Treina o modelo com os melhores parâmetros
modelo_otimizado = grid_search.best_estimator_

# Faz previsões e avalia o modelo otimizado
y_pred_otimizado = modelo_otimizado.predict(X_teste)
rmse_otimizado = mean_squared_error(y_teste, y_pred_otimizado, squared=False)
print("RMSE do Modelo Otimizado:", rmse_otimizado)
Fitting 5 folds for each of 81 candidates, totalling 405 fits
Melhores Hiperparâmetros: {'learning_rate': 0.01, 'max_depth': 3, 'n_estimators': 200, 'subsample': 0.6}
RMSE do Modelo Otimizado: 112555.30074019264

Após a execução do GridSearchCV, o modelo XGBoost foi ajustado com os melhores hiperparâmetros encontrados: learning_rate: 0.01, max_depth: 3, n_estimators: 200, subsample: 0.6. Esses ajustes foram fundamentais para melhorar a performance do modelo, resultando em um RMSE de 112555.30. Esse processo de otimização é essencial para garantir previsões mais precisas, refinando o modelo para melhor atender às especificidades do conjunto de dados e das tarefas de previsão.


3. SHAP: Interpretação de Modelos de Machine Learning¶

SHAP (SHapley Additive exPlanations) é uma biblioteca que fornece explicações interpretáveis para os resultados de modelos de machine learning.

In [5]:
import shap

# Criaando um objeto Explainer
explainer = shap.Explainer(modelo_otimizado, X_treino)
shap_values = explainer(X_teste)

# Visualizando os valores SHAP
shap.summary_plot(shap_values, X_teste)
100%|===================| 6184/6192 [00:11<00:00]       
No description has been provided for this image

SHAP (SHapley Additive exPlanations) é uma poderosa ferramenta que facilita a interpretação de modelos complexos de machine learning. Em nosso exemplo, utilizamos SHAP paraanalisar o modelo XGBoost, e os valores SHAP nos ajudam a entender a contribuição de cada variável para as previsões do modelo.

No gráfico de dispersão SHAP, usando o modelo otimisado, cada ponto representa uma previsão individual. A cor dos pontos indica o valor da variável total_rooms, variando de azul (valores baixos) a rosa (valores altos). A posição no eixo x revela o impacto dessa variável nas previsões: pontos à direita (impacto positivo) indicam que valores mais altos de total_rooms tendem a aumentar a previsão do valor da casa, enquanto pontos à esquerda (impacto negativo) sugerem o contrário.

Essa visualização é crucial para entender como o modelo XGBoost está utilizando a variável total_rooms para fazer previsões, além de permitir a identificação de padrões ou possíveis outliers que podem estar influenciando as previsões de maneira inesperada.


4. Plotly: Visualizações Interativas¶

In [6]:
import plotly.express as px

dados_casas = pd.read_csv(url)

# Criando um gráfico de dispersão interativo
fig = px.scatter(dados_casas, 
                 x="total_rooms",  # Coluna com o número total de cômodos
                 y="median_house_value",  # Coluna com o valor mediano da casa
                 title="Número de Cômodos (Agregado) vs. Valor Mediano da Casa",
                 hover_data={'total_rooms': True, 'median_house_value': ':.1f'})

# Atualizando o layout do gráfico
fig.update_layout(
    xaxis_title="Número Total de Cômodos (Agregado por Região)",  # Ajuste do rótulo no eixo X
    yaxis_title="Valor Mediano da Casa",  # Ajuste do rótulo no eixo Y
    title_x=0.5  # Centraliza o título
)

# Exibir o gráfico
fig.show()

O gráfico interativo acima mostra a relação entre o número total de cômodos agregados por região (total_rooms) e o valor mediano das casas (median_house_value). Ele revela uma correlação positiva entre o número de cômodos na região e o valor das propriedades, embora fatores como localização e conservação possam influenciar o preço. A interatividade permite explorar detalhes específicos, facilitando a identificação de padrões ocultos nos dados.


5. TensorFlow: Deep Learning¶

In [7]:
import tensorflow as tfqq
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense


# Carregando o conjunto de dados usando pandas
dados_casas = pd.read_csv(url)

# Preparando os dados
X = dados_casas[["total_rooms"]].values
y = dados_casas["median_house_value"].values

# Definindo a arquitetura do modelo
modelo_tf = Sequential([
    Dense(10, activation='relu', input_shape=(X.shape[1],)),
    Dense(1)
])

# Compilando o modelo
modelo_tf.compile(optimizer='adam', loss='mse')

# Treinando o modelo
modelo_tf.fit(X, y, epochs=10, batch_size=32)

# Fazendo previsões
y_pred_tf = modelo_tf.predict(X)
d_tf = modelo_tf.predict(X)
Epoch 1/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 5s 1ms/step - loss: 56108036096.0000  
Epoch 2/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 931us/step - loss: 54081626112.0000
Epoch 3/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 900us/step - loss: 46221725696.0000
Epoch 4/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 811us/step - loss: 37783916544.0000
Epoch 5/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 780us/step - loss: 31379750912.0000
Epoch 6/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 817us/step - loss: 28132274176.0000
Epoch 7/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 820us/step - loss: 27776878592.0000
Epoch 8/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 898us/step - loss: 27917871104.0000
Epoch 9/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 812us/step - loss: 27391543296.0000
Epoch 10/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 798us/step - loss: 27503605760.0000
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 761us/step
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 768us/step

Neste exemplo, utilizamos tensorflow.keras para construir e treinar uma rede neural simples com uma camada densa (Dense). O modelo foi treinado para prever os preços das casas com base na variável total_rooms, que reflete o número total de cômodos agregados por região. Durante o treinamento, a rede neural ajusta os pesos das conexões para minimizar a função de perda (loss), que, neste caso, foi definida como o erro quadrático médio (mse).

Após o treinamento, usamos o modelo para fazer previsões sobre os dados. No entanto, uma rede neural simples como essa pode ser propensa ao overfitting, especialmente se a arquitetura não for devidamente regularizada ou se o conjunto de dados for limitado.

Após o treinamento, usamos o modelo para fazer previsões sobre os dados. No entanto, uma rede neural simples como essa pode ser propensa ao overfitting, especialmente se a arquitetura não for devidamente regularizada ou se o conjunto de dados for limitado.

A seguir, demonstramos como modificar o modelo original para incluir a camada de Dropout, que ajudará a prevenir o overfitting:

In [8]:
from tensorflow.keras.layers import Dropout

# Modificação da arquitetura do modelo para incluir Dropout
modelo_tf = Sequential([
    Dense(10, activation='relu', input_shape=(X.shape[1],)),
    Dropout(0.2),  # 20% das unidades serão desligadas durante o treinamento
    Dense(1)
])

# Compilando o modelo
modelo_tf.compile(optimizer='adam', loss='mse')

# Treinar o modelo com a nova arquitetura
modelo_tf.fit(X, y, epochs=10, batch_size=32)
Epoch 1/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 2s 855us/step - loss: 55228936192.0000
Epoch 2/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 825us/step - loss: 47544848384.0000
Epoch 3/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 934us/step - loss: 34778632192.0000
Epoch 4/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 887us/step - loss: 29066162176.0000
Epoch 5/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 914us/step - loss: 27990056960.0000
Epoch 6/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 893us/step - loss: 28555808768.0000
Epoch 7/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 900us/step - loss: 28106973184.0000
Epoch 8/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 891us/step - loss: 29005492224.0000
Epoch 9/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 928us/step - loss: 29002612736.0000
Epoch 10/10
645/645 ━━━━━━━━━━━━━━━━━━━━ 1s 864us/step - loss: 27780956160.0000
Out[8]:
<keras.src.callbacks.history.History at 0x211cfd3db80>

A adição da camada de Dropout no modelo foi essencial para mitigar o risco de overfitting durante o treinamento. Os resultados mostraram uma redução constante na perda ao longo das épocas, indicando que o modelo foi capaz de aprender de maneira controlada. Essa técnica, junto com a otimização dos hiperparâmetros, é crucial para garantir que redes neurais sejam capazes de fazer previsões precisas e confiáveis, mesmo em cenários complexos.


© Copyright 2024 | Luciano Magalhães