Skip to content

Introdução

Este projeto tem como objetivo explorar diferentes técnicas de aprendizado supervisionado e não supervisionado, aplicadas a um conjunto de dados real relacionado a cartas colecionáveis.

Serão utilizados algoritmos como:
- Random Forest,
- KNN,
- Regressão Linear,
além de outros métodos complementares conforme a necessidade analítica.

Com a aplicação dessas abordagens, busca-se compreender os pontos fortes e limitações de cada técnica, bem como avaliar seu desempenho em diferentes cenários preditivos e exploratórios.


Exploração de Dados

A análise inicial do conjunto de dados envolve a descrição detalhada das variáveis, cálculos de estatísticas descritivas e produção de visualizações que permitam entender o comportamento, distribuição e relevância das informações contidas no dataset.


Contexto da Base de Dados

O dataset utilizado neste projeto é composto por um grande volume de registros de cartas colecionáveis, incluindo atributos de preço, tipo, acabamento e coleção.

No total, são disponibilizadas 82.423 observações (linhas) distribuídas em 5 variáveis (colunas).

Essas variáveis são do tipo numérico (como valores monetários) e categórico, contendo múltiplas classificações de cartas, elementos e versões foil.

Entre os tipos de atributos presentes:

  • Atributos numéricos — representando valores monetários das cartas.
  • Atributos categóricos — como tipo de carta, elemento, coleção e tipo de acabamento (foil).
  • O dataset não possui variáveis booleanas codificadas numericamente, mas apresenta categorias bem definidas, adequadas para análises supervisionadas e não supervisionadas.

Como o conjunto possui estrutura consistente e volume expressivo, não houve necessidade de criação de dados sintéticos. O dataset real foi integralmente utilizado para a fase de exploração.

Para experimentos envolvendo técnicas preditivas — caso necessário — a variável valor pode ser tratada como target em problemas de regressão, enquanto variáveis como elemento, coleção ou foil podem ser utilizadas como alvos em cenários de classificação.

Descrição e Estatísticas Descritivas das colunas

Variável Descrição Estatísticas Descritivas (%)
valor Valor monetário da carta. Média: 43,24
Mediana: 8,40
Mínimo: 0,07
Máximo: 12.276,10
elemento Tipo elemental associado ao Pokémon ou carta. Grama: 11,94%
Normal: 11,94%
Psíquica: 10,70%
Água: 10,61%
Luta: 10,50%
Fogo: 7,47%
Escuridão: 7,37%
Raio: 5,96%
Metal: 5,11%
Dragão: 2,28%
foil Tipo de acabamento da carta (variações de brilho). Normal: 33,06%
Foil: 25,94%
Reverse Foil: 24,67%
Pokeball Foil: 16,27%
Masterball Foil: 0,06%
tipoCarta Categoria da carta dentro do jogo. Pokémon – Basic: 47,91%
Pokémon – Stage 1: 26,51%
Pokémon – Stage 2: 7,41%
colecao Coleção/expansão à qual a carta pertence. Megaevolução: 21,83%
Amigos da Jornada: 21,04%
Evoluções Prismáticas: 19,13%
Raio Preto: 13,17%
Fogo Branco: 13,02%
151: 11,82%

Pré Processamento

Como os dados foram obtidos a partir de scripts de raspagem desenvolvidos pelo grupo, já existe um bom nível de padronização nas colunas. Durante a etapa de inspeção inicial, verificou-se que apenas a variável elemento necessitava de pré-processamento. Isso ocorre porque nem todas as cartas possuem um tipo elemental — por exemplo, cartas de Treinador, Itens e algumas cartas especiais não apresentam elemento associado.

Para tratar essa inconsistência, a coluna foi convertida para o tipo string e os valores ausentes foram substituídos pela categoria "None", representando corretamente a ausência de elemento. Dessa forma, evita-se perda de informação e garante-se a consistência sem introduzir distorções nos modelos a serem aplicados.

valor elemento foil tipoCarta colecao
4.81 Luta Reverse Foil Pokémon – Basic Megaevolução
22.66 Grama Reverse Foil Pokémon – Basic Fogo Branco
10.33 Psíquica Normal Pokémon – Basic Fogo Branco
14.29 Grama Normal Pokémon – Basic Evoluções Prismáticas
0.29 Raio Normal Pokémon – Stage 1 Megaevolução
7.75 Raio Reverse Foil Pokémon – Stage 1 Amigos da Jornada
0.33 Luta Normal Pokémon – Stage 1 Megaevolução
52.23 Dragão Foil Pokémon – Basic Fogo Branco
5.51 None Normal Trainer - Item - Pokémon Tool Evoluções Prismáticas
5.41 Grama Foil Pokémon – Stage 1 Amigos da Jornada
import pandas as pd


df = pd.read_csv('dados/dadosprojeto.csv', low_memory=True)

d = df.copy()

d['elemento'] = d['elemento'].astype('string')
d['foil'] = d['foil'].astype('string')
d['tipoCarta'] = d['tipoCarta'].astype('string')
d['colecao'] = d['colecao'].astype('string')

d['elemento'] = d['elemento'].fillna('None')



print(d.sample(n=10).to_markdown(index=False))

Divisão dos Dados

O conjunto de dados foi dividido em 70% para treino e 30% para validação, garantindo que os modelos fossem treinados em partes significativa das observações, mas ainda avaliados em dados não vistos. O uso do conjunto de validação tem como objetivo detectar e reduzir o risco de overfitting.

Treinamento dos modelos

Random Forest

2025-11-30T23:40:34.267958 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.preprocessing import OneHotEncoder
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestRegressor

# =========================
# Configurações

def pre(d):


    d['elemento'] = d['elemento'].astype('string')
    d['foil'] = d['foil'].astype('string')
    d['tipoCarta'] = d['tipoCarta'].astype('string')
    d['colecao'] = d['colecao'].astype('string')

    d['elemento'] = d['elemento'].fillna('None')
    return d

RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)

CSV_PATH = "dados/dadosprojeto.csv"   # <-- ajuste aqui
TARGET_COLUMN = "valor"       # <-- ajuste aqui

# =========================
# Leitura dos dados
# =========================
df = pd.read_csv(CSV_PATH)
df = pre(df)

y = df[TARGET_COLUMN].values
X = df.drop(columns=[TARGET_COLUMN])

# =========================
# One-Hot Encoding
# =========================
ohe = OneHotEncoder(handle_unknown="ignore")
X_ohe = ohe.fit_transform(X)

# =========================
# PCA para 2 componentes
# =========================
pca = PCA(n_components=2, random_state=RANDOM_STATE)
X_pca = pca.fit_transform(X_ohe.toarray())

# =========================
# Treinar modelo no espaço PCA
# =========================
model = RandomForestRegressor(
    n_estimators=200,
    random_state=RANDOM_STATE
)
model.fit(X_pca, y)

y_pred = model.predict(X_pca)

# =========================
# Plot – Espaço PCA colorido pelo valor previsto
# =========================
plt.figure(figsize=(7, 6))
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y_pred, alpha=0.7)
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("Random Forest – Espaço PCA (cor = valor previsto)")
plt.colorbar(scatter, label="Valor previsto")
plt.grid(alpha=0.3)
plt.tight_layout()

# Para imprimir na página HTML
buffer = StringIO()
plt.savefig(buffer, format="svg")
print(buffer.getvalue())

KNN

2025-11-30T23:40:40.042266 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.preprocessing import OneHotEncoder
from sklearn.decomposition import PCA
from sklearn.neighbors import KNeighborsRegressor

# =========================
# Configurações
# =========================

def pre(d):


    d['elemento'] = d['elemento'].astype('string')
    d['foil'] = d['foil'].astype('string')
    d['tipoCarta'] = d['tipoCarta'].astype('string')
    d['colecao'] = d['colecao'].astype('string')

    d['elemento'] = d['elemento'].fillna('None')
    return d


RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)

CSV_PATH = "dados/dadosprojeto.csv"   # <-- ajuste aqui
TARGET_COLUMN = "valor"       # <-- ajuste aqui

# =========================
# Leitura dos dados
# =========================
df = pd.read_csv(CSV_PATH)
df = pre(df)

y = df[TARGET_COLUMN].values
X = df.drop(columns=[TARGET_COLUMN])

# =========================
# One-Hot Encoding
# =========================
ohe = OneHotEncoder(handle_unknown="ignore")
X_ohe = ohe.fit_transform(X)

# =========================
# PCA para 2 componentes
# =========================
pca = PCA(n_components=2, random_state=RANDOM_STATE)
X_pca = pca.fit_transform(X_ohe.toarray())

# =========================
# Treinar modelo no espaço PCA
# =========================
model = KNeighborsRegressor(n_neighbors=5)
model.fit(X_pca, y)

y_pred = model.predict(X_pca)

# =========================
# Plot – Espaço PCA colorido pelo valor previsto
# =========================
plt.figure(figsize=(7, 6))
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y_pred, alpha=0.7)
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("KNN Regressor – Espaço PCA (cor = valor previsto)")
plt.colorbar(scatter, label="Valor previsto")
plt.grid(alpha=0.3)
plt.tight_layout()

# Para imprimir na página HTML
buffer = StringIO()
plt.savefig(buffer, format="svg")
print(buffer.getvalue())

Linear

2025-11-30T23:40:45.417415 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.preprocessing import OneHotEncoder
from sklearn.decomposition import PCA
from sklearn.linear_model import LinearRegression

# =========================
# Configurações
# =========================

def pre(d):


    d['elemento'] = d['elemento'].astype('string')
    d['foil'] = d['foil'].astype('string')
    d['tipoCarta'] = d['tipoCarta'].astype('string')
    d['colecao'] = d['colecao'].astype('string')

    d['elemento'] = d['elemento'].fillna('None')
    return d


RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)

CSV_PATH = "dados/dadosprojeto.csv"   # <-- ajuste aqui
TARGET_COLUMN = "valor"       # <-- ajuste aqui

# =========================
# Leitura dos dados
# =========================
df = pd.read_csv(CSV_PATH)
df = pre(df)

y = df[TARGET_COLUMN].values
X = df.drop(columns=[TARGET_COLUMN])

# =========================
# One-Hot Encoding
# =========================
ohe = OneHotEncoder(handle_unknown="ignore")
X_ohe = ohe.fit_transform(X)

# =========================
# PCA para 2 componentes
# =========================
pca = PCA(n_components=2, random_state=RANDOM_STATE)
X_pca = pca.fit_transform(X_ohe.toarray())

# =========================
# Treinar modelo no espaço PCA
# =========================
model = LinearRegression()
model.fit(X_pca, y)

# Previsões no próprio espaço PCA (para visualização do modelo)
y_pred = model.predict(X_pca)

# =========================
# Plot – Espaço PCA colorido pelo valor previsto
# =========================
plt.figure(figsize=(7, 6))
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y_pred, alpha=0.7)
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("Linear Regression – Espaço PCA (cor = valor previsto)")
plt.colorbar(scatter, label="Valor previsto")
plt.grid(alpha=0.3)
plt.tight_layout()

# Para imprimir na página HTML
buffer = StringIO()
plt.savefig(buffer, format="svg")
print(buffer.getvalue())

Avaliação

2025-11-30T23:41:57.143504 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/ 2025-11-30T23:41:57.201782 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from io import StringIO
from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# =========================
# Configurações iniciais
# =========================
RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)

# =========================
# Configurações
# =========================

def pre(d):


    d['elemento'] = d['elemento'].astype('string')
    d['foil'] = d['foil'].astype('string')
    d['tipoCarta'] = d['tipoCarta'].astype('string')
    d['colecao'] = d['colecao'].astype('string')

    d['elemento'] = d['elemento'].fillna('None')
    return d


RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)

CSV_PATH = "dados/dadosprojeto.csv"   # <-- ajuste aqui
TARGET_COLUMN = "valor"       # <-- ajuste aqui

# =========================
# Leitura dos dados
# =========================
df = pd.read_csv(CSV_PATH)
df = pre(df)

# y = variável numérica (alvo)
y = df[TARGET_COLUMN]

# X = todas as demais colunas (assumidas categóricas)
X = df.drop(columns=[TARGET_COLUMN])

# =========================
# Train/Test split
# =========================
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,
    random_state=RANDOM_STATE
)

# =========================
# One-Hot Encoding para todas as features
# =========================
categorical_features = X.columns.tolist()

preprocessor = ColumnTransformer(
    transformers=[
        ("cat", OneHotEncoder(handle_unknown="ignore"), categorical_features)
    ]
)

# =========================
# Definição dos modelos (pipelines)
# =========================
models = {
    "LinearRegression": Pipeline([
        ("preprocess", preprocessor),
        ("model", LinearRegression())
    ]),

    "RandomForest": Pipeline([
        ("preprocess", preprocessor),
        ("model", RandomForestRegressor(
            n_estimators=200,
            random_state=RANDOM_STATE
        ))
    ]),

    "KNN": Pipeline([
        ("preprocess", preprocessor),
        ("model", KNeighborsRegressor(
            n_neighbors=5
        ))
    ])
}

# =========================
# Treinamento dos modelos
# =========================
fitted_models = {}
for name, mdl in models.items():
    mdl.fit(X_train, y_train)
    fitted_models[name] = mdl

# =========================
# Função de métricas
# =========================
def compute_regression_metrics(y_true, y_pred):
    mae = mean_absolute_error(y_true, y_pred)
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    r2 = r2_score(y_true, y_pred)

    return {
        "MAE": mae,
        "MSE": mse,
        "RMSE": rmse,
        "R2": r2
    }

# =========================
# Avaliar modelos e montar DataFrame de métricas
# =========================
results = {}

for name, mdl in fitted_models.items():
    y_pred = mdl.predict(X_test)
    metrics = compute_regression_metrics(y_test, y_pred)
    results[name] = metrics

metrics_df = pd.DataFrame(results).T  # modelos nas linhas

# =========================
# Gráficos de comparação (R² e RMSE)
# =========================
# Gráfico 1 – R² por modelo
plt.figure(figsize=(8, 5))
plt.bar(metrics_df.index, metrics_df["R2"])
plt.title("R² por modelo")
plt.ylabel("R²")
plt.ylim(0, 1)
plt.grid(axis="y", alpha=0.3)

buffer = StringIO()
plt.savefig(buffer, format="svg")
print(buffer.getvalue())

# Gráfico 2 – RMSE por modelo
plt.figure(figsize=(8, 5))
plt.bar(metrics_df.index, metrics_df["RMSE"])
plt.title("RMSE por modelo")
plt.ylabel("RMSE")
plt.grid(axis="y", alpha=0.3)

# Para imprimir na página HTML
buffer = StringIO()
plt.savefig(buffer, format="svg")
print(buffer.getvalue())

Avaliação dos Modelos

A avaliação dos modelos foi realizada combinando a visualização das predições no espaço PCA e as métricas quantitativas de desempenho (R² e RMSE). Nos gráficos de PCA, observamos que tanto o Random Forest quanto o KNN apresentam baixa variação nas cores, indicando que ambos tendem a prever valores muito próximos entre si, mesmo em regiões distintas do espaço reduzido — um sinal claro de subajuste (underfitting). O desempenho numérico confirma essa limitação: o KNN apresentou o menor R² do grupo e o maior RMSE, indicando dificuldade em capturar relações relevantes no dataset.

O Random Forest, apesar de também apresentar um padrão visual homogêneo no PCA, foi o modelo que obteve melhor desempenho relativo, alcançando o maior R² (ainda baixo) e o menor RMSE, mostrando ligeira superioridade na modelagem da variabilidade dos preços.

Já a Regressão Linear apresentou um comportamento diferente: no PCA, suas predições exibem gradientes de cor bem definidos, refletindo maior sensibilidade às mudanças nas componentes principais. No entanto, seu R² reduzido demonstra que, apesar de capturar alguma estrutura linear nos dados, o modelo não explica adequadamente a variabilidade da variável resposta.

Em conjunto, os resultados mostram que nenhum dos modelos conseguiu generalizar bem, sugerindo necessidade de engenharia de features mais robusta, uso de técnicas avançadas ou ajustes adicionais para melhorar a capacidade preditiva.