{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.12"},"colab":{"provenance":[]},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":50160,"databundleVersionId":7921029,"sourceType":"competition"},{"sourceId":10325142,"sourceType":"datasetVersion","datasetId":6392912}],"dockerImageVersionId":30823,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Preprocesamiento y modelo","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport polars as pl\nimport os\nimport joblib\nprint(\"listo\")\nROOT = '/kaggle/input/home-credit-credit-risk-model-stability'\n","metadata":{"id":"vNxGql7IH42m","outputId":"31966a1a-76a4-4a7b-991b-3c60f9fae851","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.761468Z","iopub.execute_input":"2024-12-29T22:25:58.761900Z","iopub.status.idle":"2024-12-29T22:25:58.766458Z","shell.execute_reply.started":"2024-12-29T22:25:58.761869Z","shell.execute_reply":"2024-12-29T22:25:58.765462Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Preprocesamiento de los datos","metadata":{}},{"cell_type":"code","source":"class Importador:\n    # Clase que importa datos\n    def __init__(self, directory, dataframes_nombres):\n        #directory: directorio de datos\n        #dataframes_nombres: diccionario con los nombres de los data frames\n        self.directory = directory\n        self.dataframes_nombres = dataframes_nombres\n        self.dataframes = {}\n\n    def from_csv(self):\n        # Lectura de archivos utilizando csv\n        for df_name, file_names in self.dataframes_nombres.items():\n            try:\n                if len(file_names) > 1:\n                    dfs = []\n                    for file_name in file_names:\n                        file_path = os.path.join(self.directory, file_name+'.csv')\n                        dfs.append(pl.read_csv(file_path))\n                    self.dataframes[df_name] = pl.concat(dfs, how='vertical_relaxed')\n                else:\n                    file_path = os.path.join(self.directory, file_names[0]+'.csv')\n                    self.dataframes[df_name] = pl.read_csv(file_path)\n            except FileNotFoundError:\n                print(f\"Error: No se pudo encontrar el arcivo con nombre {df_name}\")\n            except Exception as e:\n              print(f\"Ocurrio un error al procesar {df_name}: {e}\")\n        return self.dataframes\n\n    def from_parquet(self):\n        # Lectura de archivos optimizada para el uso de Parquets\n        depth0 = ['train_static_0', 'train_static_cb','base','test_static_0','test_static_cb'] #tablas con profundidad cero\n        for df_name, file_names in self.dataframes_nombres.items():\n            try:\n                if len(file_names) > 1:\n                    dfs = []\n                    for file_name in file_names:\n                        file_path = os.path.join(self.directory, file_name+'.parquet')\n                        temp = pl.read_parquet(file_path)\n                        temp = Preprocesamiento.casteo_columnas(temp)\n                        if df_name not in depth0:\n                            temp = temp.group_by(\"case_id\").agg(Agregaciones.get_exprs(temp))\n                        dfs.append(temp)\n                    self.dataframes[df_name] = pl.concat(dfs, how='vertical_relaxed')\n                else:\n                    file_path = os.path.join(self.directory, file_names[0]+'.parquet')\n                    temp = pl.read_parquet(file_path)\n                    temp =Preprocesamiento.casteo_columnas(temp)\n                    if df_name not in depth0:\n                        temp = temp.group_by(\"case_id\").agg(Agregaciones.get_exprs(temp))\n                    self.dataframes[df_name] = temp\n            except FileNotFoundError:\n                print(f\"Error: No se pudo encontrar el arcivo con nombre {df_name}\")\n            except Exception as e:\n              print(f\"Ocurrio un error al procesar {df_name}: {e}\")\n        return self.dataframes\n\n    def from_csv_optim(self):\n        # Lectura de archivos optimizada para csv\n        depth0 = ['train_static_0', 'train_static_cb','base','test_static_0','test_static_cb'] #tablas con profundidad cero\n        for df_name, file_names in self.dataframes_nombres.items():\n            try:\n                if len(file_names) > 1:\n                    dfs = []\n                    for file_name in file_names:\n                        file_path = os.path.join(self.directory, file_name+'.csv')\n                        temp = pl.read_csv(file_path)\n                        temp = Preprocesamiento.casteo_columnas(temp)\n                        if df_name not in depth0:\n                           temp = temp.group_by(\"case_id\").agg(Agregaciones.get_exprs(temp))\n                        dfs.append(temp)\n                    self.dataframes[df_name] = pl.concat(dfs, how='vertical_relaxed')\n                else:\n                    file_path = os.path.join(self.directory, file_names[0]+'.csv')\n                    temp = pl.read_csv(file_path)\n                    temp =Preprocesamiento.casteo_columnas(temp)\n                    if df_name not in depth0:\n                        temp = temp.group_by(\"case_id\").agg(Agregaciones.get_exprs(temp))\n                    self.dataframes[df_name] = temp\n            except FileNotFoundError:\n                print(f\"Error: No se pudo encontrar el arcivo con nombre {df_name}\")\n            except Exception as e:\n              print(f\"Ocurrio un error al procesar {df_name}: {e}\")\n        return self.dataframes","metadata":{"id":"A1friDaueYe3","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.767793Z","iopub.execute_input":"2024-12-29T22:25:58.768063Z","iopub.status.idle":"2024-12-29T22:25:58.785437Z","shell.execute_reply.started":"2024-12-29T22:25:58.768043Z","shell.execute_reply":"2024-12-29T22:25:58.784788Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Preprocesamiento:\n    # Clase con funciones para el preprocesamiento\n    def casteo_columnas(df):\n      # basandonos en la documentacion de kaggle\n      # utilizamos las etiquetas para castear los datos\n      for col in df.columns:\n          # columnas especiales para la base\n          if col in [\"case_id\", \"WEEK_NUM\", \"num_group1\", \"num_group2\"]:\n              df = df.with_columns(pl.col(col).cast(pl.Int64))\n          elif col in [\"date_decision\"]:\n              df = df.with_columns(pl.col(col).cast(pl.Date))\n          # P representa dias\n          # A representa ganancias\n          elif col[-1] in (\"P\", \"A\"):\n              df = df.with_columns(pl.col(col).cast(pl.Float64))\n          # M representan categorias\n          elif col[-1] in (\"M\",):\n              df = df.with_columns(pl.col(col).cast(pl.String))\n          # D es para fechas\n          elif col[-1] in (\"D\",):\n              df = df.with_columns(pl.col(col).cast(pl.Date))\n      return df\n\n    def convertir_fechas(df):\n      # Convertimos las fechas a dias utilizano date_decision\n      for col in df.columns:\n          if col[-1] in (\"D\",):\n              df = df.with_columns(pl.col(col) - pl.col(\"date_decision\"))\n              df = df.with_columns(pl.col(col).dt.total_days())\n      df = df.drop(\"date_decision\", \"MONTH\",'WEEK_NUM')\n      return df\n\n    def filtrar_fijos(df):\n      # Filtramos los fijos y aquellas columnas con mas del 99% de nulos\n      for col in df.columns:\n          if col not in [\"target\", \"case_id\", \"WEEK_NUM\",'MONTH','date_decision']:\n              isnull = df[col].is_null().mean()\n              if isnull >0.99 or df[col].n_unique() == 1:\n                  df = df.drop(col)\n      return df\n\n\n    def filtrar_categoricas(df):\n        # Elimina variables categoricas amplias\n        for col in df.columns:\n            if df[col].dtype == pl.Categorical or df[col].dtype == pl.String:\n                if df[col].n_unique() > 150:\n                    df = df.drop(col)\n        return df\n\n    def filtrar_valores_atipicos(df):\n      # Eliminamos valores atipicos\n      for col in df.columns:\n        if df[col].dtype not in (pl.String,pl.Categorical,pl.Boolean,pl.Date) and not df[col].is_null().all():\n          Q1 = df[col].quantile(0.25)\n          Q3 = df[col].quantile(0.75)\n          IQR = Q3 - Q1\n          lower = Q1 - 1.5*IQR\n          upper = Q3 + 1.5*IQR\n\n          # Arreglo que indica los outliers\n          upper_array = np.where(df[col] >= upper)[0]\n          lower_array = np.where(df[col] <= lower)[0]\n\n          df = df.with_columns(\n              pl.when((pl.col(col) < lower) | (pl.col(col) > upper))\n              .then(None)\n              .otherwise(pl.col(col)).alias(col))\n      return df\n","metadata":{"id":"JRP6iyrBGZpa","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.786814Z","iopub.execute_input":"2024-12-29T22:25:58.787080Z","iopub.status.idle":"2024-12-29T22:25:58.805266Z","shell.execute_reply.started":"2024-12-29T22:25:58.787061Z","shell.execute_reply":"2024-12-29T22:25:58.804482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Agregaciones:\n    def num_expr(df):\n        # Agregaciones para numeros\n        cols = [col for col in df.columns if col[-1] in (\"P\", \"A\")]\n        expr_mean = [pl.mean(col).alias(f\"mean_{col}\") for col in cols]#consideramos la media\n        expr_median = [pl.median(col).alias(f\"median_{col}\") for col in cols]#consideramos la mediana\n        return expr_mean + expr_median\n\n    def date_expr(df):\n        # Agregaciones para fechas\n        cols = [col for col in df.columns if col[-1] in (\"D\")]\n        expr_last = [pl.last(col).alias(f\"last_{col}\") for col in cols] # consideramos el ultimo valor segun la fecha\n        return expr_last\n\n    def str_expr(df):\n        # transofrmaciones para categorias\n        cols = [col for col in df.columns if col[-1] in (\"M\",)]\n        expr_mode = [pl.col(col).mode().first().name.prefix(\"mode_\") for col in cols] #consideramos la moda\n        expr_last = [pl.last(col).alias(f\"last_{col}\") for col in cols] #consideramos el ultimo valor segun la fecha\n        #expr_last = [pl.last(col).alias(f\"last_{col}\") for col in cols]\n        return expr_mode + expr_last\n\n    def other_expr(df):\n        # otro tipo de datos\n        cols = [col for col in df.columns if col[-1] in (\"T\", \"L\")]\n        expr_last = [pl.last(col).alias(f\"last_{col}\") for col in cols]\n        return expr_last #expr_mode\n\n    def get_exprs(df):\n        exprs = Agregaciones.num_expr(df) + \\\n                Agregaciones.date_expr(df) + \\\n                Agregaciones.str_expr(df) + \\\n                Agregaciones.other_expr(df)\n        return exprs","metadata":{"id":"XexJ_xDkTmfg","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.806327Z","iopub.execute_input":"2024-12-29T22:25:58.806517Z","iopub.status.idle":"2024-12-29T22:25:58.824594Z","shell.execute_reply.started":"2024-12-29T22:25:58.806501Z","shell.execute_reply":"2024-12-29T22:25:58.823816Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Pipeline_preprocesamiento:\n\n  def casteo_datos(self,dfs):\n    # Se castean todas las columnas\n    for df_name,df in dfs.items():\n      dfs[df_name] = Preprocesamiento.casteo_columnas(df)\n    return dfs\n\n  def filtracion_datos(self,dfs):\n    # Se filtran las columnas\n    for df_name,df in dfs.items():\n      dfs[df_name] = Preprocesamiento.filtrar_fijos(df)\n      dfs[df_name] = Preprocesamiento.filtrar_categoricas(df)\n    return dfs\n\n  def convertir_fechas_datos(self,dfs):\n    # Se hace un join con la base, necesario para convertir las fechas\n    base = dfs['base'][['case_id',\"date_decision\", \"MONTH\",'WEEK_NUM']]\n    for df_name,df in dfs.items():\n        if df_name == 'base':\n          continue\n        dfs[df_name] = dfs[df_name].join(base,on='case_id',how='left')\n        dfs[df_name] = Preprocesamiento.convertir_fechas(dfs[df_name])\n    return dfs\n\n  def agregacion(self,dfs):\n    # Se agregaon los datos con depth>0\n    depth0 = ['train_static_0', 'train_static_cb','base','test_static_0','test_static_cb'] #tablas con profundidad cero\n    for df_name,df in dfs.items():\n      if df_name not in depth0:\n        dfs[df_name] = dfs[df_name].group_by(\"case_id\").agg(Agregaciones.get_exprs(df))\n    return dfs\n\n  def concat_datos(self,dfs):\n    # Se concatenan los datos\n    # Este valor sirve para formar los cojuntos X_train y y_train\n    base = dfs['base'].drop(\"date_decision\", \"MONTH\",'WEEK_NUM')\n    for df_name,df in dfs.items():\n      if df_name == 'base':\n        continue\n      base = base.join(df,on='case_id',how='left')\n    return base\n\n  def to_pandas(self, df_data, cat_cols=None):\n    # El modelo XGBClassifier solo funcionar con objetivos tipo pd.DataFrame\n    # Por lo tanto el casteo es necesario\n    df_data = df_data.to_pandas()\n    print('tranformacion correcta')\n    print(type(df_data))\n    if cat_cols is None:\n        cat_cols = list(df_data.select_dtypes(\"object\").columns)\n    df_data[cat_cols] = df_data[cat_cols].astype(\"category\") #tipo categorias, importante para el modelo XGB\n    return df_data\n\n  def __call__(self,dict_df):\n    dfs = {df_name: df.clone() for df_name, df in dict_df.items()}\n\n    dfs = self.filtracion_datos(dfs)\n    dfs = self.convertir_fechas_datos(dfs)\n    dfs = self.concat_datos(dfs)\n    dfs = self.to_pandas(dfs)\n    dfs.replace([np.inf, -np.inf], np.nan, inplace=True)\n    dfs = liberar_memoria(dfs)\n    return dfs\n","metadata":{"id":"DL_R0HGluz1W","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.825536Z","iopub.execute_input":"2024-12-29T22:25:58.825846Z","iopub.status.idle":"2024-12-29T22:25:58.841406Z","shell.execute_reply.started":"2024-12-29T22:25:58.825819Z","shell.execute_reply":"2024-12-29T22:25:58.840597Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def liberar_memoria(df):\n    # Funcion para liberar memoria\n    start_mem = df.memory_usage().sum() / 1024**2  # Memoria utilizada\n    print('La memoria utilizada es {:.2f} MB'.format(start_mem))\n\n    for col in df.columns:\n        col_type = df[col].dtype\n        if str(col_type)==\"category\":\n            continue\n\n        if col_type != object:\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == 'int':\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)\n            else:\n                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    df[col] = df[col].astype(np.float64)\n        else:\n            continue\n    end_mem = df.memory_usage().sum() / 1024**2\n    #print('La memoria optimizada es: {:.2f} MB'.format(end_mem))\n    print('Se optimizó en {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))\n\n    return df","metadata":{"id":"5-NwzOWuWCc7","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.843202Z","iopub.execute_input":"2024-12-29T22:25:58.843413Z","iopub.status.idle":"2024-12-29T22:25:58.859489Z","shell.execute_reply.started":"2024-12-29T22:25:58.843395Z","shell.execute_reply":"2024-12-29T22:25:58.858793Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# directorio\ndirectory = '/kaggle/input/home-credit-credit-risk-model-stability/csv_files/train' #aqui agregas tu directorio\n# diccionario con dataframes\ndataframes_nombres = {'train_applprev_1':['train_applprev_1_0',\n                                  'train_applprev_1_1'],\n              'train_applprev_2':['train_applprev_2'],\n              'base':['train_base'],\n              'train_credit_bureau_a_1':['train_credit_bureau_a_1_0',\n                                        'train_credit_bureau_a_1_1',\n                                        'train_credit_bureau_a_1_2',\n                                        'train_credit_bureau_a_1_3'],\n              'train_credit_bureau_a_2':['train_credit_bureau_a_2_0',\n                                        'train_credit_bureau_a_2_1',\n                                        'train_credit_bureau_a_2_2',\n                                        'train_credit_bureau_a_2_3',\n                                        'train_credit_bureau_a_2_4',\n                                        'train_credit_bureau_a_2_5',\n                                        'train_credit_bureau_a_2_6',\n                                        'train_credit_bureau_a_2_7',\n                                        'train_credit_bureau_a_2_8',\n                                        'train_credit_bureau_a_2_9',\n                                        'train_credit_bureau_a_2_10'],\n              'train_credit_bureau_b_1':['train_credit_bureau_b_1'],\n              'train_credit_bureau_b_2':['train_credit_bureau_b_2'],\n              'train_debitcard_1':['train_debitcard_1'],\n              'train_other_1':['train_other_1'],\n              'train_deposit_1':['train_deposit_1'],\n              'train_person_1':['train_person_1'],\n              'train_person_2':['train_person_2'],\n              'train_static_0':['train_static_0_0','train_static_0_1'],\n              'train_static_cb':['train_static_cb_0'],\n              'train_tax_registry_a_1':['train_tax_registry_a_1'],\n              'train_tax_registry_b_1':['train_tax_registry_b_1'],\n              'train_tax_registry_c_1':['train_tax_registry_c_1']\n              }","metadata":{"id":"yuTOHzhaLCuh","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.861023Z","iopub.execute_input":"2024-12-29T22:25:58.861210Z","iopub.status.idle":"2024-12-29T22:25:58.876029Z","shell.execute_reply.started":"2024-12-29T22:25:58.861194Z","shell.execute_reply":"2024-12-29T22:25:58.875393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Importamos datos\nprint(\"iniciando\")\ndataframes = Importador(directory,dataframes_nombres).from_csv_optim()\nprint('listo')","metadata":{"id":"s3IejVxSip1h","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:25:58.876822Z","iopub.execute_input":"2024-12-29T22:25:58.877087Z","iopub.status.idle":"2024-12-29T22:31:25.938190Z","shell.execute_reply.started":"2024-12-29T22:25:58.877062Z","shell.execute_reply":"2024-12-29T22:31:25.937305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataframes","metadata":{"id":"9BPfIBsH5Sbg","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:31:25.939056Z","iopub.execute_input":"2024-12-29T22:31:25.939419Z","iopub.status.idle":"2024-12-29T22:31:25.962941Z","shell.execute_reply.started":"2024-12-29T22:31:25.939394Z","shell.execute_reply":"2024-12-29T22:31:25.962095Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Objeto pipeline\npipe = Pipeline_preprocesamiento()","metadata":{"id":"XmT4NAo8vONZ","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:31:25.963677Z","iopub.execute_input":"2024-12-29T22:31:25.964009Z","iopub.status.idle":"2024-12-29T22:31:25.978408Z","shell.execute_reply.started":"2024-12-29T22:31:25.963971Z","shell.execute_reply":"2024-12-29T22:31:25.977813Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#  Se realiza el preproceaminento de los datos\ndf = pipe(dataframes)","metadata":{"id":"GEXuy6cDl5d6","outputId":"ea2a9bef-bf28-4d88-f8a2-cc9345a2ec7d","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:31:25.979046Z","iopub.execute_input":"2024-12-29T22:31:25.979293Z","iopub.status.idle":"2024-12-29T22:32:34.860556Z","shell.execute_reply.started":"2024-12-29T22:31:25.979268Z","shell.execute_reply":"2024-12-29T22:32:34.859619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.shape\n","metadata":{"id":"M6HgxUNNmSPZ","outputId":"977fb342-1c4c-4897-c3c7-8a48cc680502","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:32:34.861522Z","iopub.execute_input":"2024-12-29T22:32:34.861884Z","iopub.status.idle":"2024-12-29T22:32:34.867076Z","shell.execute_reply.started":"2024-12-29T22:32:34.861852Z","shell.execute_reply":"2024-12-29T22:32:34.866285Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#pip install xgboost\nprint(\"Inicio modelado\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T22:32:34.867811Z","iopub.execute_input":"2024-12-29T22:32:34.868011Z","iopub.status.idle":"2024-12-29T22:32:34.883931Z","shell.execute_reply.started":"2024-12-29T22:32:34.867995Z","shell.execute_reply":"2024-12-29T22:32:34.883195Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Modelo y entrenamiento","metadata":{}},{"cell_type":"code","source":"\n\nfrom sklearn.model_selection import RandomizedSearchCV\nfrom scipy.stats import uniform, randint\nfrom sklearn.metrics import accuracy_score\nfrom xgboost import XGBClassifier\n","metadata":{"execution":{"iopub.status.busy":"2024-12-29T22:32:34.886036Z","iopub.execute_input":"2024-12-29T22:32:34.886233Z","iopub.status.idle":"2024-12-29T22:32:35.924691Z","shell.execute_reply.started":"2024-12-29T22:32:34.886217Z","shell.execute_reply":"2024-12-29T22:32:35.924060Z"},"id":"ARuAFizLvT2E","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport joblib\n\nfrom sklearn.model_selection import RandomizedSearchCV\nfrom scipy.stats import uniform, randint\nfrom sklearn.metrics import roc_auc_score, confusion_matrix\nfrom xgboost import XGBClassifier\nimport os\n\n# 1. Lectura\n#df = pd.read_csv(\"/kaggle/input/credito-limpio/mycsvfile.csv\", low_memory=False)\nfor col in df.select_dtypes(include=[\"float64\"]):\n    df[col] = df[col].astype(np.float32)\nfor col in df.select_dtypes(include=[\"int64\"]):\n    df[col] = df[col].astype(np.int32)\nfor col in df.select_dtypes(include=[\"object\"]):\n    df[col] = df[col].astype(\"category\")\n\nclass ModeloXGB:\n    def __init__(self, cv=3, n_iter=5):\n        self.cv = cv\n        self.n_iter = n_iter\n        self.features = None\n        self.model = None\n\n        # Parám. fijos para reducir memoria\n        self.xgb_params = {\n            'objective':         'binary:logistic',\n            'eval_metric':       'auc',\n            'random_state':      42,\n            'enable_categorical': True,\n            'tree_method':       'gpu_hist',         # Cambia a 'gpu_hist' si estás seguro\n            'max_bin':           128,            # reduce bins\n            'nthread':           2               # limita hilos\n        }\n\n        # Rango de hiperparámetros más pequeño\n        self.param_dist = {\n            \"n_estimators\":      randint(200, 500),\n            \"max_depth\":         randint(3, 7),\n            \"learning_rate\":     uniform(0.01, 0.1),\n            \"subsample\":         uniform(0.5, 0.4),\n            \"colsample_bytree\":  uniform(0.5, 0.4),\n            \"gamma\":             uniform(0, 5),\n            \"reg_alpha\":         uniform(0, 0.5)\n        }\n\n    def train_model(self, data: pd.DataFrame):\n        if self.features is None:\n            self.features = [c for c in data.columns if c not in ['target','case_id']]\n        X_train = data[self.features]\n        y_train = data['target']\n\n        random_search = RandomizedSearchCV(\n            estimator=XGBClassifier(**self.xgb_params),\n            param_distributions=self.param_dist,\n            n_iter=self.n_iter,\n            scoring='roc_auc',\n            cv=self.cv,\n            verbose=2,\n            # n_jobs=1: entrenar cada fold secuencialmente\n            n_jobs=1,\n            random_state=42\n        )\n        random_search.fit(X_train, y_train)\n        print(\"Mejores parámetros:\", random_search.best_params_)\n        print(\"Mejor score en validación:\", random_search.best_score_)\n\n        self.model = random_search.best_estimator_\n        return self.model\n\n    def predict_proba(self, X):\n        X = X[self.features]\n        return self.model.predict_proba(X)[:, 1]\n\n    def predict(self, X):\n        return (self.predict_proba(X) >= 0.25).astype(int)\n\n# 2. Entrenar\nprint(\"Entrenando\")\nxgboost = ModeloXGB(cv=3, n_iter=5)\nbest_model = xgboost.train_model(df)\n\n# 3. Evaluación\ny_pred = xgboost.predict_proba(df)\ny_train = df['target']\ny_p = (y_pred >= 0.19).astype(int)\n\ncm = confusion_matrix(y_train, y_p)\nprint(\"Matriz de confusión:\\n\", cm)\n\nroc_auc = roc_auc_score(y_train, y_pred)\nprint(f\"ROC AUC Score: {roc_auc:.4f}\")\n\n# 4. Guardado\nos.makedirs(\"output\", exist_ok=True)\njoblib.dump(best_model, \"output/best_xgb_model.pkl\")\npd.DataFrame({'case_id': df['case_id'], 'score': y_pred}).to_csv(\"output/submission_scores.csv\", index=False)\npd.Series(xgboost.features).to_csv(\"output/model_features.csv\", index=False, header=False)\n","metadata":{"execution":{"iopub.status.busy":"2024-12-29T22:32:35.925536Z","iopub.execute_input":"2024-12-29T22:32:35.925983Z","iopub.status.idle":"2024-12-29T22:54:45.602640Z","shell.execute_reply.started":"2024-12-29T22:32:35.925959Z","shell.execute_reply":"2024-12-29T22:54:45.601981Z"},"trusted":true},"outputs":[],"execution_count":null}]}