{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":103174,"databundleVersionId":12430709,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:39:30.951802Z","iopub.execute_input":"2025-06-28T03:39:30.952315Z","iopub.status.idle":"2025-06-28T03:39:30.967235Z","shell.execute_reply.started":"2025-06-28T03:39:30.952288Z","shell.execute_reply":"2025-06-28T03:39:30.965748Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"customer = pd.read_csv(\"/kaggle/input/diplomado-data-science-infox/customers.csv\")\ncustomer.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:39:30.969013Z","iopub.execute_input":"2025-06-28T03:39:30.969292Z","iopub.status.idle":"2025-06-28T03:39:33.838389Z","shell.execute_reply.started":"2025-06-28T03:39:30.969272Z","shell.execute_reply":"2025-06-28T03:39:33.837471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"balances = pd.read_csv(\"/kaggle/input/diplomado-data-science-infox/balances.csv\")\nbalances.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:39:33.840066Z","iopub.execute_input":"2025-06-28T03:39:33.840372Z","iopub.status.idle":"2025-06-28T03:40:05.627167Z","shell.execute_reply.started":"2025-06-28T03:39:33.840349Z","shell.execute_reply":"2025-06-28T03:40:05.626176Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"movements = pd.read_csv(\"/kaggle/input/diplomado-data-science-infox/movements.csv\")\nmovements.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:05.628233Z","iopub.execute_input":"2025-06-28T03:40:05.628506Z","iopub.status.idle":"2025-06-28T03:40:13.261238Z","shell.execute_reply.started":"2025-06-28T03:40:05.628484Z","shell.execute_reply":"2025-06-28T03:40:13.260258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/diplomado-data-science-infox/train.csv\")\ntrain.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:13.263688Z","iopub.execute_input":"2025-06-28T03:40:13.264012Z","iopub.status.idle":"2025-06-28T03:40:13.905958Z","shell.execute_reply.started":"2025-06-28T03:40:13.263981Z","shell.execute_reply":"2025-06-28T03:40:13.904779Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_pred = pd.read_csv(\"/kaggle/input/diplomado-data-science-infox/test_pred.csv\")\ntest_pred.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:13.906926Z","iopub.execute_input":"2025-06-28T03:40:13.907170Z","iopub.status.idle":"2025-06-28T03:40:14.136836Z","shell.execute_reply.started":"2025-06-28T03:40:13.907152Z","shell.execute_reply":"2025-06-28T03:40:14.135912Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Seleccionamos las columnas para hacerlas dummies\ndummies = ['product_1', 'product_2', 'product_3', 'product_4',\n               'ofert_1', 'ofert_2', 'ofert_3']\n\n# Y reemplazamos\ncustomer[dummies] = customer[dummies].replace({'Yes': 1, 'No': 0})\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:14.137779Z","iopub.execute_input":"2025-06-28T03:40:14.138008Z","iopub.status.idle":"2025-06-28T03:40:16.377073Z","shell.execute_reply.started":"2025-06-28T03:40:14.137991Z","shell.execute_reply":"2025-06-28T03:40:16.375723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ahora con las variables categoricas detectamos las que tienen pocos niveles\ncat_cols_customer = [col for col in customer.columns \n                     if customer[col].dtype == 'object' and customer[col].nunique() <= 10]\n# Solo hacemos dummies de las categóricas pequeñas\ncustomer = pd.get_dummies(customer, columns=cat_cols_customer, drop_first=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:16.378510Z","iopub.execute_input":"2025-06-28T03:40:16.378891Z","iopub.status.idle":"2025-06-28T03:40:17.124646Z","shell.execute_reply.started":"2025-06-28T03:40:16.378866Z","shell.execute_reply":"2025-06-28T03:40:17.123204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Las limitamos en tamaño para no sobrecargar el ambiente\ncat_cols_balances = [col for col in ['product', 'type', 'entity']\n                     if balances[col].nunique() <= 20]\n\n# Convertimos las variables categóricas a dummies antes de agruparlas\nbalances_dummies = pd.get_dummies(balances[cat_cols_balances], prefix=cat_cols_balances)\n\n# Concatenamos con las variables numéricas\nbalances_numeric = balances[['ID', 'balance_amount', 'days_default']]\nbalances_expanded = pd.concat([balances_numeric, balances_dummies], axis=1)\n\n# Agrupamos por cliente\nbalances_agg = balances_expanded.groupby(\"ID\").agg('mean').reset_index()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:17.125796Z","iopub.execute_input":"2025-06-28T03:40:17.126082Z","iopub.status.idle":"2025-06-28T03:40:41.721749Z","shell.execute_reply.started":"2025-06-28T03:40:17.126059Z","shell.execute_reply":"2025-06-28T03:40:41.720782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Seleccionamos las columnas numéricas\ncols_type = ['type_1', 'type_2', 'type_3', 'type_4']\n\n#Las agrupamos\nmovements_agg = movements.groupby('ID')[cols_type].agg(['mean', 'sum', 'std']).reset_index()\n\n# Aplanamos los nombres de las columnas\nmovements_agg.columns = ['ID'] + [f'movements_{col}_{agg}' for col in cols_type for agg in ['mean', 'sum', 'std']]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:41.722895Z","iopub.execute_input":"2025-06-28T03:40:41.723222Z","iopub.status.idle":"2025-06-28T03:40:48.441200Z","shell.execute_reply.started":"2025-06-28T03:40:41.723193Z","shell.execute_reply":"2025-06-28T03:40:48.440270Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Union1 = pd.merge(customer, train, on = 'ID', how = 'left')\nUnion1.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:48.443885Z","iopub.execute_input":"2025-06-28T03:40:48.444151Z","iopub.status.idle":"2025-06-28T03:40:49.234983Z","shell.execute_reply.started":"2025-06-28T03:40:48.444132Z","shell.execute_reply":"2025-06-28T03:40:49.233967Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(Union1.shape)\nprint(Union1['ID'].duplicated().sum())  # Debe ser 0 para confirmar que esta bien\nUnion1.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:49.236593Z","iopub.execute_input":"2025-06-28T03:40:49.237793Z","iopub.status.idle":"2025-06-28T03:40:49.417431Z","shell.execute_reply.started":"2025-06-28T03:40:49.237697Z","shell.execute_reply":"2025-06-28T03:40:49.416261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Union2 = pd.merge(Union1, balances_agg, on='ID', how='left')\nUnion3 = pd.merge(Union2, movements_agg, on='ID', how='left')\nUnion3['ID'].duplicated().sum()  # Debe dar 0 para confirmar que esta bien","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:49.418632Z","iopub.execute_input":"2025-06-28T03:40:49.419027Z","iopub.status.idle":"2025-06-28T03:40:52.537653Z","shell.execute_reply.started":"2025-06-28T03:40:49.418996Z","shell.execute_reply":"2025-06-28T03:40:52.536591Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Union_Test1 = pd.merge(test_pred, customer, on='ID', how='left')\nUnion_Test1['ID'].duplicated().sum()  # Debe dar 0 para confirmar que esta bien","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:52.538802Z","iopub.execute_input":"2025-06-28T03:40:52.539801Z","iopub.status.idle":"2025-06-28T03:40:53.082287Z","shell.execute_reply.started":"2025-06-28T03:40:52.539766Z","shell.execute_reply":"2025-06-28T03:40:53.081169Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Union_Test2 = pd.merge(Union_Test1, balances_agg, on='ID', how='left')\nUnion_Test3 = pd.merge(Union_Test2, movements_agg, on='ID', how='left')\nUnion_Test3['ID'].duplicated().sum()  # Debe dar 0 para confirmar que esta bien","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:53.083703Z","iopub.execute_input":"2025-06-28T03:40:53.084027Z","iopub.status.idle":"2025-06-28T03:40:53.883643Z","shell.execute_reply.started":"2025-06-28T03:40:53.083993Z","shell.execute_reply":"2025-06-28T03:40:53.882493Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Union3.isnull().sum()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:53.884910Z","iopub.execute_input":"2025-06-28T03:40:53.885242Z","iopub.status.idle":"2025-06-28T03:40:54.184684Z","shell.execute_reply.started":"2025-06-28T03:40:53.885218Z","shell.execute_reply":"2025-06-28T03:40:54.183584Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Union_Test3.isnull().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.185927Z","iopub.execute_input":"2025-06-28T03:40:54.186243Z","iopub.status.idle":"2025-06-28T03:40:54.255221Z","shell.execute_reply.started":"2025-06-28T03:40:54.186219Z","shell.execute_reply":"2025-06-28T03:40:54.254085Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**MODELO**","metadata":{}},{"cell_type":"code","source":"#Eliminamos los valores nulos de la base\nUnion3_train_clean = Union3.dropna()\nUnion3_test_clean = Union_Test3.dropna()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.256236Z","iopub.execute_input":"2025-06-28T03:40:54.256521Z","iopub.status.idle":"2025-06-28T03:40:54.644181Z","shell.execute_reply.started":"2025-06-28T03:40:54.256498Z","shell.execute_reply":"2025-06-28T03:40:54.643037Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Entrenamiento\n# Realizamos el train y el test de nuestro modelo\nX_train = Union3_train_clean.drop(columns=['ID', 'attrition'])\ny_train = Union3_train_clean['attrition']\n\nX_test = Union3_test_clean.drop(columns=['ID'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.645219Z","iopub.execute_input":"2025-06-28T03:40:54.645545Z","iopub.status.idle":"2025-06-28T03:40:54.674208Z","shell.execute_reply.started":"2025-06-28T03:40:54.645515Z","shell.execute_reply":"2025-06-28T03:40:54.673158Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Revisamos que las columnas con NaN en el train que hicimos sean 0\")\nprint(Union3_train_clean.isnull().sum().sort_values(ascending=False).head())\n\nprint(\"NaNs en y_train\")\nprint(Union3_train_clean['attrition'].isnull().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.675870Z","iopub.execute_input":"2025-06-28T03:40:54.676154Z","iopub.status.idle":"2025-06-28T03:40:54.733701Z","shell.execute_reply.started":"2025-06-28T03:40:54.676132Z","shell.execute_reply":"2025-06-28T03:40:54.732764Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Verificamos los tipos de valores en y_train\nprint(y_train.value_counts(normalize=True))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.734827Z","iopub.execute_input":"2025-06-28T03:40:54.735512Z","iopub.status.idle":"2025-06-28T03:40:54.745107Z","shell.execute_reply.started":"2025-06-28T03:40:54.735474Z","shell.execute_reply":"2025-06-28T03:40:54.743877Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Hacemos variables dummy para nuestras variables categoricas\nX_train = pd.get_dummies(X_train)\nX_test = pd.get_dummies(X_test)\n\n# Alineamos las columnas de test con las de train para que se adapten al modelo\nX_test = X_test.reindex(columns=X_train.columns, fill_value=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.746190Z","iopub.execute_input":"2025-06-28T03:40:54.747037Z","iopub.status.idle":"2025-06-28T03:40:54.968246Z","shell.execute_reply.started":"2025-06-28T03:40:54.747010Z","shell.execute_reply":"2025-06-28T03:40:54.967242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score\nfrom xgboost import XGBClassifier\n\n# División de columnas de train\nX_tr, X_val, y_tr, y_val = train_test_split(\n    X_train, y_train, test_size=0.2, stratify=y_train, random_state=42\n)\n\n# Peso de clases\nratio = (y_train == 0).sum() / (y_train == 1).sum()\n\nmodel = XGBClassifier(\n    n_estimators=500,\n    max_depth=5,\n    learning_rate=0.05,\n    subsample=0.8,\n    colsample_bytree=0.8,\n    random_state=42,\n    use_label_encoder=False,\n    eval_metric='logloss',\n    scale_pos_weight=ratio\n)\n\n# Entrenamiento\nmodel.fit(X_tr, y_tr)\n\n# Evaluación de la preducción\ny_val_pred = model.predict(X_val)\nf1 = f1_score(y_val, y_val_pred)\nprint(\"F1-score:\", f1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T03:40:54.969393Z","iopub.execute_input":"2025-06-28T03:40:54.969701Z","iopub.status.idle":"2025-06-28T03:41:02.708869Z","shell.execute_reply.started":"2025-06-28T03:40:54.969678Z","shell.execute_reply":"2025-06-28T03:41:02.707823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_test_pred = model.predict(X_test)\n\nsubmission = Union3_test_clean[['ID']].copy()\nsubmission['attrition'] = y_test_pred.astype(int)\nsubmission = submission.sort_values(\"ID\")\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-28T04:04:41.571190Z","iopub.execute_input":"2025-06-28T04:04:41.572080Z","iopub.status.idle":"2025-06-28T04:04:42.357127Z","shell.execute_reply.started":"2025-06-28T04:04:41.572047Z","shell.execute_reply":"2025-06-28T04:04:42.355889Z"}},"outputs":[],"execution_count":null}]}