# **Riesgo crediticio**
##Resumen
El problema de investigación planteado consiste en estimar el score crediticio de un individuo a partir de diferentes datos que se obtienen del mismo.
Se dispone de datos para 2279856 personas residentes en la India que han solicitado un crédito. De estos individuos se consideran distintos atributos y características como ser la edad, el género, el ingreso declarado, su experiencia con créditos (instrumentada como la cantidad de meses del primer crédito obtenido), la cantidad de créditos actuales, el monto solicitado del préstamo solicitado, la cantidad de cuotas, si es un cliente de la entidad a la que se le solicita el préstamo, el lugar que reside (ciudad y estado), la proporción del préstamo solicitado sobre la garantía propuesta (ratio LTV), categoría de empleo y ocupación, entre otros.
A partir de estos datos se propone una estimación del riesgo crediticio del individuo así como una clasificación del mismo a partir de la aplicación de diversos modelos de aprendizaje supervisado.
En función de esto se generan las siguientes preguntas de investigación:
¿Cuál es la clasificación crediticia de un individuo a partir de sus atributos?
¿A que cluster pertenece un potencial cliente?
¿Cuáles son las variables explicativas del comportamiento crediticio de los solicitantes? ¿Cuáles son más influyentes?
¿Cuál es el grado de dispersión del riesgo crediticio en función del ingreso?
#Objetivos y problema comercial
Objetivo Principal:
El objetivo principal de esta investigación es estimar el riesgo crediticio y la clasificación crediticia de los solicitantes de crédito basándose en sus atributos personales y financieros.
Objetivos Secundarios:
Identificar a qué grupo o cluster pertenecen los posibles clientes con características similares.
Determinar cuáles son las variables más influyentes en el comportamiento crediticio de los solicitantes.
Evaluar el grado de dispersión del riesgo crediticio en función del ingreso de los solicitantes.
Contexto Comercial:
En un contexto comercial, esta investigación podría ser relevante para una entidad financiera, como un banco o una institución de préstamos en la India. Estas instituciones a menudo enfrentan el desafío de evaluar el riesgo crediticio de los solicitantes de préstamos, lo que influye en su decisión de aprobar o denegar una solicitud de crédito. Una evaluación precisa del riesgo crediticio es esencial para proteger los intereses de la entidad financiera y garantizar la salud de su cartera de préstamos. Además, una clasificación crediticia precisa puede ayudar a la entidad a ofrecer términos y condiciones adecuados a los solicitantes.
Problema Comercial:
El problema comercial principal que se aborda en esta investigación es la evaluación del riesgo crediticio de los solicitantes de préstamos. Los bancos y las instituciones financieras desean comprender la probabilidad de que un individuo incumpla con el pago de un préstamo. Este problema comercial puede abordarse mediante el desarrollo de modelos de aprendizaje supervisado para predecir el riesgo crediticio y clasificar a los solicitantes en categorías de riesgo, como "alto riesgo", "riesgo moderado" y "bajo riesgo". Además, se busca identificar las variables más influyentes en la decisión de otorgar crédito, lo que podría ayudar a mejorar las políticas de aprobación de préstamos.
#Hipotesis
Hipótesis Primarias:
Hipótesis Principal: Existe una relación significativa entre los atributos personales y financieros de un solicitante y su riesgo crediticio
Hipótesis Secundarias:
Hipótesis de Clusterización: Los solicitantes de crédito con características similares formarán grupos o clusters distintos, lo que sugiere la existencia de segmentos homogéneos en la población de solicitantes.
Hipótesis de Variables Influyentes: Se espera que ciertas dimensiones instrumentadas en las variables del modelo (como el historial crediticio, ingreso declarado y categoría de empleo) tengan una influencia significativa en la decisión de riesgo crediticio.
Hipótesis de Predicción de Clasificación Crediticia: Los modelos de aprendizaje supervisado, al entrenarse con datos históricos, serán capaces de predecir la clasificación crediticia de nuevos solicitantes con una precisión significativa.
Hipótesis de Mejora de Políticas de Aprobación de Préstamos: La identificación de variables clave permitirá mejorar las políticas de aprobación de préstamos, permitiendo a la entidad financiera tomar decisiones más informadas y precisas.
Hipótesis de Generalización del Modelo: El modelo desarrollado será generalizable a otros conjuntos de datos de solicitudes de crédito en la India, lo que sugiere que los patrones de comportamiento crediticio son consistentes en diferentes muestras de la población.
Hipótesis de Dispersión del Riesgo en Función del Ingreso: Se anticipa que habrá una relación observable entre el nivel de ingreso de un solicitante y el grado de dispersión del riesgo crediticio, con posiblemente una mayor dispersión en los ingresos más bajos.
#EDA
##Importación y analisis preliminar de los datos
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from google.colab import drive
import os
drive.mount('/content/gdrive')
%cd '/content/gdrive/MyDrive'
#Itero diferentes codificaciones para evitar error de cargada
codificaciones = ['utf-8', 'latin-1', 'ISO-8859-1', 'ISO-8859-15']
for codificacion in codificaciones:
try:
df = pd.read_csv('credit_data.csv', sep=',', encoding=codificacion)
break
except UnicodeDecodeError:
continue
# Consultar la cantidad de filas y columnas
num_filas, num_columnas = df.shape
print(f'Número de filas: {num_filas}')
print(f'Número de columnas: {num_columnas}')
#Definición de variables
variables_y_descripciones = [
("Age", "Represents the age of the applicant. Indicates the applicant's maturity level."),
("Gender", "Gender of the applicant."),
("Income", "The applicant's income, which is critical in assessing their ability to repay the loan."),
("Credit Score", "A score quantifying the applicant's creditworthiness based on their credit history."),
("Credit History Length", "Represents the number of months since the applicant's first credit line. Indicates the applicant's experience with credit management."),
("Number of Existing Loans", "The number of loans the applicant currently has."),
("Loan Amount", "The amount of money the applicant is requesting."),
("Loan Tenure", "The number of months the applicant wants to repay the loan over."),
("Existing Customer", "Whether the applicant is an existing customer of the finance company."),
("State", "The state in India where the applicant resides."),
("City", "The city or village in India where the applicant resides."),
("LTV Ratio", "The loan-to-value ratio, represents the ratio of the loan amount to the appraised value of the asset (typically a house). Higher LTVs can indicate higher risk."),
("Employment Profile", "General employment category of the applicant."),
("Occupation", "Specific occupation or job title of the applicant."),
("Profile Score", "A score ranging from 0 to 100 represents the overall profile of the applicant based on the actual loan repayment data. Higher values indicate better profiles.")
]
for i, (variable, descripcion) in enumerate(variables_y_descripciones, 1):
print(f"{i}. {variable}:\n {descripcion}\n")
##Gráficos y estadísticos principales (Matplot Lib)
import matplotlib.ticker as mticker
df.dtypes
Cantidad_filas = len(df.Age)
print(Cantidad_filas)
df.head(10)
df.groupby('Gender')['Loan Amount'].mean().plot(kind='bar', color='lightgreen')
plt.xlabel('Género')
plt.ylim(100000, )
plt.ylabel('Préstamo promedio')
plt.title('Préstamo promedio por género')
plt.tick_params(axis='x', labelsize=12)
plt.tick_params(axis='y', labelsize=12)
plt.show()
No se observan diferencias sustantivas en el préstamo promedio solicitado entre generos
df.groupby('Profile Score')['Loan Amount'].sum().plot(kind='line', color='lightgreen', linewidth=4)
plt.xlabel('Profile Score')
plt.ylim(100000, )
plt.ylabel('Suma de Monto solicitado')
plt.xlabel('Calificación')
plt.title('Total de préstamos solicitados por Calificación')
plt.tick_params(axis='x', labelsize=12)
plt.tick_params(axis='y', labelsize=12)
plt.show()
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(df['Profile Score'], color='lightgreen', bins=10)
ax.set_title('Histograma de Calificación')
ax.set_xlabel('Calificación del solicitante')
ax.set_ylabel('Frecuencia absoluta')
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(df['Loan Amount'], bins=20, color='lightgreen')
ax.set_title('Histograma de Monto solicitado')
ax.set_xlabel('Monto solicitado')
ax.set_ylabel('Frecuencia absoluta')
Existe una fuerte de concentración de frecuencia en los montos solicitados de mayor monto, es decir, en su mayoría los individuos solicitan el máximo posible que es de $150000
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(df['Credit Score'], bins=20, color='lightgreen')
ax.set_title('Calificación crediticia')
ax.set_xlabel('Calificación del solicitante')
ax.set_ylabel('Frecuencia absoluta')
La clasificacion del perfil del solicitante tiene máximos en la menor clasificación y en la mayor, mientras que tiene una frecuencia estable en valores intermedios.
# Crear el gráfico de barras del ingreso promedio por género
df.groupby('Age')['Loan Amount'].mean().plot(kind='bar', color='lightgreen')
# Etiquetas de ejes y título
plt.xlabel('Edad', size = 12)
plt.ylabel('Préstamo promedio', size = 12)
plt.title('Préstamo promedio solicitado por edad', size = 12)
plt.tick_params(axis='x', labelsize=8)
plt.tick_params(axis='y', labelsize=8)
plt.show()
Se puede observar que los prestamos promedios incrementan a medida que se avanza en edad.
#Gráfico de puntos de ingreso contra cantidad prestada
fig, ax = plt.subplots(figsize=(27, 6))
plt.scatter(df['Income'], df['Loan Amount'], alpha=0.8, s=1, color = "lightgreen")
plt.xlabel('Ingreso')
plt.ylabel('Monto del Préstamo',)
plt.ylim(0, 160000)
plt.title('Relación entre Ingreso y Monto del Préstamo')
Se observa un tope de monto solicitado por ingreso:
Aquellos individuos con ingreso de $10000 pueden solicitar $50000, mientras que aquellos con ingreso de $25000 pueden obtener hasta $120000 por ejemplo. A su vez, se puede observar que el monto máximo permitido es de $150000.
loan_amount_means = df.groupby('Occupation')['Loan Amount'].mean()
df.boxplot(column='Credit Score', by='Occupation', patch_artist=True,
boxprops={'linewidth': 1, 'edgecolor': 'green', 'facecolor': 'lightgreen'},
capprops={'color': 'green'}, whiskerprops = {'color': 'green'})
plt.xlabel('Ocupación')
plt.ylabel('Calificación crediticia')
whiskerprops = {'color': 'green'}
plt.xticks(rotation=45)
plt.tick_params(axis='x', labelsize=6)
plt.tick_params(axis='y', labelsize=6)
plt.show()
Se observan ingresos desde 420000 a 750000 unidades monetarias con medias superiores para trabajadores bancarios, ingenieros de software y profesores, mientras que la ocupación con menor media es para estudiantes, diseñadores gráficos y consultores independientes.
existing_customer_counts = df['Existing Customer'].value_counts()
fig, ax = plt.subplots(figsize=(8, 8))
ax.pie(existing_customer_counts, labels=existing_customer_counts.index,
autopct='%1.1f%%', startangle=90, colors = ['#F08080', '#5CB85C'])
ax.set_aspect('equal')
plt.title('Distribución de Clientes Existentes vs. Nuevos Clientes')
plt.legend(fontsize=12)
plt.show()
Se observa que casi dos tercios de los solicitantes no son clientes existentes, por lo que se dificulta el conocimiento de pago de los clientes en profundidad.
##Gráficos Seaborn
sns.set(rc={'axes.labelsize': 8, 'xtick.labelsize': 8, 'ytick.labelsize': 8})
apg = sns.FacetGrid(df, row = "Gender", col = "Existing Customer", aspect=2 )
apg.map_dataframe(sns.scatterplot, x="Income", y="Profile Score", s=4)
apg.set_axis_labels("Ingreso", "Monto del Préstamo")
apg.add_legend()
plt.show()
Se observa que los clientes existentes, independiente de su género e ingreso, tienden a solicitar un préstamo superior, mientras que en clientes no existentes se observa una mayor dispersión de los datos.
colores = {"No": "rosybrown", "Yes": "lightgreen"}
g = sns.catplot(data=df, kind='violin', x='Gender', y='Loan Amount', hue='Existing Customer', split=True, palette=colores, aspect=2)
g.set_axis_labels("Género", "Monto del préstamo")
plt.title('Distribución de Monto del préstamo por género y tipo de cliente')
plt.show()
colores = {"No": "rosybrown", "Yes": "lightgreen"}
# Crear un gráfico de violín dividido por género
g = sns.catplot(data=df, kind='violin', x='Gender', y='Profile Score', hue='Existing Customer', split=True, palette=colores, aspect=2)
g.set_axis_labels("Género", "Monto solicitado del préstamo")
plt.title('Distribución de calificación del perfil por género y tipo de cliente')
plt.show()
g = sns.displot(data=df, kind='hist', x='Credit Score', y='Profile Score', hue='Existing Customer', aspect=1)
g.set_axis_labels("Clasificación crediticia", "Calificacón del perfil")
plt.title('Distribución de calificación del perfil en función de clasificación crediticia')
plt.show()
g.set(xlim=(0,1000), ylim=(0,100))
g = sns.histplot(data=df, y="Number of Existing Loans")
g.set_xticklabels(g.get_xticks(), size=12)
g.set_yticklabels(g.get_yticks(), size=12)
plt.ylabel('Cantidad de préstamos del solicitante', size=12)
plt.xlabel('Cantidad de préstamos solicitados', size=12)
plt.title('Cantidad de préstamos solicitados según los préstamos actuales del cliente')
plt.show()
Existe una cantidad importante de individuos con más de 1 préstamos solicitado, lo cual impactaría, hipoteticamente, sobre la capacidad de pago del préstamo incrementando el riesgo.
plt.figure(figsize=(8, 6))
sns.displot(data=df, kind = 'hist', x='Credit Score', aspect=2)
plt.xlabel('Clasificación crediticia')
plt.ylabel('Cantidad de préstamos')
plt.title('Cantidad de préstamos solicitados según clasificación crediticia')
plt.show()
La cantidad de préstamos solicitados alcanza picos importantes en los individuos con peor y mejor clasificación crediticia, mientras que se observa una distribución homogenea entre los individuos intermedios.
cantidad = df['Profile Score'].value_counts().reset_index()
sns.displot(data=df, kind = 'hist', x='Profile Score', hue = 'Occupation', multiple="stack", height=20, palette='pastel')
plt.xlabel('Clasificación del perfil', size = 12)
plt.ylabel('Cantidad de préstamos', size = 12)
plt.title('Clasifcación del perfil por ocupación', size = 12)
plt.show()
g = sns.histplot(data=df, y="Loan Tenure")
g.set_xticklabels(g.get_xticks(), size=12)
g.set_yticklabels(g.get_yticks(), size=12)
g.xaxis.set_major_formatter('{:.0f}'.format)
g.yaxis.set_major_formatter('{:.0f}'.format)
plt.ylabel('Cantidad de cuotas solicitadas', size=12)
plt.xlabel('Cantidad de préstamos', size = 12)
plt.title('Cantidad de préstamos según cuotas solicitadas')
plt.show()
df.groupby('Gender')['Credit Score'].mean().plot(kind='bar', color='lightgreen')
plt.xlabel('Género')
plt.ylim(200, )
plt.ylabel('Clasificación crediticia promedio')
plt.title('Clasificación crediticia promedio por género')
plt.tick_params(axis='x', labelsize=12)
plt.tick_params(axis='y', labelsize=12)
plt.show()
No se observar grandes diferencias entre el riesgo crediticio entre géneros, los tres considerados estan cercanos al 580.
# Crear el gráfico de barras del ingreso promedio por género
df.groupby('Age')['Credit Score'].mean().plot(kind='bar', color='lightgreen')
# Etiquetas de ejes y título
plt.xlabel('Edad', size = 12)
plt.ylabel('Clasificación crediticia promedio', size = 12)
plt.title('Clasificación crediticia promedio por edad', size = 12)
plt.tick_params(axis='x', labelsize=8)
plt.tick_params(axis='y', labelsize=8)
plt.show()
Se observa una distribución bastante homogenea por edad, aunque existe una leve correlación positiva entre edad y clasificación crediticia.
colores = {"No": "rosybrown", "Yes": "lightgreen"}
g = sns.catplot(data=df, kind='violin', x='Gender', y='Credit Score', hue='Existing Customer', split=True, palette=colores, aspect=2)
g.set_axis_labels("Género", "Riesgo crediticio")
plt.title('Distribución de riesgo crediticio por género y tipo de cliente')
plt.show()
Se observa que los clientes existentes tienen en promedio una mayor calificación crediticia, con una mayor dispersión para aquellos que se identifican con un genero no binario.
loan_amount_means = df.groupby('Occupation')['Credit Score'].mean()
df.boxplot(column='Credit Score', by='Occupation', patch_artist=True,
boxprops={'linewidth': 1, 'edgecolor': 'green', 'facecolor': 'lightgreen'},
capprops={'color': 'green'}, whiskerprops = {'color': 'green'})
plt.xlabel('Ocupación')
plt.ylabel('Calificación crediticia')
whiskerprops = {'color': 'green'}
plt.xticks(rotation=45)
plt.tick_params(axis='x', labelsize=6)
plt.tick_params(axis='y', labelsize=6)
plt.show()
average_credit_score_by_income = df.groupby('Income')['Credit Score'].mean().reset_index()
# Imprimir los resultados para verificar
print(average_credit_score_by_income)
# Crear un gráfico de barras
plt.figure(figsize=(10, 6))
plt.bar(average_credit_score_by_income['Income'], average_credit_score_by_income['Credit Score'], color='green')
plt.xlabel('Nivel de Ingreso')
plt.ylabel('Puntuación Crediticia Promedio')
plt.title('Puntuación Crediticia Promedio por Nivel de Ingreso')
plt.xticks(rotation=45) # Rotar las etiquetas del eje X para una mejor visualización
# Mostrar el gráfico
plt.show()
#Genero un mapa de calor de la matriz de correlación
matriz_correlacion = df.corr()
plt.figure(figsize=(10, 10))
sns.heatmap(matriz_correlacion, annot=True, cmap='coolwarm', linewidths=0.1)
annot_kws = {"size": 0.8}
plt.title('Mapa de Calor de Correlación')
plt.show()
Se observa una correlación importante entre la clasificación crediticia y la clasifiación del perfil, así como con la cantidad de cuotas solicitadas, la cantidad de préstamos actuales, todas de forma positiva. La única variable que se correlaciona negativamente es el ratio LTV.
##Estadísticos principales
#Contar la cantidad de nulos por variable
df.isnull().sum()
df.describe()
#Distintos valores de Occupation
unique_values = df['Occupation'].unique()
num_unique_values = len(unique_values)
print(unique_values)
print(num_unique_values)
#Distintos valores de Occupation
unique_values = df['Employment Profile'].unique()
num_unique_values = len(unique_values)
print(unique_values)
print(num_unique_values)
#Distintos valores de Occupation
unique_values = df['State'].unique()
num_unique_values = len(unique_values)
print(unique_values)
print(num_unique_values)
#Reemplazo las ocupaciones vacías por "Desconocido"
df['Occupation'].fillna('Unknown', inplace=True)
#Valores distintos por variable
df.nunique()
average_income_by_city = df.groupby('State')['Income'].mean().reset_index()
print(average_income_by_city)
average_income_by_occupation = df.groupby('Occupation')['Income'].mean().reset_index()
print(average_income_by_occupation)
average_credit_score_by_occupation = df.groupby('Occupation')['Credit Score'].mean().reset_index()
print(average_credit_score_by_occupation)
average_credit_score_by_state = df.groupby('State')['Credit Score'].mean().reset_index()
print(average_credit_score_by_state)
average_credit_score_by_age = df.groupby('Age')['Credit Score'].mean().reset_index()
print(average_credit_score_by_age)
average_income_by_credit_score = df.groupby('Employment Profile')['Credit Score'].mean().reset_index()
print(average_income_by_credit_score)
#Algoritmos de Machine Learning
##modelo OLS
Se plantea la hipotesis de que la clasificación crediticia se explica en función de las variables Edad, Género (convertida en binaria), Ingreso, Clasificación crediticia, Historial crediticio, Cantidad de prestamos actuales, Monto del préstamo solicitado, Duración del préstamo solicitado, Ratio LTV, Perfil Laboral y Profesión.
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import statsmodels.api as sm
#Se convierte en binarias las variables Genero, Cliente existente, Perfil de empleo y Ocupación, considerando un valor fijo como "constante" o variable de control para evitar problemas de multicolinealidad exacta.
df_ols = df.copy()
df_ols = pd.get_dummies(df, columns=['Gender', 'Existing Customer', 'Employment Profile', 'Occupation'], drop_first=True)
df_ols.get
print(df_ols.columns)
# Definir las variables independientes (X) y la variable dependiente (y)
X = df_ols[['Profile Score', 'Age', 'Income', 'Credit History Length',
'Number of Existing Loans', 'Loan Amount', 'Loan Tenure', 'LTV Ratio',
'Gender_Male', 'Gender_Other', 'Employment Profile_Salaried',
'Employment Profile_Self-Employed', 'Employment Profile_Student',
'Employment Profile_Unemployed', 'Occupation_Business Owner',
'Occupation_Civil Servant', 'Occupation_Contractor',
'Occupation_Doctor', 'Occupation_Farmer', 'Occupation_Graphic Designer',
'Occupation_Independent Consultant', 'Occupation_Photographer',
'Occupation_Shopkeeper', 'Occupation_Software Engineer',
'Occupation_Student', 'Occupation_Teacher', 'Occupation_Writer']]
y = df_ols['Credit Score']
X = sm.add_constant(X)
# Ajustar el modelo de regresión lineal utilizando statsmodels
model = sm.OLS(y, X).fit()
# Obtener los resultados del modelo, incluyendo coeficientes y p-valores
results = model.summary()
# Imprimir los resultados
print(results)
# Dividir el conjunto de datos en entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Crear un modelo de regresión lineal
model = LinearRegression()
# Entrenar el modelo con los datos de entrenamiento
model.fit(X_train, y_train)
# Realizar predicciones en el conjunto de prueba
y_pred = model.predict(X_test)
residuals = y_test - y_pred
# Evaluar el modelo
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f"Mean Squared Error: {mse}")
print(f"R-squared (R2) Score: {r2}")
print("Normalidad de los residuos")
sns.histplot(residuals, kde=True)
plt.xlabel("Residuos")
plt.ylabel("Frecuencia")
plt.title("Histograma de Residuos")
plt.show()
##K-Means
En este caso se procura identificar clusters del nivel de riesgo contra el ingreso y contra la edad de los individuos.
Se propone el método del codo para identificar la cantidad óptima de medias
###Wealth
#Clusterización de Credit Score, contra un proxy de Riqueza
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
data = df[["Income", "LTV Ratio"]]
#Estandarización de las variables para que tengan media 0 y varianza 1
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)
#Método del codo
wcss = []
for i in range(1, 11):
kmeans = KMeans(n_clusters=i, init='k-means++', max_iter=300, n_init=10, random_state=0)
kmeans.fit(data_scaled)
wcss.append(kmeans.inertia_)
plt.plot(range(1, 11), wcss)
plt.title('Método del Codo')
plt.xlabel('Número de clusters')
plt.ylabel('Inercia')
plt.show()
print("Gráfico de cluster por variables proxys de riqueza")
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10, random_state=0)
kmeans.fit(data_scaled)
df['Cluster Wealth'] = kmeans.labels_
plt.scatter(data_scaled[:, 0], data_scaled[:, 1], c=kmeans.labels_, cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=300, c='red')
plt.xlabel('Income')
plt.ylabel('LTV')
plt.title('Clustering de Credit Score vs Income and LTV Ratio')
plt.show()
###Profile Score
#Clusterización de Credit Score y Profile Score
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
data = df[["Credit Score", "Profile Score"]]
#Estandarización de las variables para que tengan media 0 y varianza 1
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)
#Método del codo
wcss = []
for i in range(1, 11):
kmeans = KMeans(n_clusters=i, init='k-means++', max_iter=300, n_init=10, random_state=0)
kmeans.fit(data_scaled)
wcss.append(kmeans.inertia_)
plt.plot(range(1, 11), wcss)
plt.title('Método del Codo')
plt.xlabel('Número de clusters')
plt.ylabel('Inercia')
plt.show()
print("Gráfico de cluster de Credit Score vs Profile Score")
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10, random_state=0)
kmeans.fit(data_scaled)
df['Cluster Profile-Credit'] = kmeans.labels_
plt.scatter(data_scaled[:, 0], data_scaled[:, 1], c=kmeans.labels_, cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=300, c='red')
plt.xlabel('Credit Score')
plt.ylabel('Profile Score')
plt.title('Clustering de Credit Score vs Income and LTV Ratio')
plt.show()
##Transformación de variables
Credit_bins = [0, 500, 600, 700, 851]
Credit_labels = ["Riesgo Alto", "Riesgo medio-alto", "Riesgo medio-bajo", "Riesgo bajo"]
df['Credit_Category'] = pd.cut(df['Credit Score'], bins=Credit_bins, labels=Credit_labels, right=False)
df.head(10)
Profile_bins = [0, 25, 50, 75, 100]
Profile_labels = ["Riesgo Alto", "Riesgo medio-alto", "Riesgo medio-bajo", "Riesgo bajo"]
df['Profile_Category'] = pd.cut(df['Profile Score'], bins=Profile_bins, labels=Profile_labels, right=False)
df.head(10)
Age_bins = [18, 25, 35, 45, 55, 65, 99]
Age_labels = ["De 18 a 24", "De 25 a 34", "De 35 a 44", "De 45 a 54", "De 55 a 64", "Mayor a 65"]
df['Age_Category'] = pd.cut(df['Age'], bins=Age_bins, labels=Age_labels, right=False)
df.head(10)
Income_bins = [9000, 39999, 59999, 79999, 99999, 149999, 299999]
Income_labels = ["Ingreso bajo", "Ingreso Medio-Bajo", "Ingreso Medio", "Ingreso Medio Alto", "Ingreso Alto", "Ingreso Muy Alto"]
df['Income_Category'] = pd.cut(df['Income'], bins=Income_bins, labels=Income_labels, right=False)
df.head(10)
# Variable Credit_Category
df['Credit_Category'] = pd.cut(df['Credit Score'], bins=Credit_bins, labels=Credit_labels, right=False)
df['Credit_Category_Code'] = df['Credit_Category'].cat.codes
# Variable Age_Category
df['Age_Category'] = pd.cut(df['Age'], bins=Age_bins, labels=Age_labels, right=False)
df['Age_Category_Code'] = df['Age_Category'].cat.codes
# Variable Income_Category
df['Income_Category'] = pd.cut(df['Income'], bins=Income_bins, labels=Income_labels, right=False)
df['Income_Category_Code'] = df['Income_Category'].cat.codes
# Variable Profile_Category
df['Profile_Category'] = pd.cut(df['Profile Score'], bins=Profile_bins, labels=Profile_labels, right=False)
df['Profile_Category_Code'] = df['Profile_Category'].cat.codes
viz_Credit_Category = df.groupby('Credit_Category')['Credit_Category_Code'].mean().reset_index()
viz_Age_Category = df.groupby('Age_Category')['Age_Category_Code'].mean().reset_index()
viz_Income_Category = df.groupby('Income_Category')['Income_Category_Code'].mean().reset_index()
viz_Profile_Category = df.groupby('Profile_Category')['Profile_Category_Code'].mean().reset_index()
print(viz_Credit_Category, viz_Income_Category, viz_Age_Category, viz_Profile_Category)
average_credit_score_by_ageCategory = df.groupby('Age_Category')['Credit Score'].mean().reset_index()
print(average_credit_score_by_ageCategory)
average_credit_score_by_IncomeCategory = df.groupby('Income_Category')['Credit Score'].mean().reset_index()
print(average_credit_score_by_IncomeCategory)
average_credit_score_by_LTV_RATIO = df.groupby('LTV Ratio')['Credit Score'].mean().reset_index()
print(average_credit_score_by_LTV_RATIO)
average_credit_score_by_WC = df.groupby('Cluster Wealth')['Credit Score'].mean().reset_index()
average_income_by_WC = df.groupby('Cluster Wealth')['Income'].mean().reset_index()
average_LTV_by_WC = df.groupby('Cluster Wealth')['LTV Ratio'].mean().reset_index()
# Crear una figura con subgráficos
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(15, 5))
# Graficar las medias de Credit Score por cluster de riqueza
axes[0].bar(average_credit_score_by_WC['Cluster Wealth'], average_credit_score_by_WC['Credit Score'])
axes[0].set_title('Promedio de Credit Score por Cluster de Riqueza')
axes[0].set_xlabel('Cluster Wealth')
axes[0].set_ylabel('Promedio de Credit Score')
# Graficar las medias de Income por cluster de riqueza
axes[1].bar(average_income_by_WC['Cluster Wealth'], average_income_by_WC['Income'])
axes[1].set_title('Promedio de Income por Cluster de Riqueza')
axes[1].set_xlabel('Cluster Wealth')
axes[1].set_ylabel('Promedio de Income')
# Graficar las medias de LTV Ratio por cluster de riqueza
axes[2].bar(average_LTV_by_WC['Cluster Wealth'], average_LTV_by_WC['LTV Ratio'])
axes[2].set_title('Promedio de LTV Ratio por Cluster de Riqueza')
axes[2].set_xlabel('Cluster Wealth')
axes[2].set_ylabel('Promedio de LTV Ratio')
plt.tight_layout() # Ajustar el espacio entre los subgráficos
plt.show()
average_credit_score_by_PC = df.groupby('Cluster Profile-Credit')['Credit Score'].mean().reset_index()
average_ps_by_PC = df.groupby('Cluster Profile-Credit')['Profile Score'].mean().reset_index()
average_income_by_PC = df.groupby('Cluster Profile-Credit')['Income'].mean().reset_index()
average_LTV_by_PC = df.groupby('Cluster Profile-Credit')['LTV Ratio'].mean().reset_index()
# Crear una figura con subgráficos
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 8))
# Graficar el promedio de Credit Score por cluster "Cluster Profile-Credit"
axes[0, 0].bar(average_credit_score_by_PC['Cluster Profile-Credit'], average_credit_score_by_PC['Credit Score'])
axes[0, 0].set_title('Promedio de Credit Score por Cluster Profile-Credit')
axes[0, 0].set_xlabel('Cluster Profile-Credit')
axes[0, 0].set_ylabel('Promedio de Credit Score')
# Graficar el promedio de Profile Score por cluster "Cluster Profile-Credit"
axes[0, 1].bar(average_ps_by_PC['Cluster Profile-Credit'], average_ps_by_PC['Profile Score'])
axes[0, 1].set_title('Promedio de Profile Score por Cluster Profile-Credit')
axes[0, 1].set_xlabel('Cluster Profile-Credit')
axes[0, 1].set_ylabel('Promedio de Profile Score')
# Graficar el promedio de Income por cluster "Cluster Profile-Credit"
axes[1, 0].bar(average_income_by_PC['Cluster Profile-Credit'], average_income_by_PC['Income'])
axes[1, 0].set_title('Promedio de Income por Cluster Profile-Credit')
axes[1, 0].set_xlabel('Cluster Profile-Credit')
axes[1, 0].set_ylabel('Promedio de Income')
# Graficar el promedio de LTV Ratio por cluster "Cluster Profile-Credit"
axes[1, 1].bar(average_LTV_by_PC['Cluster Profile-Credit'], average_LTV_by_PC['LTV Ratio'])
axes[1, 1].set_title('Promedio de LTV Ratio por Cluster Profile-Credit')
axes[1, 1].set_xlabel('Cluster Profile-Credit')
axes[1, 1].set_ylabel('Promedio de LTV Ratio')
plt.tight_layout() # Ajustar el espacio entre los subgráficos
plt.show()
##Arboles de clasificación
###Modelo 1: Noel y Wealth
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
from sklearn.metrics import confusion_matrix
X = df[["Number of Existing Loans", "Cluster Wealth"]]
y = df["Credit_Category"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=5)
model = DecisionTreeClassifier(max_depth=3)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.figure(figsize=(30, 6))
plot_tree(model, feature_names=X.columns, class_names=model.classes_, filled=True, rounded=True)
plt.show()
confusion = confusion_matrix(y_test, y_pred)
# Crear una figura para el gráfico
plt.figure(figsize=(8, 6))
# Usar seaborn para generar un mapa de calor
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
# Configurar etiquetas de los ejes y título
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
# Añadir etiquetas de las clases en los ejes
class_names = ["Clase 0", "Clase 1", "Clase 2", "Clase 3"] # Reemplaza con las etiquetas de tus clases
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
###Age, Income y LTV
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
X = df[["Age", "Income", "LTV Ratio"]]
y = df["Credit_Category"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=5)
model = DecisionTreeClassifier()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
confusion = confusion_matrix(y_test, y_pred)
# Crear una figura para el gráfico
plt.figure(figsize=(8, 6))
# Usar seaborn para generar un mapa de calor
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
# Configurar etiquetas de los ejes y título
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
# Añadir etiquetas de las clases en los ejes
class_names = ["Clase 0", "Clase 1", "Clase 2", "Clase 3"] # Reemplaza con las etiquetas de tus clases
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
###Clusters
X = df[["Cluster Profile-Credit", "Cluster Wealth"]]
y = df["Credit_Category"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=5)
model = DecisionTreeClassifier(max_depth=5)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.figure(figsize=(30, 6))
plot_tree(model, feature_names=X.columns, class_names=model.classes_, filled=True, rounded=True)
plt.show()
confusion = confusion_matrix(y_test, y_pred)
# Crear una figura para el gráfico
plt.figure(figsize=(8, 6))
# Usar seaborn para generar un mapa de calor
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
# Configurar etiquetas de los ejes y título
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
# Añadir etiquetas de las clases en los ejes
class_names = ["Riesgo alto", "Riesgo bajo", "Riesgo medio-alto", "Riesgo medio-bajo"] # Reemplaza con las etiquetas de tus clases
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
##K-Nearest Neighbors
###Income y LTV Ratio
A partir del analisis que se desarrolla a continuación podríamos determinar que este modelo es underfitting, debido a que tiene una baja precisión. Por tanto, si bien las variables proxys de riqueza parecen tener capacidad explicativa para clusterizar las categorías crediticias, no son suficientes ni completamente abarcativas.
from sklearn.neighbors import KNeighborsClassifier
from mlxtend.plotting import plot_decision_regions
X = df[['Income', 'LTV Ratio']]
y = df['Credit_Category']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
# Calcular la matriz de confusión
confusion = confusion_matrix(y_test, y_pred)
# Crear una figura para el gráfico
plt.figure(figsize=(8, 6))
# Usar seaborn para generar un mapa de calor
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
# Configurar etiquetas de los ejes y título
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
# Añadir etiquetas de las clases en los ejes
class_names = ["Clase 0", "Clase 1", "Clase 2", "Clase 3"] # Reemplaza con las etiquetas de tus clases
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
# Mostrar la exactitud y el informe de clasificación
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
# Mostrar el gráfico
plt.show()
###Income y Profile Score
Al igual que en el modelo anterior, podríamos determinar que este modelo es underfitting, debido a que tiene una precisión de tan solo el 56%. Deberían incluirse otras variables para poder agrupar la categoría crediticia de un individuo.
from sklearn.neighbors import KNeighborsClassifier
from mlxtend.plotting import plot_decision_regions
X = df[['Income', 'Profile Score']]
y = df['Credit_Category_Code']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Crear y entrenar el modelo KNN
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
# Predicciones en el conjunto de prueba
y_pred = model.predict(X_test)
# Evaluar el modelo
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
# Convertir las series pandas a matrices numpy
X_train_np = X_train.to_numpy()
y_train_np = y_train.to_numpy()
# Generar el gráfico de regiones de decisión
plot_decision_regions(X_train_np, y_train_np, clf=model, legend=2)
plt.xlabel('Income')
plt.ylabel('Profile Score')
plt.title('Regiones de Decisión del Modelo KNN')
plt.show()
confusion = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
class_names = ["Riesgo alto", "Riesgo bajo", "Riesgo medio-alto", "Riesgo medio-bajo"]
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
### Modelo 2: Number of Existing Loans and Income
La inclusión de la cantidad de préstamos existentes (previos) es determinante a la hora de explicar el comportamiento de la clasificación crediticia. Llegando, de esta forma al 86% y 88% al considerarlo junto a un proxy de riqueza, como son ingreso y el ratio LTV respectivamente. *Un detalle no menor es que aquellos individuos mal clasificados son de una categoría contigua a la especificada. Es decir, si alguien es de riesgo alto, no es clasificada como baja y viceversa, lo que disminuye el riesgo del prestador. *
from sklearn.neighbors import KNeighborsClassifier
X = df[['Number of Existing Loans']]
y = df['Credit_Category_Code']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
report = classification_report(y_test, y_pred)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
# Convertir las series pandas a matrices numpy
X_train_np = X_train.to_numpy()
y_train_np = y_train.to_numpy()
# Generar el gráfico de regiones de decisión
plot_decision_regions(X_train_np, y_train_np, clf=model, legend=2)
plt.xlabel('Number of Existing Loans')
plt.ylabel('Credit Category')
plt.title('Regiones de Decisión del Modelo KNN')
plt.show()
confusion = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
class_names = ["Riesgo alto", "Riesgo bajo", "Riesgo medio-alto", "Riesgo medio-bajo"]
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
X = df[['Income', 'Number of Existing Loans']]
y = df['Credit_Category_Code']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Crear y entrenar el modelo KNN
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
# Predicciones en el conjunto de prueba
y_pred = model.predict(X_test)
# Evaluar el modelo
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
# Convertir las series pandas a matrices numpy
X_train_np = X_train.to_numpy()
y_train_np = y_train.to_numpy()
# Generar el gráfico de regiones de decisión
plot_decision_regions(X_train_np, y_train_np, clf=model, legend=2)
plt.xlabel('Income')
plt.ylabel('Number of Existing Loans')
plt.title('Regiones de Decisión del Modelo KNN')
plt.show()
confusion = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
class_names = ["Riesgo alto", "Riesgo bajo", "Riesgo medio-alto", "Riesgo medio-bajo"]
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
###Number of Existing Loans and LTV Ratio
X = df[['Number of Existing Loans']]
y = df['Credit_Category']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Crear y entrenar el modelo KNN
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
# Predicciones en el conjunto de prueba
y_pred = model.predict(X_test)
# Evaluar el modelo
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.scatter(X_test, y_test, c='blue', label='Real')
plt.scatter(X_test, y_pred, c='red', label='Predicción')
plt.xlabel('NOEL')
plt.ylabel('Credit Category')
plt.legend()
plt.show()
X = df[[ 'LTV Ratio', 'Number of Existing Loans']]
y = df['Credit_Category_Code']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Crear y entrenar el modelo KNN
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
# Predicciones en el conjunto de prueba
y_pred = model.predict(X_test)
# Evaluar el modelo
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)
# Convertir las series pandas a matrices numpy
X_train_np = X_train.to_numpy()
y_train_np = y_train.to_numpy()
# Generar el gráfico de regiones de decisión
plot_decision_regions(X_train_np, y_train_np, clf=model, legend=2)
plt.xlabel('LTV Ratio')
plt.ylabel('Number of Existing Loans')
plt.title('Regiones de Decisión del Modelo KNN')
plt.show()
confusion = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(confusion, annot=True, fmt="d", cmap="Blues", linewidths=0.5, cbar=False)
plt.xlabel("Predicción")
plt.ylabel("Etiqueta Real")
plt.title("Matriz de Confusión")
class_names = ["Riesgo alto", "Riesgo bajo", "Riesgo medio-alto", "Riesgo medio-bajo"]
tick_marks = [0.5, 1.5, 2.5, 3.5] # Posiciones de las marcas en los ejes
plt.xticks(tick_marks, class_names, rotation=0)
plt.yticks(tick_marks, class_names)
print("Exactitud del modelo:", accuracy)
print("Informe de clasificación:\n", report)
plt.show()
##Modelo 3: Reducción de la dimensionalidad
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
# Selecciona las variables numéricas para aplicar PCA
features = df_ols[['Profile Score', 'Age', 'Income', 'Credit History Length',
'Number of Existing Loans', 'Loan Amount', 'Loan Tenure', 'LTV Ratio',
'Gender_Male', 'Gender_Other', 'Employment Profile_Salaried',
'Employment Profile_Self-Employed', 'Employment Profile_Student',
'Employment Profile_Unemployed']]
# Escala las variables numéricas
scaler = StandardScaler()
scaled_features = scaler.fit_transform(features)
# Aplica PCA para reducir la dimensionalidad
pca = PCA(n_components=14) # Selecciona el número de componentes principales deseado
pca_result = pca.fit_transform(scaled_features)
explained_variance_ratio = pca.explained_variance_ratio_
cumulative_variance = explained_variance_ratio.cumsum()
# Grafica la varianza explicada acumulativa
import matplotlib.pyplot as plt
plt.plot(range(1, len(cumulative_variance) + 1), cumulative_variance, marker='o', linestyle='--')
plt.xlabel('Número de Componentes Principales')
plt.ylabel('Varianza Ac(umulativa Explicada')
plt.show()
variance_explained = pca.explained_variance_ratio_
cumulative_variance_explained = variance_explained.cumsum()
result_df = pd.DataFrame({
"Componente": range(1, len(variance_explained) + 1),
"Varianza Explicada": variance_explained
})
# Sumar la varianza explicada acumulada
result_df["Varianza Acumulada"] = result_df["Varianza Explicada"].cumsum()
# Imprimir el DataFrame
print(result_df)
import statsmodels.api as sm
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# Realizar el PCA
pca = PCA(n_components=14)
X_pca = pca.fit_transform(scaled_features)
# Crear un DataFrame con los componentes principales
df_pca = pd.DataFrame(data=X_pca, columns=[f"PC{i}" for i in range(1, 15)])
# Agregar las variables dependientes al DataFrame PCA
df_pca['Credit Score'] = df['Credit Score']
# Dividir el conjunto de datos en entrenamiento y prueba
X = df_pca.drop(columns=['Credit Score'])
y = df_pca['Credit Score']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Crear un modelo de regresión lineal
model = LinearRegression()
model.fit(X_train, y_train)
# Realizar predicciones en el conjunto de prueba
y_pred = model.predict(X_test)
# Evaluar el modelo
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print("Resultados del modelo de regresión lineal:")
print(f"Mean Squared Error: {mse}")
print(f"R-squared (R2) Score: {r2}")
print(f"Error Absoluto Medio (MAE): {mae}")
# Normalidad de los residuos
residuals = y_test - y_pred
print("\nNormalidad de los residuos:")
sns.histplot(residuals, kde=True)
plt.xlabel("Residuos")
plt.ylabel("Frecuencia")
plt.title("Histograma de Residuos")
plt.show()
Mean Squared Error (MSE) indoca el promedio de los errores cuadrados entre las predicciones y los valores reales. Un valor bajo de MSE generalmente es una señal de un buen ajuste del modelo a los datos. En este caso, el MSE es relativamente bajo, lo que sugiere que el modelo tiene una buena capacidad para predecir los valores reales.
R-cuadrado (R^2) indica que aproximadamente el 98.99% de la variabilidad en la variable dependiente (objetivo) se explica por el modelo. Un valor de R^2 cercano a 1 es una señal de que el modelo se ajusta bien a los datos. En este caso se podría sospechar sobre overfitting del modelo, por lo que posteriormente se desarrollará una partición de los datos para poder investigar sobre esto con mayor profundidad.
El Error Absoluto Medio (MAE) es de 14.08, lo que indica el promedio de las diferencias absolutas entre las predicciones y los valores reales. Un MAE bajo también sugiere que el modelo está haciendo buenas predicciones.
#Validación cruzada
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores_mae = -cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=kf)
scores_mse = -cross_val_score(model, X, y, scoring='neg_mean_squared_error', cv=kf)
scores_r2 = cross_val_score(model, X, y, scoring='r2', cv=kf)
mean_mae = np.mean(scores_mae)
mean_mse = np.mean(scores_mse)
mean_r2 = np.mean(scores_r2)
results = pd.DataFrame({'MAE': scores_mae, 'MSE': scores_mse, 'R^2': scores_r2})
print("Resultados de Validación Cruzada:")
print(results)
# Creo un gráfico de barras para comparar las métricas
metrics = ['MAE', 'MSE', 'R^2']
mean_scores = [mean_mae, mean_mse, mean_r2]
fig, axes = plt.subplots(3, 1, figsize=(8, 12))
# Gráfico para MAE
axes[0].bar(range(1, len(scores_mae) + 1), scores_mae)
axes[0].set_ylabel('MAE')
axes[0].set_title('Valores de MAE en Validación Cruzada')
# Gráfico para MSE
axes[1].bar(range(1, len(scores_mse) + 1), scores_mse)
axes[1].set_ylabel('MSE')
axes[1].set_title('Valores de MSE en Validación Cruzada')
# Gráfico para R^2
axes[2].bar(range(1, len(scores_r2) + 1), scores_r2)
axes[2].set_xlabel('Partición de Validación Cruzada')
axes[2].set_ylabel('R^2')
axes[2].set_title('Valores de R^2 en Validación Cruzada')
plt.tight_layout()
plt.show()