Sesión 14 B#

Modelos de Mezcla Gaussiana (GMM)#

from sklearn.mixture import GaussianMixture
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import os
ruta = os.path.join('..', 'data', 'bank_customer_data.csv')
df = pd.read_csv(ruta)
df.head()
income debt labels
0 2.985433 1.467052 0.0
1 1.661632 6.248713 1.0
2 2.131999 6.693823 1.0
3 5.851889 4.742888 2.0
4 3.404236 2.991008 0.0
df.shape
(400, 3)
df.labels.value_counts()
labels
0.0    200
1.0    150
2.0     50
Name: count, dtype: int64

1. Gaussian Mixture Model (GMM) básico#

GaussianMixture?
  • También puedes checar la documentación oficial de sklearn sobre GMM aquí.

# Modelo de mezclas Gaussianas
gmm = GaussianMixture(
    n_components=3
)
# Entrenamos
gmm.fit(df[['income', 'debt']])
GaussianMixture(n_components=3)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
# Parámetros óptimos: means_
gmm.means_[0]
array([2.96040004, 2.57742868])
# Parámetros óptimos: covariances_
gmm.covariances_
array([[[ 1.09095334, -0.21668949],
        [-0.21668949,  1.08251907]],

       [[ 0.53573118, -0.10747755],
        [-0.10747755,  0.76187159]],

       [[ 0.948484  ,  0.90614216],
        [ 0.90614216,  1.00900976]]])
# Parámetros óptimos: weights_
gmm.weights_
array([0.49736151, 0.37979719, 0.1228413 ])
from scipy.stats import multivariate_normal

# Gaussianas ajustadas
X1 = multivariate_normal(
    mean=gmm.means_[0],
    cov=gmm.covariances_[0]
)
X2 = multivariate_normal(
    mean=gmm.means_[1],
    cov=gmm.covariances_[1]
)
X3 = multivariate_normal(
    mean=gmm.means_[2],
    cov=gmm.covariances_[2]
)
#X4 = multivariate_normal(
#    mean=gmm.means_[3],
#    cov=gmm.covariances_[3]
#)
# Predicción de probabilidades
probas = gmm.predict_proba(df[['income', 'debt']])
probas
array([[9.97898701e-01, 3.63395861e-06, 2.09766539e-03],
       [1.59470132e-03, 9.98405299e-01, 1.28157116e-49],
       [4.45537550e-04, 9.99554462e-01, 1.41247255e-48],
       ...,
       [9.96186473e-01, 3.81352745e-03, 4.36364940e-11],
       [9.99985299e-01, 2.23920789e-06, 1.24613957e-05],
       [2.87390800e-01, 7.12609200e-01, 4.97269931e-23]], shape=(400, 3))
# Convertir a DataFrame
df_probas = pd.DataFrame(
    probas,
    columns=[f"componente_{i}" for i in range(3)]
)
df_probas
componente_0 componente_1 componente_2
0 0.997899 0.000004 2.097665e-03
1 0.001595 0.998405 1.281571e-49
2 0.000446 0.999554 1.412473e-48
3 0.000871 0.000003 9.991260e-01
4 0.988526 0.002157 9.317247e-03
... ... ... ...
395 0.977300 0.000057 2.264287e-02
396 0.051108 0.948892 5.911349e-29
397 0.996186 0.003814 4.363649e-11
398 0.999985 0.000002 1.246140e-05
399 0.287391 0.712609 4.972699e-23

400 rows × 3 columns

# Datos
plt.scatter(
    x=df['income'],
    y=df['debt'], 
    c=gmm.predict_proba(df[['income', 'debt']]),
    cmap='Accent',
    alpha=0.5
)
# Añadimos etiquetas a los ejes
plt.xlabel('Ingresos mensuales (x100k MXN)')
plt.ylabel('Deuda (x100k MXN)')

# Gaussiana 1
x = np.linspace(0, 8, 100)
y = np.linspace(0, 8, 100)
X, Y = np.meshgrid(x, y)
z = X1.pdf(np.dstack((X, Y)))
# Graficamos la función de densidad
plt.contour(X, Y, z, levels=10, cmap='rainbow')

# Gaussiana 2
x = np.linspace(0, 8, 100)
y = np.linspace(0, 8, 100)
X, Y = np.meshgrid(x, y)
z = X2.pdf(np.dstack((X, Y)))
# Graficamos la función de densidad
plt.contour(X, Y, z, levels=10, cmap='rainbow')

# Gaussiana 3
x = np.linspace(0, 8, 100)
y = np.linspace(0, 8, 100)
X, Y = np.meshgrid(x, y)
z = X3.pdf(np.dstack((X, Y)))
# Graficamos la función de densidad
plt.contour(X, Y, z, levels=10, cmap='rainbow')

# Gaussiana 4
#x = np.linspace(0, 8, 100)
#y = np.linspace(0, 8, 100)
#X, Y = np.meshgrid(x, y)
#z = X4.pdf(np.dstack((X, Y)))
# Graficamos la función de densidad
#plt.contour(X, Y, z, levels=10, cmap='rainbow')
/tmp/ipykernel_1189/1720985629.py:2: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored
  plt.scatter(
<matplotlib.contour.QuadContourSet at 0x79696c4edbd0>
../_images/9479a7ec64cbfab332d79184dc980e423fef0b9407a000e0d970f1a428d022af.png

2. Probar varios números de componentes y comparar BIC#

import warnings
warnings.filterwarnings('ignore')
#BIC
ks = range(1, 10)
bics = []

for k in ks:
    gmm = GaussianMixture(n_components=k)
    gmm.fit(df[['income', 'debt']])
    bics.append(gmm.bic(df[['income', 'debt']]))

list1 = list(zip(ks, bics))
list1
[(1, 3139.7023248527153),
 (2, 3047.3837113363734),
 (3, 2848.5387889567273),
 (4, 2878.8971484807275),
 (5, 2916.0991099907646),
 (6, 2946.246983381312),
 (7, 2977.954275497212),
 (8, 3006.681357865192),
 (9, 3035.3456323761566)]
min(list1, key=lambda x: x[1])
(3, 2848.5387889567273)
#AIC
aics = []
for k in ks:
    gmm = GaussianMixture(n_components=k)
    gmm.fit(df[['income', 'debt']])
    aics.append(gmm.aic(df[['income', 'debt']]))

list2 = list(zip(ks, aics))
list2
[(1, 3119.7450021171753),
 (2, 3003.4776013181854),
 (3, 2780.788837891324),
 (4, 2786.7990912971527),
 (5, 2799.482076627995),
 (6, 2809.136688817821),
 (7, 2810.809417537192),
 (8, 2819.294055008664),
 (9, 2832.147419284117)]
min(list2, key=lambda x: x[1])
(3, 2780.788837891324)
# Mostrar resultados
plt.plot(ks, bics, marker='o', label="BIC", color='purple')
plt.plot(ks, aics, marker='o', label="AIC", color='green')
plt.xlabel("Número de componentes (k)")
plt.ylabel("Valor del criterio")
plt.legend()
plt.show()
../_images/4c4ecba12e30bb601e087d8b7715bc5d7dca820894b61fa4f501ab6ac2aa5ba8.png