17  Análise Discriminante Exploratória

Neste exemplo, realizaremos uma Análise Discriminante com um dos conjuntos de dados mais clássicos da estatística: o dataset Iris, popularizado por R.A. Fisher em seu artigo de 1936, que introduziu a Análise Discriminante Linear.

O nosso foco será exploratório: queremos entender como as medidas das flores (variáveis) ajudam a distinguir as três espécies de íris (grupos). Em vez de focar na precisão da classificação de novas flores, vamos usar a LDA para encontrar as “visões” (projeções) que melhor separam os grupos e interpretar o que essas visões significam.

O conjunto de dados contém 150 observações de flores de íris, divididas igualmente em três espécies:

  1. Setosa
  2. Versicolor
  3. Virginica

Para cada flor, quatro características foram medidas (em centímetros):

17.1 Análise Descritiva

Queremos entender a distribuição de cada variável e como elas se relacionam, especialmente quando observamos os diferentes grupos. Vamos carregar os dados e visualizar um resumo descritivo e um gráfico de pares.

Código
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris

# Carregar o dataset Iris
iris_data = load_iris()
iris = pd.DataFrame(data=iris_data.data, columns=iris_data.feature_names)
iris['especie'] = iris_data.target_names[iris_data.target]

# Renomear colunas para o português, para facilitar a interpretação
iris.columns = ['comp_sepala', 'larg_sepala', 'comp_petala', 'larg_petala', 'especie']

# Exibir as primeiras linhas
print(iris.head())
Tabela 17.1: Primeiras linhas do banco de dados Iris
   comp_sepala  larg_sepala  comp_petala  larg_petala especie
0          5.1          3.5          1.4          0.2  setosa
1          4.9          3.0          1.4          0.2  setosa
2          4.7          3.2          1.3          0.2  setosa
3          4.6          3.1          1.5          0.2  setosa
4          5.0          3.6          1.4          0.2  setosa
Código
# Gerar o gráfico de pares

sns.pairplot(iris, hue='especie', palette='viridis', height=2, aspect=1)
plt.show()
Figura 17.1: Gráfico de pares das variáveis do dataset Iris, separadas por espécie.

Na figura, observamos algumas características interessantes:

  1. Separação Clara da Setosa: A espécie Setosa é facilmente distinguível das outras duas. Suas pétalas são muito menores (comprimento e largura) e suas sépalas são mais largas e mais curtas. A separação é tão clara que um simples corte em comp_petala ou larg_petala poderia classificar quase todas as Setosas perfeitamente.

  2. Sobreposição entre Versicolor e Virginica: As espécies Versicolor e Virginica são mais parecidas. Embora a Virginica tenda a ter pétalas e sépalas maiores que a Versicolor, há uma sobreposição considerável em todas as variáveis. É aqui que uma técnica multivariada como a Análise Discriminante se torna útil, pois pode encontrar uma combinação de variáveis que melhore a separação.

  3. Correlações: O comprimento e a largura da pétala (comp_petala e larg_petala) são altamente correlacionados. O comprimento da sépala (comp_sepala) também tem uma correlação positiva com ambas.

17.2 Análise Discriminante Linear (LDA)

A análise discriminante linear tem como suposição a homocedasticidade dos grupos. Ou seja, ela pressupõe que as matrizes de covariâncias de todos os grupos são iguais. A Figura 17.1 nos dá indícios de que tal suposição não é razoável. Em particular, a variância da largura e do comprimento da sépala do grupo Setosa parece bem inferior as demais. Ainda assim, vamos prosseguir com a LDA por razões didáticas.

A LDA busca encontrar as combinações lineares das variáveis originais — as funções discriminantes — que maximizam a razão entre a variância entre os grupos e a variância dentro dos grupos. Como temos \(k=3\) grupos e \(p=4\) variáveis, podemos encontrar no máximo \(\min(p, k-1) = \min(4, 2) = 2\) funções discriminantes.

Essas duas funções, LD1 e LD2, criarão um novo espaço 2D onde a separação dos grupos é otimizada.

Código
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

# Separar variáveis preditoras (X) e a variável resposta (y)
X = iris[['comp_sepala', 'larg_sepala', 'comp_petala', 'larg_petala']]
y = iris['especie']

# Criar e ajustar o modelo LDA
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, y)

# Criar um DataFrame com os resultados
lda_df = pd.DataFrame(data=X_lda, columns=['LD1', 'LD2'])
lda_df['especie'] = y

# Plotar o resultado
plt.figure(figsize=(8, 6))
sns.scatterplot(x='LD1', y='LD2', hue='especie', data=lda_df, palette='viridis', s=70, alpha=0.8)
plt.title('Projeção da Análise Discriminante Linear')
plt.xlabel('Função Discriminante 1 (LD1)')
plt.ylabel('Função Discriminante 2 (LD2)')
plt.grid(True, linestyle='--', alpha=0.5)
plt.legend()
plt.show()
Figura 17.2: Projeção dos dados do Iris no espaço discriminante. Os eixos LD1 e LD2 são as combinações lineares que melhor separam as espécies.

O gráfico da projeção LDA é bem informativo:

  • LD1 (Eixo Horizontal): Esta primeira função discriminante separa a Setosa das outras duas espécies. As flores da espécie Setosa aparecem agrupadas a direita, com uma grande lacuna os separando dos outros grupos. Vemos ainda que essa dimensão separa também os grupos Versicolor e Virginica relativamente bem.
  • LD2 (Eixo Vertical): Esta segunda função discriminante acaba não sendo tão informativa, principalmente pelo fato da primeira dimensão já apresentar uma ótima separabilidade dos grupos. Ainda assim, podemos observar que as flores Virginica tendem a ter valores mais baixos em LD2, enquanto a Versicolor tem valores mais altos.

Juntas, as duas funções criam um mapa claro da estrutura dos grupos. Mas o que exatamente são LD1 e LD2? Para entender isso, precisamos olhar para os coeficientes (ou “loadings”) de cada função.

Código
# Coeficientes das funções discriminantes
coeficientes = pd.DataFrame(lda.scalings_, index=X.columns, columns=['LD1', 'LD2'])
print("Coeficientes das Funções Discriminantes (Loadings):")
print(coeficientes)
Coeficientes das Funções Discriminantes (Loadings):
                  LD1       LD2
comp_sepala  0.829378 -0.024102
larg_sepala  1.534473 -2.164521
comp_petala -2.201212  0.931921
larg_petala -2.810460 -2.839188

Interpretando os Coeficientes:

  • LD1: Os coeficientes de maior magnitude são larg_petala (-2.81) e comp_petala (-2.20), ambos negativos, que se contrapõem aos coeficientes positivos de larg_sepala (1.53) e comp_sepala (0.83). Isso significa que a LD1 é uma medida de contraste entre o tamanho das pétalas e o tamanho das sépalas. Escores baixos em LD1 (valores negativos) são associados a flores com pétalas grandes, enquanto escores altos (valores positivos) estão associados a flores com pétalas pequenas e sépalas largas. Olhando o gráfico, vemos que a Setosa tem escores altos em LD1, o que é consistente com suas pétalas pequenas. Virginica e Versicolor têm escores negativos, correspondendo às suas pétalas maiores.

  • LD2: Esta função é dominada pelo contraste entre larg_sepala (-2.16) e larg_petala (-2.84), ambos com grandes coeficientes negativos, e comp_petala (0.93), com coeficiente positivo. Essencialmente, a LD2 separa flores com base em uma “forma” que opõe o comprimento da pétala à sua largura e à largura da sépala. Esta função é a principal responsável por separar a Versicolor (que tende a ter escores positivos em LD2) da Virginica (que tende a ter escores negativos), capturando as diferenças mais sutis entre essas duas espécies.

17.3 Comparação das Fronteiras de Decisão (LDA vs. QDA)

Enquanto a LDA assume que todos os grupos têm a mesma matriz de covariância (levando a fronteiras de decisão lineares), a Análise Discriminante Quadrática (QDA) relaxa essa suposição, permitindo fronteiras quadráticas mais flexíveis.

Vamos visualizar as fronteiras de decisão de ambos os modelos usando apenas duas variáveis: comp_petala e larg_petala. O objetivo disso é poder observar a diferença dos métodos visualmente de forma clara em duas dimensões. Ilustramos as regiões de discriminação na figura abaixo.

Código
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
from matplotlib.colors import ListedColormap

# Usar apenas as duas variáveis mais importantes para visualização
X_petal = iris[['comp_petala', 'larg_petala']]
y_petal = iris['especie']

# Mapear espécies para números para o plot
species_map = {species: i for i, species in enumerate(y_petal.unique())}
y_numeric = y_petal.map(species_map)

# Ajustar modelos LDA e QDA
lda_petal = LinearDiscriminantAnalysis()
lda_petal.fit(X_petal, y_petal)

qda_petal = QuadraticDiscriminantAnalysis()
qda_petal.fit(X_petal, y_petal)

# Criar uma malha de pontos para plotar as fronteiras
x_min, x_max = X_petal.iloc[:, 0].min() - 1, X_petal.iloc[:, 0].max() + 1
y_min, y_max = X_petal.iloc[:, 1].min() - 1, X_petal.iloc[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

# Criar um DataFrame com os pontos da malha para evitar o warning
grid_points = pd.DataFrame(np.c_[xx.ravel(), yy.ravel()], columns=X_petal.columns)

# Prever em cada ponto da malha
Z_lda = lda_petal.predict(grid_points)
Z_lda = np.array([species_map[label] for label in Z_lda]).reshape(xx.shape)

Z_qda = qda_petal.predict(grid_points)
Z_qda = np.array([species_map[label] for label in Z_qda]).reshape(xx.shape)

# Plotar
plt.figure(figsize=(8, 6))

# Plotar as áreas de decisão da QDA
cmap_light = ListedColormap(['#DAF7A6', '#FFC300', '#FF5733'])
plt.contourf(xx, yy, Z_qda, alpha=0.2, cmap=cmap_light)

# Plotar as fronteiras da LDA
plt.contour(xx, yy, Z_lda, colors='black', linestyles='--', linewidths=2)

# Plotar os pontos de dados
sns.scatterplot(x=X_petal.iloc[:, 0], y=X_petal.iloc[:, 1], hue=y_petal,
                palette='viridis', alpha=0.9, edgecolor='k', s=80)

plt.title('Fronteiras de Decisão: LDA (tracejado) vs. QDA (fundo colorido)')
plt.xlabel('Comprimento da Pétala (cm)')
plt.ylabel('Largura da Pétala (cm)')
plt.legend(title='Espécie')
plt.show()
Figura 17.3: Fronteiras de decisão para LDA (linhas retas) e QDA (curvas) usando as variáveis da pétala.

A visualização das fronteiras de decisão nos mostra:

  • LDA (Linhas Tracejadas): Como esperado, a LDA cria fronteiras perfeitamente retas entre os grupos. Ela faz um excelente trabalho ao isolar a Setosa, mas a linha que separa Versicolor e Virginica não mostra uma separação tão clara.
  • QDA (Fundo Colorido): A QDA cria fronteiras curvas (cônicas). Note como a fronteira entre Versicolor e Virginica é uma parábola. Essa flexibilidade permite que a QDA se ajuste um pouco melhor à forma específica da nuvem de pontos de cada grupo.

17.4 Conclusão

Nesta análise exploratória, usamos a Análise Discriminante não apenas como um classificador, mas como uma ferramenta para redução de dimensionalidade e interpretação.

  1. A Análise Descritiva nos deu a intuição inicial de que a Setosa era muito diferente e que a distinção entre Versicolor e Virginica seria o principal desafio.
  2. A Análise Discriminante Linear confirmou isso e foi além: ela quantificou a importância de cada variável para a separação. A LD1, principal eixo de separação, revelou que a distinção dos grupos se baseia em uma medida de contraste entre o tamanho das pétalas e o das sépalas. A LD2 capturou uma diferença de forma mais sutil, opondo o comprimento da pétala à sua largura e à largura da sépala, o que foi fundamental para separar as espécies mais parecidas, Versicolor e Virginica.
  3. A comparação com a QDA ilustrou a diferença fundamental entre os modelos: a flexibilidade das fronteiras de decisão. Para este dataset, onde a separação já é bastante clara, as vantagens da QDA em termos de poder de classificação podem ser pequenas, mas a visualização de suas fronteiras nos ajuda a entender a estrutura não-linear que a LDA não pode capturar.