Skip to content

Random Forest

Introdução

A Random Forest é um método de aprendizado supervisionado baseado em conjunto de árvores de decisão. A ideia central é treinar várias árvores em amostras bootstrap do conjunto de treino, introduzindo aleatoriedade tanto nas amostras quanto na seleção de atributos em cada divisão. A predição final resulta do voto da maioria (classificação) ou da média (regressão). Essa estratégia reduz overfitting típico de árvores individuais, melhora a generalização e mantém boa interpretabilidade via importância de atributos. Além disso, por ser baseada em árvores, lida naturalmente com relações não lineares e interações entre variáveis e não exige padronização das features para funcionar — embora possamos manter o mesmo pipeline de pré-processamento para consistência com os outros modelos do projeto.

Exploração dos Dados

O Dataset

Para esse projeto foi utilizada o Dataset Fitness Classification Dataset. Essa Base de dados posuí 2.000 linhas e 11 colunas. A variável dependente que será usada como objeto de classificação é a is_fit, ela indica se a pessoa é fit (1) ou não fit (0).

Análise dos dados

Tipo: numérica contínua

O que é: idade em anos.

Para que serve: pode relacionar-se com hábitos e condição física.

Ação necessária: nenhuma obrigatória; só checar faixas implausíveis (não observei no geral).

2025-10-28T15:18:55.640723 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua

O que é: altura em centímetros.

Para que serve: isoladamente costuma ter pouco poder; combinada ao peso forma o BMI.

Ação necessária: checar valores muito fora do plausível. Sugestão: considerar substituir altura e peso por bmi(Índice de Massa Corporal).

2025-10-28T15:18:55.708982 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua

O que é: peso em quilogramas.

Para que serve: junto com a altura permite calcular BMI = peso(kg) / (altura(m))², que costuma ser mais informativo para a árvore.

Ação necessária: manter como numérica ou criar bmi e remover height_cm/weight_kg das features (deixando só o bmi).

2025-10-28T15:18:55.795187 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua

O que é: frequência cardíaca (bpm).

Para que serve: indicador de condicionamento cardiovascular; pode ajudar na separação das classes.

Ação necessária: nenhuma obrigatória; apenas conferir plausibilidade de valores extremos.

2025-10-28T15:18:55.849942 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua

O que é: medida sintética de pressão arterial fornecida pelo dataset.

Para que serve: sinal de saúde geral que pode complementar a predição.

Ação necessária: nenhuma obrigatória; só verificar extremos muito fora do usual.

2025-10-28T15:18:55.936101 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua

O que é: horas de sono por dia.

Para que serve: hábito de descanso; costuma ter correlação com “estar fit”.

Ação necessária: possui valores ausentes (160 valores); imputar com a mediana.

2025-10-28T15:18:56.009668 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua (escala)

O que é: qualidade da nutrição (escala contínua, ex.: 0–10).

Para que serve: proxy de alimentação saudável; geralmente relevante.

Ação necessária: nenhuma; manter como numérica (só garantir faixa válida).

2025-10-28T15:18:56.085504 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: numérica contínua (escala)

O que é: nível de atividade física (escala contínua, ex.: 0–10).

Para que serve: costuma ser uma das variáveis mais importantes para is_fit.

Ação necessária: nenhuma; manter como numérica (garantir faixa válida).

2025-10-28T15:18:56.160451 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: categórica binária

O que é: status de tabagismo (sim/não).

Para que serve: fator de estilo de vida; pode ajudar a separar perfis.

Ação necessária: tipos mistos no bruto (“yes/no” e “1/0”). Padronizar para binário numérico (no→0, yes→1) e converter para int.

2025-10-28T15:18:56.244451 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: categórica binária

O que é: gênero (F/M).

Para que serve: possível moderador de outros efeitos; em geral fraco sozinho.

Ação necessária: codificar para numérico (F→0, M→1) e converter para int.

2025-10-28T15:18:56.272869 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Tipo: categórica binária (target)

O que é: rótulo de condição física (1 = fit, 0 = não fit).

Para que serve: variável dependente a ser prevista.

Ação necessária: checar balanceamento das classes.

2025-10-28T15:18:56.326819 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Pré-processamento

Nesta etapa tratei e preparei os dados para treinar a Árvore de Decisão. Antes do tratamento, a base apresentava valores ausentes em sleep_hours, tipos mistos em smokes (valores como yes/no e 0/1 ao mesmo tempo) e variáveis categóricas em texto (gender com F/M). Abaixo, o que foi feito:

• Padronização de categóricas

  • smokes: normalizei rótulos e converti para binário numérico (no→0, yes→1, cobrindo também 0/1 em string).

  • gender: converti F→0 e M→1.

• Valores ausentes

  • sleep_hours: converti para numérico e imputei a mediana.

• Tipos e consistência

  • Garanti que as variáveis contínuas ficaram em formato numérico, sem strings residuais/espaços.

• Criação de nova variável

  • Criei a variável BMI (peso(kg) / altura(m)²) para avaliar seu impacto. Na exploração, mantenho height_cm e weight_kg para referência; na modelagem, comparo dois cenários: (A) sem BMI (altura + peso) e (B) com apenas BMI, evitando usar os três juntos no mesmo modelo para não introduzir redundância.
age height_cm weight_kg heart_rate blood_pressure sleep_hours nutrition_quality activity_index smokes gender is_fit
66 181 84 69.6 132.3 5.3 5.75 1.09 0 M 0
73 163 77 64.6 98.6 null 5.71 4.38 yes M 0
25 157 90 96.9 108.3 null 3.72 1.24 yes M 0
54 189 87 69.3 113 5.8 6.1 3.43 0 M 1
79 169 46 58.7 105.1 null 1.83 1.92 no M 0
18 193 96 65.2 131.5 10.5 6.67 2.8 yes M 1
72 194 58 48 141.3 7.8 7.05 1.13 0 F 0
52 197 78 83.9 124.8 6.1 6.76 3.47 no F 1
41 189 112 56.6 98.9 9.0 5.88 2.55 yes F 0
25 186 100 58.8 111.3 7.0 7.52 2.97 yes M 1
53 169 78 105.6 108.9 7.4 0.18 1.51 yes M 0
79 160 94 65.4 107.9 5.0 5.56 2.12 0 M 0
73 151 62 67.2 117.9 7.3 6.83 1.51 0 F 0
33 153 103 70 140.5 7.7 8.51 3.48 no F 0
45 159 85 74.7 132.6 7.3 1.75 1.26 0 F 0
import pandas as pd

df = pd.read_csv("./src/fitness_dataset.csv")

df["sleep_hours"] = df["sleep_hours"].fillna(df["sleep_hours"].median())

df["smokes"] = (
    df["smokes"].astype(str).str.strip().str.lower()
      .map({"yes": 1, "no": 0, "1": 1, "0": 0})
).astype(int)

df["gender"] = df["gender"].replace({"F": 0, "M": 1}).astype(int)

h_m = pd.to_numeric(df["height_cm"], errors="coerce") / 100.0
bmi = pd.to_numeric(df["weight_kg"], errors="coerce") / (h_m**2)
df["bmi"] = bmi.replace([float("inf"), float("-inf")], pd.NA).fillna(bmi.median())

print(df.sample(n=15).to_markdown(index=False))
age height_cm weight_kg heart_rate blood_pressure sleep_hours nutrition_quality activity_index smokes gender is_fit bmi
53 169 78 105.6 108.9 7.4 0.18 1.51 1 1 0 27.31
75 153 67 85 111.9 7.9 9.51 2.11 0 1 1 28.6215
37 181 78 71.8 152.7 8.2 8.77 3.87 1 0 0 23.8088
45 179 71 68.2 115.8 7.1 3.11 3.18 0 0 0 22.1591
55 167 57 74.2 90 8.5 4.12 2.01 1 1 0 20.4382
22 184 63 76 116.1 8.2 6.74 3.59 0 0 1 18.6082
24 160 82 68.4 132.8 4.7 1.91 3.29 1 1 0 32.0312
18 167 59 84.7 135.7 8.8 1.43 2.21 0 0 0 21.1553
72 152 91 79.5 148.2 8 5.37 4 0 1 0 39.3871
34 177 96 60 128.9 7.2 6.85 3.4 0 0 1 30.6425
63 155 68 68.6 137.8 5.7 3 4.64 0 0 1 28.3039
48 197 61 81.4 121.9 5.2 0.44 1.19 0 0 0 15.718
65 177 115 80.5 117.6 6.4 5.21 3.61 1 1 0 36.7072
22 178 92 90.2 133.2 6.8 4.53 1.06 1 0 1 29.0367
29 160 84 58.9 131.5 6 3.89 1.11 0 0 0 32.8125

Divisão dos Dados

Os dados foram divididos em treino (80%) e teste (20%) com o parâmetro random_state=42 para garantir reprodutibilidade e stratify=y para manter a proporção entre as classes is_fit.

Como a Random Forest é composta por árvores de decisão, não há necessidade de padronização das variáveis numéricas, porém a mesma estrutura de features foi mantida para comparação com os demais modelos.

Shape X: (2000, 9) Proporção 'is_fit'=1: 0.3995

Treinamento do Modelo

O modelo foi configurado com 300 árvores (n_estimators=300), seleção aleatória de atributos (max_features="sqrt") e profundidade ilimitada (max_depth=None), permitindo que cada árvore se adapte ao padrão dos dados de forma independente. O treinamento foi realizado sobre o conjunto de treino e avaliado com base na acurácia, balanced accuracy e matriz de confusão.

Acurácia: 0.7600 Balanced Accuracy: 0.7375 Classification Report: precision recall f1-score support 0 0.7727 0.8500 0.8095 240 1 0.7353 0.6250 0.6757 160 accuracy 0.7600 400 macro avg 0.7540 0.7375 0.7426 400 weighted avg 0.7578 0.7600 0.7560 400 2025-10-28T15:18:57.283151 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

2025-10-28T15:18:58.003057 image/svg+xml Matplotlib v3.10.7, https://matplotlib.org/

Avaliação do Modelo

A Random Forest apresentou desempenho consistente e maior estabilidade em comparação com modelos individuais de árvore ou com o KNN. A matriz de confusão mostrou uma redução significativa nos erros de classificação, e o valor de Balanced Accuracy indicou boa capacidade de generalização entre as classes.

A análise da importância das variáveis revelou que os fatores mais determinantes para o modelo são:

  • activity_index
  • nutrition_quality
  • bmi
  • heart_rate

Essas variáveis refletem, respectivamente, o nível de atividade física, a qualidade da alimentação e os indicadores fisiológicos de saúde.

Conclusão

O uso da Random Forest no dataset de fitness demonstrou excelente equilíbrio entre desempenho e interpretabilidade. O modelo foi capaz de identificar padrões consistentes que diferenciam indivíduos “fit” e “não fit”, destacando-se pela robustez e pela redução de sobreajuste em relação à árvore de decisão simples.

A análise confirma que hábitos e parâmetros fisiológicos — especialmente atividade física, nutrição e índice de massa corporal — são fatores-chave para a previsão da condição física. Como próximos passos, recomenda-se explorar a otimização de hiperparâmetros (max_depth, min_samples_leaf, n_estimators) e realizar validação cruzada para refinar ainda mais a performance do modelo.