{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Introdução\nConforme descrito no *overview*, o desafio consiste em avaliar se determinado cliente executará ou não uma transação específica no futuro.\n\nO problema possui variáveis anônimas e objetivo binário.\n\n## Considerações gerais\nDado o contexto acima, a seguinte metodologia foi estabelecida:\n\n- [x] Carregar os arquivos disponibilizados e avaliar o volume de dados disponíveis em cada um deles;\n- [x] Remover colunas irrelevantes para o modelo (coluna de `ID`, por exemplo);\n- [x] Avaliar dados nulos/vazios\n- [x] Normalizar dados\n- [x] Avaliar balanceamento dos dados de acordo com o `TARGET`\n- [x] Avaliar necessidade de remoção de *outliers*; (etapa descartada em virtude da normalização escolhida)\n- [x] Avaliar a possibilidade de utilização de análise de componentes para a redução do número de atributos utilizadas como entrada do modelo;\n- [x] Avaliar se os outliers removidos implicam na exclusão de informações importantes para o modelo;  (etapa descartada em virtude da normalização escolhida)\n- [x] Utilizar formato automatizado para identificação dos modelos e hiperparâmetros (`GridSearchCV` ou `BayesSearchCV`);\n- [x] Realizar validação dos modelos com os dados de teste e selecionar o melhor modelo\n- [x] Submeter o resultado para contabilização do score\n- [x] Avaliar as alterações necessárias e ressubmeter o trabalho até que o score mínimo de 85% seja alcançado\n\n### Resumo das alterações em cada submissão\n#### 1ª submissão\nTestes iniciais de diversos modelos e parâmetros.\n\n#### 2ª submissão\nAo investigar o que poderia ter ocorrido com os modelos que obtiveram melhores resultados, foi observado que os parâmetros configurados para o algoritmo `LightGBM` não estavam adequados e que nem mesmo o tipo de objetivo (`objective = 'binary'`) havia sido configurado.\n\nComo o tempo de treinamento deste algoritmo é relativamente rápido, foi realizada por uma abordagem direta para o modelo, reavaliando os resultados com o conjunto de testes.\n\n#### 3ª submissão\nConsiderando que as alterações não foram satisfatórias, os melhores modelos da primeira submissão foram retreinados após a criação de features (*feature engineering*) utilizando ACP.\n\n#### 4ª submissão\nForam explorados alguns modelos da biblioteca `scikit-learn` com uma configuração mínima dos parâmetros disponíveis.\n\n#### 5ª submissão\nUma vez que as alterações anteriores não resultaram em um índice de acerto $\\geq$ 85% (*benchmark* desejado), foi realizada uma nova avaliação sobre as *features* e etapa de normalização.\n\nCom relação as *features*, foi avaliada a correlação entre as variáveis com o intuito de desconsiderar quaisquer variáveis linearmente dependentes.\n\n> O resultado demonstrou o que era esperado: variáveis não são correlacionadas.\n\nNo que tange a normalização, a suspeita é que os dados contenham algum tipo de *spike* que caracterize a execução da transação e que estejam sendo desprezados pelo `RobustScaler`. Neste sentido, serão utilizados os algoritmos `MinMaxScaler` ou `StandardScaler` como alternativa.\n\n> A utilização do `MinMaxScaler` ou `StandardScaler` não implicou em incremento do *score*.\n\nAlém disso, foi observado também que existem dados fictícios em potencial no conjunto de testes, tal como descrito [neste link](https://www.kaggle.com/code/yag320/list-of-fake-samples-and-public-private-lb-split). Neste sentido, será realizada uma análise detalhada dos dados de teste, até mesmo porque [a descrição do problema](https://www.kaggle.com/competitions/santander-customer-transaction-prediction/data) explicita que alguns dados de teste não são contabilizados no score:\n\n> *test.csv - the test set. The test set contains some rows which are not included in scoring.*\n\n#### 6ª a 10ª submissão\nForam construídas novas features considerando a característica da unicidade destacada na submissão anterior. Além disso, foi utilizada a estratégia de dividir para conquistar, tendo sido treinado um conjunto contendo 200 modelos (um por *feature*). A saída resultante é obtida a partir da composição das saídas de cada modelo individual.\n\nO resultado do primeiro conjunto (6ª submissão, com parâmetros mínimos) foi consideravelmente melhor do que todos os resultados anteriores. Neste sentido, as submissões seguintes buscaram apenas otimizar os hiperparâmetros dos modelos.","metadata":{}},{"cell_type":"markdown","source":"## Código e análises\n### Instalação e importação de bibliotecas","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport os\nimport pandas as pd\nimport warnings\n\nfrom lightgbm import LGBMClassifier\nfrom scipy.special import logit\nfrom sklearn.model_selection import GridSearchCV\nfrom tqdm import tqdm\n\n# Manutenção da sanidade mental\nwarnings.simplefilter( action='ignore', category = pd.errors.PerformanceWarning )","metadata":{"_kg_hide-output":false,"execution":{"iopub.status.busy":"2022-07-21T20:14:56.187423Z","iopub.execute_input":"2022-07-21T20:14:56.188102Z","iopub.status.idle":"2022-07-21T20:14:56.196368Z","shell.execute_reply.started":"2022-07-21T20:14:56.188059Z","shell.execute_reply":"2022-07-21T20:14:56.195202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Versões anteriores\n# !pip install imblearn\n# import joblib\n# import math\n# import matplotlib.pyplot as plt\n\n# import pprint\n# import seaborn as sns\n\n# from catboost import CatBoostClassifier\n# from hyperopt import fmin\n# from hyperopt import hp\n# from hyperopt import STATUS_OK\n# from hyperopt import tpe\n# from hyperopt import Trials\n# from imblearn.over_sampling import SMOTE\n# from imblearn.under_sampling import RandomUnderSampler\n# from lightgbm import cv as lgb_cv\n# from lightgbm import Dataset\n# from sklearn import metrics\n# from sklearn.decomposition import PCA\n# from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n# from sklearn.ensemble import AdaBoostClassifier\n# from sklearn.ensemble import ExtraTreesClassifier\n# from sklearn.ensemble import HistGradientBoostingClassifier\n# from sklearn.ensemble import RandomForestClassifier\n# from sklearn.linear_model import LogisticRegression\n# from sklearn.linear_model import RidgeClassifier\n# from sklearn.metrics import make_scorer\n# from sklearn.model_selection import StratifiedKFold\n# from sklearn.model_selection import train_test_split\n# from sklearn.naive_bayes import GaussianNB\n# from sklearn.neighbors import KNeighborsClassifier\n# from sklearn.neural_network import MLPClassifier\n# from sklearn.preprocessing import MinMaxScaler\n# from sklearn.preprocessing import RobustScaler\n# from sklearn.preprocessing import StandardScaler\n# from sklearn.svm import LinearSVC\n# from sklearn.svm import NuSVC\n# from sklearn.svm import SVC\n# from sklearn.tree import DecisionTreeClassifier\n# from skopt import BayesSearchCV\n# from skopt.callbacks import DeadlineStopper\n# from skopt.callbacks import DeltaYStopper\n# from skopt.space import Real\n# from skopt.space import Categorical\n# from skopt.space import Integer\n# from time import time\n# from xgboost import XGBClassifier","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-21T20:14:56.198473Z","iopub.execute_input":"2022-07-21T20:14:56.199189Z","iopub.status.idle":"2022-07-21T20:14:56.208818Z","shell.execute_reply.started":"2022-07-21T20:14:56.199132Z","shell.execute_reply":"2022-07-21T20:14:56.207538Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Carga dos arquivos","metadata":{}},{"cell_type":"code","source":"# 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\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","execution":{"iopub.status.busy":"2022-07-21T20:14:56.210650Z","iopub.execute_input":"2022-07-21T20:14:56.211039Z","iopub.status.idle":"2022-07-21T20:14:56.234470Z","shell.execute_reply.started":"2022-07-21T20:14:56.210986Z","shell.execute_reply":"2022-07-21T20:14:56.233101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# https://www.kaggle.com/code/mjbahmani/santander-ml-explainability?scriptVersionId=11406347&cellId=25\ndef reduce_mem_usage(df):\n    start_mem_usg = df.memory_usage().sum() / 1024**2 \n    print(\"Memory usage of properties dataframe is :\",start_mem_usg,\" MB\")\n    NAlist = [] # Keeps track of columns that have missing values filled in. \n    for col in df.columns:\n        if df[col].dtype != object:  # Exclude strings\n            \n            # Print current column type\n            print(\"******************************\")\n            print(\"Column: \",col)\n            print(\"dtype before: \",df[col].dtype)\n            \n            # make variables for Int, max and min\n            IsInt = False\n            mx = df[col].max()\n            mn = df[col].min()\n            \n            # Integer does not support NA, therefore, NA needs to be filled\n            if not np.isfinite(df[col]).all(): \n                NAlist.append(col)\n                df[col].fillna(mn-1,inplace=True)  \n                   \n            # test if column can be converted to an integer\n            asint = df[col].fillna(0).astype(np.int64)\n            result = (df[col] - asint)\n            result = result.sum()\n            if result > -0.01 and result < 0.01:\n                IsInt = True\n\n            \n            # Make Integer/unsigned Integer datatypes\n            if IsInt:\n                if mn >= 0:\n                    if mx < 255:\n                        df[col] = df[col].astype(np.uint8)\n                    elif mx < 65535:\n                        df[col] = df[col].astype(np.uint16)\n                    elif mx < 4294967295:\n                        df[col] = df[col].astype(np.uint32)\n                    else:\n                        df[col] = df[col].astype(np.uint64)\n                else:\n                    if mn > np.iinfo(np.int8).min and mx < np.iinfo(np.int8).max:\n                        df[col] = df[col].astype(np.int8)\n                    elif mn > np.iinfo(np.int16).min and mx < np.iinfo(np.int16).max:\n                        df[col] = df[col].astype(np.int16)\n                    elif mn > np.iinfo(np.int32).min and mx < np.iinfo(np.int32).max:\n                        df[col] = df[col].astype(np.int32)\n                    elif mn > np.iinfo(np.int64).min and mx < np.iinfo(np.int64).max:\n                        df[col] = df[col].astype(np.int64)    \n            \n            # Make float datatypes 32 bit\n            else:\n                df[col] = df[col].astype(np.float32)\n            \n            # Print new column type\n            print(\"dtype after: \",df[col].dtype)\n            print(\"******************************\")\n    \n    # Print final result\n    print(\"___MEMORY USAGE AFTER COMPLETION:___\")\n    mem_usg = df.memory_usage().sum() / 1024**2 \n    print(\"Memory usage is: \",mem_usg,\" MB\")\n    print(\"This is \",100*mem_usg/start_mem_usg,\"% of the initial size\")\n    return df, NAlist","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-21T20:14:56.237067Z","iopub.execute_input":"2022-07-21T20:14:56.237622Z","iopub.status.idle":"2022-07-21T20:14:56.260480Z","shell.execute_reply.started":"2022-07-21T20:14:56.237585Z","shell.execute_reply":"2022-07-21T20:14:56.259429Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train = pd.read_csv( '/kaggle/input/santander-customer-transaction-prediction/train.csv' )\ndf_test = pd.read_csv( '/kaggle/input/santander-customer-transaction-prediction/test.csv' )\n\n# Redução de uso de memória (versões anteriores)\n# df_train, NAList = reduce_mem_usage( df_train )\n# df_test, NAList = reduce_mem_usage( df_test )","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-21T20:14:56.261884Z","iopub.execute_input":"2022-07-21T20:14:56.262275Z","iopub.status.idle":"2022-07-21T20:15:13.083106Z","shell.execute_reply.started":"2022-07-21T20:14:56.262231Z","shell.execute_reply":"2022-07-21T20:15:13.081449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Análise preliminar","metadata":{}},{"cell_type":"code","source":"df_train.head()","metadata":{"execution":{"iopub.status.busy":"2022-07-21T20:15:13.084771Z","iopub.execute_input":"2022-07-21T20:15:13.085200Z","iopub.status.idle":"2022-07-21T20:15:13.119421Z","shell.execute_reply.started":"2022-07-21T20:15:13.085165Z","shell.execute_reply":"2022-07-21T20:15:13.117952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test.head()","metadata":{"execution":{"iopub.status.busy":"2022-07-21T20:15:13.120900Z","iopub.execute_input":"2022-07-21T20:15:13.121963Z","iopub.status.idle":"2022-07-21T20:15:13.155879Z","shell.execute_reply.started":"2022-07-21T20:15:13.121914Z","shell.execute_reply":"2022-07-21T20:15:13.154798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Remoção de colunas irrelevantes para o modelo","metadata":{}},{"cell_type":"code","source":"cols_remover = []\n\nprint( 'Dimensões (train) ANTES:', df_train.shape )\nprint( 'Dimensões (test) ANTES:', df_test.shape )\n\ntarget = df_train[ 'target' ]\nids = df_test[ 'ID_code' ]\n\nfor c in df_train.columns:\n    if not c.startswith( 'var_' ):\n        df_train.drop( c, inplace = True, axis = 1 )\n        \n        if c in df_test.columns:\n            df_test.drop( c, inplace = True, axis = 1 )\n\nprint( 'Dimensões (train) DEPOIS:', df_train.shape )\nprint( 'Dimensões (test) DEPOIS:', df_test.shape )","metadata":{"execution":{"iopub.status.busy":"2022-07-21T20:05:46.409921Z","iopub.execute_input":"2022-07-21T20:05:46.410767Z","iopub.status.idle":"2022-07-21T20:05:47.178771Z","shell.execute_reply.started":"2022-07-21T20:05:46.410722Z","shell.execute_reply":"2022-07-21T20:05:47.177412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Tratamento de dados nulos","metadata":{}},{"cell_type":"code","source":"print( 'Nulos' )\nprint( 'Train:', df_train.isnull().values.any() )\nprint( 'Test:', df_test.isnull().values.any() )\nprint( '\\nVazios' )\nprint( 'Train:', df_train.isna().values.any() )\nprint( 'Test:', df_test.isna().values.any() )","metadata":{"execution":{"iopub.status.busy":"2022-07-21T17:55:50.011490Z","iopub.execute_input":"2022-07-21T17:55:50.013266Z","iopub.status.idle":"2022-07-21T17:55:50.299134Z","shell.execute_reply.started":"2022-07-21T17:55:50.013210Z","shell.execute_reply":"2022-07-21T17:55:50.298035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Feature engineering e treinamento\n\nDe acordo com [esta discussão](https://www.kaggle.com/competitions/santander-customer-transaction-prediction/discussion/89003), criada pelo primeiro colocado na competição, a \"virada de chave\" do problema está na identificação de características únicas das *features*.\n\nEm suma, para a solução do problema os vencedores da competição construiram 400 novas *features*, sendo 200 categóricas e 200 numéricas a partir do [kernel](https://www.kaggle.com/yag320/list-of-fake-samples-and-public-private-lb-split) compartilhado por [YaG320](https://www.kaggle.com/yag320), cuja ideia consiste basicamente em identificar todas as amostras criadas artificialmente para compor a base de dados de teste. <!-- Ainda de acordo com a referida discussão, a criação das *features* categóricas permitiu que o score do algoritmo fosse de 91%. -->\n\n<!-- , conforme detalhamento abaixo.\n\n#### *Features* categóricas:\n- O valor aparece pelo menos duas vezes nos dados com target = 1 e nenhuma vez com target = 0;\n- O valor aparece pelo menos duas vezes nos dados com target = 0 e nenhuma vez com target = 1;\n- O valor aparece pelo menos duas vezes com target = 0 e duas vezes com target = 1;\n- O valor é único nos dados de treinamento;\n- O valor é unico nos dados de treinamento + teste (considerando apenas os valores de teste reais).\n\nA segregação entre valores de teste reais e sintéticos pode ser observada [neste link](https://www.kaggle.com/code/yag320/list-of-fake-samples-and-public-private-lb-split).\n\n#### *Features* numéricas:\nAs 200 *features* numéricas foram construídas a partir da *feature* original, substituindo os valores únicos dos dados + testes (última das *features categóricas) pela média da *feature*.\n -->\n\n#### O que fazer?\n\nObservando várias soluções (exemplos: [1](https://www.kaggle.com/code/gunesevitan/santander-customer-transaction-eda-fe-lgb), [2](https://www.kaggle.com/code/dott1718/922-in-3-minutes/notebook), [3](https://www.kaggle.com/code/jesucristo/top-1-in-40-lines) e [4](https://www.kaggle.com/code/whitebird/0-923-in-n-5-aug)), é fácil perceber que a criação de *features* que \"carreguem\" a característica da unicidade das amostras, ainda que de forma simplificada, é consideravelmente eficaz para a solução.\n\nNeste sentido, serão construídas 800 novas *features* (4 para cada *feature* original) com as seguintes características:\n\n- *var_$i$vc*: $vc_i = \\min(10, N_{rep})$ (o teto de 10 poderia, na verdade, ser qualquer valor);\n- *var_$i$sum1*: $(V_i - \\mu) \\times vc_i$ para os itens com mais do que 1 repetição\n- *var_$i$sum2*: $V_i \\times vc_i$ para os itens com mais do que 2 repetições\n- *var_$i$sum3*: $V_i \\times vc_i$ para os itens com mais do que 4 repetições\n\nPara o contexto acima, $i$ se refere ao índice da *feature*, $vc_i$ é a i-ésima *feature vc*, $V_i$ é o valor da i-ésima *feature*, $\\mu$ é a média da *feature* e $N_{rep}$ é o número de repetições\n\n#### Treinamento\n\nUma vez que as *features* estejam disponíveis, será realizado o treinamento de modelos individualizados para cada *feature* $i$, considerando os 5 valores como entrada (*feature* original + *features* construídas) como entradas e o *target* original como saída.\n\n<!-- Dessa forma, em um primeiro momento, apenas as *features* categórias serão construídas. Se o benchmark desejado for atingido, o trabalho será considerado concluído. Caso contrário, as 200 *features* numéricas também serão adicionadas aos dados. -->\n\n<!-- Ademais, como o intuito do trabalho não é o de reinventar a roda, as features categórias serão carregadas a partir dos dados disponibilizados no [link](https://www.kaggle.com/code/fl2ooo/create-data/notebook) da discussão.\n\nPor fim, e apenas por preciosismo/tradição, serão mantidas as *features* numéricas que foram testadas em modelos das outras submissões, a saber: `sum`, `min`, `max`, `mean`, `std`, `skew`, `kurtosis` e `median`. -->","metadata":{}},{"cell_type":"code","source":"# Baseado em https://www.kaggle.com/code/gunesevitan/santander-customer-transaction-eda-fe-lgb\ntest = df_test.values\n\nunique_count = np.zeros_like( test )\n\nfor feature in range( test.shape[ 1 ] ):\n    _, index, count = np.unique( test[ :, feature ], return_counts = True, return_index = True )\n    unique_count[ index[ count == 1 ], feature ] += 1\n    \nreal_samples = np.argwhere( np.sum( unique_count, axis = 1 ) > 0 )[ :, 0 ]\nsynth_samples = np.argwhere( np.sum( unique_count, axis = 1 ) == 0 )[ :, 0 ]\n\nprint( f'Número de amostras reais: {len( real_samples )}' )\nprint( f'Número de amostras criadas artificialmente: {len( synth_samples )}' )\n\nfeatures = [ col for col in df_train.columns if col.startswith( 'var' ) ]\ndf_all = pd.concat( [ df_train, df_test.iloc[ real_samples ] ] )\n\nprint( df_all.shape )","metadata":{"execution":{"iopub.status.busy":"2022-07-20T16:36:53.795743Z","iopub.execute_input":"2022-07-20T16:36:53.796116Z","iopub.status.idle":"2022-07-20T16:37:00.160952Z","shell.execute_reply.started":"2022-07-20T16:36:53.796082Z","shell.execute_reply":"2022-07-20T16:37:00.160012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Construção das *magic features*","metadata":{}},{"cell_type":"code","source":"# Baseado em https://www.kaggle.com/code/gunesevitan/santander-customer-transaction-eda-fe-lgb\nfor feature in features:\n    temp = df_all[feature].value_counts(dropna=True)\n\n    # Número de repetições com teto em 10\n    df_train[feature + 'vc'] = df_train[feature].map(temp).map(lambda x: min(10, x)).astype(np.uint8)\n    df_test[feature + 'vc'] = df_test[feature].map(temp).map(lambda x: min(10, x)).astype(np.uint8)\n\n    # ( Valor - Média ) para itens com mais do que 1 repetição (treinamento + teste)\n    df_train[feature + 'sum1'] = ((df_train[feature] - df_all[feature].mean()) * df_train[feature + 'vc'].map(lambda x: int(x > 1))).astype(np.float32)\n    df_test[feature + 'sum1'] = ((df_test[feature] - df_all[feature].mean()) * df_test[feature + 'vc'].map(lambda x: int(x > 1))).astype(np.float32) \n\n    # Valor dos itens com mais do que 2 repetições\n    df_train[feature + 'sum2'] = ((df_train[feature]) * df_train[feature + 'vc'].map(lambda x: int(x > 2))).astype(np.float32)\n    df_test[feature + 'sum2'] = ((df_test[feature]) * df_test[feature + 'vc'].map(lambda x: int(x > 2))).astype(np.float32)\n\n    # Valor dos itens com mais do que 4 repetições\n    df_train[feature + 'sum3'] = ((df_train[feature]) * df_train[feature + 'vc'].map(lambda x: int(x > 4))).astype(np.float32) \n    df_test[feature + 'sum3'] = ((df_test[feature]) * df_test[feature + 'vc'].map(lambda x: int(x > 4))).astype(np.float32)\n    \nprint( 'Conjunto de treinamento após a criação das features: {}'.format( df_train.shape ) )\nprint( 'Conjunto de teste após a criação das features: {}'.format( df_test.shape ) )","metadata":{"execution":{"iopub.status.busy":"2022-07-20T16:37:00.161945Z","iopub.execute_input":"2022-07-20T16:37:00.162185Z","iopub.status.idle":"2022-07-20T16:40:40.719981Z","shell.execute_reply.started":"2022-07-20T16:37:00.162162Z","shell.execute_reply":"2022-07-20T16:40:40.718033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Composição dos *dataframes* e treinamento dos modelos individualizados","metadata":{}},{"cell_type":"code","source":"clfs = {}\n\nfor feature in tqdm( features ):\n    df = pd.DataFrame()\n    \n    df[ feature ] = df_train[ feature ]\n    df[ feature + 'vc' ] = df_train[ feature + 'vc' ]\n    df[ feature + 'sum1' ] = df_train[ feature + 'sum1' ]\n    df[ feature + 'sum2' ] = df_train[ feature + 'sum2' ]\n    df[ feature + 'sum3' ] = df_train[ feature + 'sum3' ]\n    \n    df_t = pd.DataFrame()\n    \n    df_t[ feature ] = df_test[ feature ]\n    df_t[ feature + 'vc' ] = df_test[ feature + 'vc' ]\n    df_t[ feature + 'sum1' ] = df_test[ feature + 'sum1' ]\n    df_t[ feature + 'sum2' ] = df_test[ feature + 'sum2' ]\n    df_t[ feature + 'sum3' ] = df_test[ feature + 'sum3' ]\n    \n    clf = LGBMClassifier(\n        metric = 'auc',\n        objective = 'binary',\n        is_unbalance = True,\n        n_jobs = -1, \n        verbose = -1,\n        # Parâmetros de https://www.kaggle.com/code/dott1718/922-in-3-minutes/notebook\n        learning_rate = 0.05,\n        max_bin = 165,\n        max_depth = 5,\n        min_child_samples = 150,\n        min_child_weight = 0.1,\n        min_split_gain = 0.0018,\n        n_estimators = 41,\n        num_leaves = 6,\n        reg_alpha = 2.0,\n        reg_lambda = 2.54,\n    )\n    \n#     params = {\n#         'learning_rate': [ 0.01, 0.05 ],\n#         'max_bin': [ 150 ],\n#         'max_depth': [ 5 ],\n#         'min_child_samples': [ 150 ],\n#         'n_estimators': [ 30 ],\n#         'num_leaves': [ 5, 7 ],\n#     }\n    \n#     grid = GridSearchCV(\n#         estimator = clf,\n#         param_grid = params,\n#         cv = 5,\n#         return_train_score = True,\n#         scoring = 'roc_auc',\n#         verbose = -1,\n#     )\n    \n#     grid.fit( df, target.values )\n    clf.fit( df, target.values )\n    \n#     clfs[ feature ] = ( grid.best_estimator_, grid.predict_proba( df_t )[ :, 1 ] )\n    clfs[ feature ] = ( clf, clf.predict_proba( df_t )[ :, 1 ] )","metadata":{"execution":{"iopub.status.busy":"2022-07-20T17:38:05.444672Z","iopub.execute_input":"2022-07-20T17:38:05.444984Z","iopub.status.idle":"2022-07-20T17:38:08.031962Z","shell.execute_reply.started":"2022-07-20T17:38:05.444958Z","shell.execute_reply":"2022-07-20T17:38:08.030611Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Submissão","metadata":{}},{"cell_type":"code","source":"pred = np.zeros( ( len( clfs[ features[ 0 ] ][ 1 ] ) ) )\n\ndf = pd.DataFrame()\n\nfor feature in features:\n    df[ feature ] = clfs[ feature ][ 1 ]\n    \n    # https://en.wikipedia.org/wiki/Logit\n    # logit(p) = log(p/(1-p)) = log(p) - log(1 - p)\n    pred += logit( df[ feature ] )\n    \nsub = pd.DataFrame( { 'ID_code': ids, 'target': pred } )\n\nsub.to_csv( f'submission.csv', index = False )","metadata":{"execution":{"iopub.status.busy":"2022-07-20T17:28:06.508108Z","iopub.execute_input":"2022-07-20T17:28:06.508422Z","iopub.status.idle":"2022-07-20T17:28:07.500184Z","shell.execute_reply.started":"2022-07-20T17:28:06.508397Z","shell.execute_reply":"2022-07-20T17:28:07.499352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Resultados\n\n#### Resumo das alterações por submissão\n\n| Submissão | Melhor modelo              | Principais alterações                           |\n|:---------:|----------------------------|-------------------------------------------------|\n| 1         | `LogisticRegression`       | Versão inicial                                  |\n| 2         | `LightGBM`                 | Atualização dos parâmetros do model `LightGBM`  |\n| 3         | `LightGBM`                 | *Feature Engineering* com PCA                   |\n| 4         | `LightGBM`                 | Exploração de modelos com configurações mínimas |\n| 5         | `LightGBM`                 | Utilização da biblioteca `skopt` para a definição dos hiperparâmetros |\n| 6         | `LightGBM`                 | Treinamento de modelos individualizados  |\n| 6         | `LightGBM`                 | Ajuste de hiperparâmetros  |\n| 7         | `LightGBM`                 | Ajuste de hiperparâmetros  |\n| 8         | `LightGBM`                 | Ajuste de hiperparâmetros  |\n| 9         | `LightGBM`                 | Ajuste de hiperparâmetros  |\n| 10        | `LightGBM`                 | Ajuste de hiperparâmetros  |\n\n#### Parâmetros e resultados\n\n| Algoritmo            | Submissão | Melhores parâmetros  | CV<br>($\\mu$) | CV<br>($\\sigma$) | Trein.<br>($\\mu$) | Trein.<br>($\\sigma$) | Score Priv. | Score Públ. |\n|:--------------------:|:---------:|:---------------------|:-------------:|:----------------:|:-----------------:|:--------------------:|:-----------:|:-----------:|\n| `AdaBoost`           | 1         | `{'learning_rate': 0.3,`<br>`'n_estimators': 20}` | 0.77 | 0.045 | 0.77 | 0.010 | - | - |\n| `DecisionTree`       | 1         | `{'max_depth': 15}`  | 0.76 | 0.015 | 0.89 | 0.005 | - | - |\n| `GaussianNB`         | 1         | `{}` | 0.92 | 0.093 | 0.92 | 0.019 | - | - |\n| `LigthGBM`           | 1         | `{'learning_rate': 1.0,`<br>`'n_estimators': 25,`<br>`'num_leaves': 25}` | 0.92 | 0.051 | 0.94 | 0.010 | - | - |\n| `LogisticRegression` | 1         | `{'C': 0.03}` | 0.88 | 0.005 | 0.88 | 0.001 | 0.72995 | 0.73044 |\n| `MLP`                | 1         | `{'activation': 'tanh',`<br>`'alpha': 1e-05,`<br>`'hidden_layer_sizes': (25, 20, 15),`<br>`'learning_rate': 'adaptive',`<br>`'learning_rate_init': 0.3,`<br>`'max_iter': 1000,`<br>`'solver': 'sgd'}` | 0.93 | 0.016 | 0.97 | 0.004 | - | - |\n| `RandomForest`       | 1         | `{'max_depth': 25,`<br>`'n_estimators': 25}` | 0.98 | 0.014 | 1.00 | 0.000 | - | - |\n| `XGBoost`            | 1         | `{'learning_rate': 0.5,`<br>`'max_depth': 10,`<br>`'n_estimators': 20}` | 0.96 | 0.000 | 1.00 | 0.000 | - | - |\n| `LigthGBM`           | 2         | `{'learning_rate': 0.04,`<br>`'min_child_samples': 1000,`<br>`'n_estimators': 200,`<br>`'num_leaves': 35,`<br>`'reg_alpha': 0.1,`<br>`'reg_lambda': 0.2}` | 0.94 | 0.051 | 0.96 | 0.008 | 0.63696 | 0.63417 |\n| `GaussianNB`         | 3         | `{}` | 0.94 | 0.066 | 0.94 | 0.013 | - | - |\n| `LightGBM`           | 3         | `{'learning_rate': 0.04,`<br>`'min_child_samples': 1000,`<br>`'n_estimators': 250,`<br>`'num_leaves': 35,`<br>`'reg_alpha': 0.1,`<br>`'reg_lambda': 0.2}` | 0.95 | 0.027 | 0.96 | 0.007 | 0.70684 | 0.70519 |\n| `ExtraTrees`         | 4         | `{}` | 0.87 | 0.005 | 1.00 | 0.000 | - | - |\n| `GaussianNB`         | 4         | `{}` | 0.89 | 0.003 | 0.89 | 0.001 | - | - |\n| `LDA`                | 4         | `{}` | 0.86 | 0.003 | 0.86 | 0.001 | - | - |\n| `LightGBM`           | 4         | `{}` | 0.87 | 0.004 | 0.94 | 0.000 | 0.77768 | 0.78409 |\n| `LSVC`               | 4         | `{}` | 0.86 | 0.003 | 0.86 | 0.001 | 0.58700 | 0.58818 |\n| `RidgeClassifier`    | 4         | `{}` | 0.86 | 0.003 | 0.86 | 0.001 | 0.51073 | 0.51548 |\n| `LightGBM`           | 5         | `{ 'bagging_fraction': 0.310705101713577,`<br>`'bagging_freq': 24,`<br>`'colsample_bytree': 0.3286602708105357,`<br>`'feature_fraction': 0.7690035470860215,`<br>`'learning_rate': 0.08365988171015928,`<br>`'max_bin': 249,`<br>`'max_depth': 24,`<br>`'min_child_weight': 5.8690603372847505,`<br>`'n_estimators': 948,`<br>`'num_leaves': 26,`<br>`'reg_alpha': 0.001590540465822274,`<br>`'reg_lambda': 20.61610545435179,`<br>`'scale_pos_weight': 84.23359790575388,`<br>`'subsample': 0.1371355611172356,`<br>`'subsample_freq': 6 }` | 0.82 | N/A   | N/A | N/A | 0.77768 | 0.78409 |\n| `LightGBM`           | 6         | `{}` | - | - | - | - | 0.85209 | 0.85515 |\n| `LightGBM`           | 7         | `{'learning_rate': 0.01,`<br>`'max_bin': 20,`<br>`'max_depth': 5,`<br>`'min_child_samples': 150,`<br>`'n_estimators': 41,`<br>`'num_leaves': 6}` | - | - | - | - | 0.90624 | 0.91036 |\n| `LightGBM`           | 8         | `{'learning_rate': 0.01,`<br>`'max_bin': 10,`<br>`'max_depth': 5,`<br>`'min_child_samples': 150,`<br>`'n_estimators': 20,`<br>`'num_leaves': 5}` | - | - | - | - | 0.88900 | 0.89357 |\n| `LightGBM`           | 9         | `GridSearchCV`, `params = {`<br>`'learning_rate': [ 0.01, 0.05 ],`<br>`'max_bin': [ 150 ],`<br>`'max_depth': [ 5 ],`<br>`'min_child_samples': [ 150 ],`<br>`'n_estimators': [ 30 ],`<br>`'num_leaves': [ 5, 7 ]}` | - | - | - | - | 0.91244 | 0.91593 |\n| `LightGBM`           | 10        | Parâmetros de [Link](https://bit.ly/3RSB8cS) | - | - | - | - | 0.91972 | 0.92166 |\n\n### Conclusões\n\n#### Submissão 1\nConsiderando os resultados obtidos, é possível que os modelos melhor classificados não tenham generalizado o problema da melhor forma, incorrendo em *overfit*.\n\n#### Submissão 2\nO único treinamento realizado para esta submissão foi do algoritmo `LightGBM`. Considerando os novos parâmetros escolhidos, era esperado que o modelo apresentasse algum tipo de melhoria. Todavia, o *score* obtido com a submissão não refletiram esta expectativa.\n\n#### Submissão 3\nApós inclusão das componentes principais como novas features, esperava-se que os resultados obtidos fossem aperfeiçoados.\n\nMais uma vez, contudo, o *score* obtido com a submissão não refletiram a expectativa.\n\n#### Submissão 4\nNesta rodada os modelos foram treinados com o mínimo de parâmetros mínimos.\n\nO arquivo de saída (`*.pkl`) do algorimo `ExtraTrees` ficou consideravelmente grande (~3 GB) e, por esse motivo, o algoritmo foi desconsiderado do ranking classificatório.\n\nOs melhores resultados portanto foram dos algoritmos `GaussianNB` e `LightGBM`, com scores (CV) de 89% e 87%, respectivamente.\n\nAlguns modelos foram selecionados para a submissão mas todos os resultados se mantiveram em patamares inferiores ao *benchmark*.\n\n#### Submissão 5\nComo esperado, a utilização da biblioteca `skopt` melhorou consideravelmente o tempo necessário para a identificação dos hiperparâmetros.\n\nO resultado da submissão, contudo, permaneceu aquém do *benchmark*.\n\n#### Submissão 6\nA estratégia de dividir para conquistar em conjunto com a criação de novas *features* que agregam a característica de unicidade das amostras, sem sombra de dúvidas, trouxeram uma melhoria significativa para o *score*.\n\nO treinamento de 200 modelos (1 por *feature*) utilizando os parâmetros mínimos necessários (`binary = True`, `is_unbalance = True` e `metric = 'auc'`) foi rápido e eficaz, fazendo com que, pela primeira vez, o *score* obtido superasse o *benchmark* desejado.\n\n#### Submissões 7 a 10\nO intuito destas submissões era o de encontrar melhores hiperparâmetros para os modelos, mantendo a abordagem de dividir para conquistar utilizada na submissão 6.\n\n\n### Possíveis melhorias\nComo melhorias em potencial, podem ser reavaliadas todas as etapas utilizadas nas submissões anteriores (disponíveis em células ocultas no final deste notebook) e desconsideradas nas últimas submissões em virtude dos bons resultados obtidos, tais como:\n\n- Normalização dos dados\n- Balanaceamento\n- Análise de Componentes Principais\n- Busca Baysiana de hiperparâmetros (biblioteca `skopt`)\n\nAlém disso, a construção de outras *features*, com cálculos um pouco mais elaborados, por exemplo, podem implicar na redução do número *features* totais utilizadas em cada modelo (de 5 para 2 ou 3, por exemplo), trazendo algum tipo de melhoria para o resultado global.\n\nAdemais, diversas abordagens para este problema estão disponíveis para consulta no Kaggle. Cada uma delas suscita novos questionamentos e nos faz refletir sobre qual seria a solução ótima para o problema (se é que ela existe).\n\n- Será que uma solução intermediária à criação de 200 modelos é razoável?\n- 50 modelos seriam suficientes ou apenas 25 já dariam conta? \n- Como as *features* poderiam ser agrupadas para compor a entrada dessas novas abordagens?\n- Faz sentido utilizar um modelo que receba como entrada a saída dos 200 modelos originais e que tenha como saída o *target* do problema?\n\nTodos esses questionamentos podem ser avaliados. Se por acaso você estiver disposto a fazer isso, deixe um comentário com o link para a sua solução! :)","metadata":{}},{"cell_type":"markdown","source":"### Análise de correlação entre as variáveis (versões anteriores)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# corr_mat = df_train.corr( method = 'pearson' )\n\n# Matriz triangular superior (valores absolutos)\n# upper_corr_mat = corr_mat.where( np.triu( np.ones( corr_mat.shape ), k = 1 ).astype( bool ) ).abs()\n\n# Pares únicos\n# unique_corr_pairs = upper_corr_mat.unstack().dropna()\n\n# Ordenação\n# sorted_corr_pairs = unique_corr_pairs.sort_values( ascending = False )\n\n# print( sorted_corr_pairs )\n\n# Resultado\n# var_139  var_26     9.844361e-03\n# var_148  var_53     9.787532e-03\n# var_165  var_81     9.713658e-03\n# var_174  var_81     9.489853e-03\n# var_189  var_183    9.358682e-03\n#                         ...     \n# var_177  var_100    3.116544e-07\n# var_144  var_27     1.772502e-07\n# var_126  var_109    1.313947e-07\n# var_173  var_6      5.942735e-08\n# var_191  var_75     2.703975e-08\n# Length: 19900, dtype: float64","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-20T16:36:53.789058Z","iopub.execute_input":"2022-07-20T16:36:53.789283Z","iopub.status.idle":"2022-07-20T16:36:53.794370Z","shell.execute_reply.started":"2022-07-20T16:36:53.789260Z","shell.execute_reply":"2022-07-20T16:36:53.793275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Divisão dos dados de treinamento e teste (versões anteriores)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# X_train, X_test, y_train, y_test = train_test_split( df_train, target, test_size = 0.2, random_state = 54 )\n\n# print( 'Dimensões X_train:', X_train.shape )\n# print( 'Dimensões y_train:', y_train.shape )\n# print( 'Dimensões X_test:', X_test.shape )\n# print( 'Dimensões y_test:', y_test.shape )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:55.125721Z","iopub.execute_input":"2022-07-19T20:47:55.126094Z","iopub.status.idle":"2022-07-19T20:47:56.857058Z","shell.execute_reply.started":"2022-07-19T20:47:55.126060Z","shell.execute_reply":"2022-07-19T20:47:56.855954Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Normalização (versões anteriores)\n\n#### Submissões 1 a 4\nDe acordo com a [documentação](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.RobustScaler.html#sklearn.preprocessing.RobustScaler) do `scikitlearn`, o `RobustScaler` é tolerante aos *outliers* e por esse motivo foi escolhido para a normalização dos dados, mitigando a necessidade de tratamento de outliers em separado.\n\n#### Submissão 5\nPara esta submissão será utilizado o `MinMaxScaler`.","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# # scaler = RobustScaler()\n# scaler = MinMaxScaler( feature_range = ( -1.0, 1.0 ) )\n# # scaler = StandardScaler()\n\n# scaler = scaler.fit( X_train )\n\n# # print( scaler.data_min )\n# # print( scaler.data_max_ )\n\n# # scaled_X_train = scaler.transform( X_train )\n# scaled_X_train = X_train","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:56.858372Z","iopub.execute_input":"2022-07-19T20:47:56.858707Z","iopub.status.idle":"2022-07-19T20:47:57.652849Z","shell.execute_reply.started":"2022-07-19T20:47:56.858677Z","shell.execute_reply":"2022-07-19T20:47:57.651615Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Balanceamento dos dados (versões anteriores)\n\nConsiderando que existe um grande número de amostras cujo `target` é zero, é possível que o modelo aprenda a classificar os itens de forma equivocada em virtude de overfit.\n\nUma maneira de lidar com este problema é realizar uma \"reamostragem\" dos dados. Existem algumas técnicas para isso e, dentre as opções disponíveis, os algoritmos escolhidos foram `SMOTE` (*Synthetic Minority Oversampling Technique*) e `RandomUnderSampler`, ambas disponíveis na [`imblearn`](https://imbalanced-learn.org/stable/).\n\n> Fonte: [Link](https://towardsdatascience.com/methods-for-dealing-with-imbalanced-data-5b761be45a18)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# target_0, target_1 = np.bincount( target )\n\n# plt.pie(\n#     x = [\n#         target_0/( target_0 + target_1 ),\n#         target_1/( target_0 + target_1 ) \n#     ], \n#     labels =[ 'Target 0', 'Target 1'],\n#     autopct = '%.2f%%',\n#     colors = sns.color_palette('pastel')[0:2]\n# )\n# print( 'Target 0:', f'{target_0:,}', f'({target_0 / ( target_0 + target_1 ):.2%})' )\n# print( 'Target 1:', f'{target_1:,}', f'({target_1 / ( target_0 + target_1 ):.2%})' )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:57.654792Z","iopub.execute_input":"2022-07-19T20:47:57.655405Z","iopub.status.idle":"2022-07-19T20:47:57.783471Z","shell.execute_reply.started":"2022-07-19T20:47:57.655364Z","shell.execute_reply":"2022-07-19T20:47:57.782264Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # sm = SMOTE( random_state = 77, sampling_strategy = 'minority', k_neighbors = 5 )\n# # scaled_X_train, y_train = sm.fit_resample( scaled_X_train, y_train )\n\n# rus = RandomUnderSampler( sampling_strategy = 'majority', random_state = 54 )\n# scaled_X_train, y_train = rus.fit_resample( scaled_X_train, y_train )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:57.785629Z","iopub.execute_input":"2022-07-19T20:47:57.786496Z","iopub.status.idle":"2022-07-19T20:47:58.794995Z","shell.execute_reply.started":"2022-07-19T20:47:57.786443Z","shell.execute_reply":"2022-07-19T20:47:58.794265Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# print( 'Treinamento' )\n# print( df_train.shape )\n# print( scaled_X_train.shape, y_train.shape )\n\n# target_0, target_1 = np.bincount( y_train )\n\n# # plt.pie(\n# #     x = [\n# #         target_0/( target_0 + target_1 ),\n# #         target_1/( target_0 + target_1 ) \n# #     ], \n# #     labels =[ 'Target 0', 'Target 1'],\n# #     autopct = '%.2f%%',\n# #     colors = sns.color_palette('pastel')[0:2]\n# # )\n\n# print( 'Target 0:', f'{target_0:,}', f'({target_0 / ( target_0 + target_1 ):.2%})' )\n# print( 'Target 1:', f'{target_1:,}', f'({target_1 / ( target_0 + target_1 ):.2%})' )\n\n# print( 'Teste' )\n# print( df_test.shape )\n# print( X_test.shape, y_test.shape )\n\n# target_0, target_1 = np.bincount( y_test )\n\n# # plt.pie(\n# #     x = [\n# #         target_0/( target_0 + target_1 ),\n# #         target_1/( target_0 + target_1 ) \n# #     ], \n# #     labels =[ 'Target 0', 'Target 1'],\n# #     autopct = '%.2f%%',\n# #     colors = sns.color_palette('pastel')[0:2]\n# # )\n\n# print( 'Target 0:', f'{target_0:,}', f'({target_0 / ( target_0 + target_1 ):.2%})' )\n# print( 'Target 1:', f'{target_1:,}', f'({target_1 / ( target_0 + target_1 ):.2%})' )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:58.796577Z","iopub.execute_input":"2022-07-19T20:47:58.799556Z","iopub.status.idle":"2022-07-19T20:47:58.809294Z","shell.execute_reply.started":"2022-07-19T20:47:58.799511Z","shell.execute_reply":"2022-07-19T20:47:58.808244Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Análise de Componentes Principais (ACP) (versões anteriores)\n#### Submissões 1 e 2\nDe acordo com a [documentação](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html#sklearn.decomposition.PCA) do `scikitlearn`, utilizar `n_components = 'mle'` e `svd_solver = 'full'` implica em utilziar o [método de seleção automática do número de componentes](https://tminka.github.io/papers/pca/minka-pca.pdf) de Minka, T. P. (2000).\n\n##### Resultado\nUma vez que o número de componentes selecionados (188) é praticamente igual ao número de *features* disponíveis, a análise de componentes principais foi dispensada. Essa decisão se dá pelo fato de que a diferença de desempenho no treinamento será, provavelmente, irrisória e o resultado do modelo poderá ser comprometido em virtude da redução dimensional.\n\n#### Submissões 3 e 4\nApós 2 submissões em que o modelo não atingiu o *benchmark* desejado ($\\geq$ 85%) foi realizado um novo treinamento considerando 10% do número de *features* como o parâmetro de seleção para as componentes principais.\n\nTodavia, ao invés de reduzir a quantidade de variáveis, as componentes principais foram utilizadas como variáveis adicionais (*feature engineering*) para a entrada do modelo.\n\n#### Submissão 5\nN/A","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# Submissões 1 e 2 --------------------------------------------------------------------------------\n# pca = PCA( n_components = 'mle', svd_solver = 'full' )\n\n# Submissões 3 e 4 --------------------------------------------------------------------------------\n# pca_fe = PCA( n_components = math.ceil( 0.1 * scaled_X_train.shape[ 1 ] ), svd_solver = 'full' )\n# pca_fe.fit( scaled_X_train )\n\n# print( 'Covariância:', pca_fe.get_covariance() )\n# print( 'Parâmetros:', pca_fe.get_params() )\n\n# df_pca_X = pca_fe.transform( scaled_X_train )\n# scaled_X_train = np.concatenate( [ scaled_X_train, df_pca_X ], axis = 1 )\n\n# print( 'Dimensão da entrada após ACP:', scaled_X_train.shape )\n\n\n# Outros testes -----------------------------------------------------------------------------------\n# pca = PCA( n_components = 0.95, svd_solver = 'full' )\n# pca.fit( scaled_X_train )\n# print( len( pca.explained_variance_ratio_ ) )\n# scaled_X_train = pca.transform( scaled_X_train )\n\n# print( 'Qtde. componentes:', len( pca_fe.explained_variance_ratio_ ) )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:58.810720Z","iopub.execute_input":"2022-07-19T20:47:58.811582Z","iopub.status.idle":"2022-07-19T20:47:58.824858Z","shell.execute_reply.started":"2022-07-19T20:47:58.811529Z","shell.execute_reply":"2022-07-19T20:47:58.823903Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Treinamento dos modelos (versões anteriores)\nOs modelos serão treinados em separado, em momentos distintos, e serão salvos em arquivos específicos utilizando a `joblib`.\n\nO log dos treinamentos estará disponível em arquivo específico no *dataset* associado como entrada do processamento (`desafio-santander-transaction-predicion`).\n\n#### Submissão 4\nPara esta tentativa, será feita uma exploração de alguns dos modelos disponíveis na bibliotena `scikit-learn`, com uma configuração mínima de parâmetros, baseado no que foi feito [neste link](https://www.kaggle.com/code/danielgrimshaw/sklearn-model-exploration) (apenas itens com *score* $\\geq$ 85%).\n\n#### Submissão 5\nConsiderando que o modelo com os melhores resultados são sempre classificadores `LightGBM`, este será considerado o modelo padrão para todas as submissões subsequentes.\n\nAdemais, com o intuito de encontrar hiperparâmetros adequados para este modelo, será utilizada a biblioteca `skopt`.","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# # Baseado em https://www.kaggle.com/code/lucamassaron/skopt-for-lightgbm/notebook\n# # Reporting util for different optimizers\n# def report_perf( optimizer, X, y, title, callbacks = None ):\n#     \"\"\"\n#     A wrapper for measuring time and performances of different optmizers\n    \n#     optimizer = a sklearn or a skopt optimizer\n#     X = the training set \n#     y = our target\n#     \"\"\"\n#     start = time()\n    \n#     if callbacks is not None:\n#         optimizer.fit( X, y, callback = callbacks )\n#     else:\n#         optimizer.fit( X, y )\n        \n#     d = pd.DataFrame( optimizer.cv_results_ )\n#     best_score = optimizer.best_score_\n#     best_score_std = d.iloc[ optimizer.best_index_ ].std_test_score\n#     best_params = optimizer.best_params_\n    \n#     len_opt = len( optimizer.cv_results_[ 'params' ] )\n    \n#     print(\n#         (\n#             f'{title} took {time() - start} seconds. '\n#             f'Candidates checked: {len_opt}. '\n#             f'Best CV score: {best_score} \\u00B1 {best_score_std}.'\n#         )\n#     )    \n    \n#     print( 'Best parameters:' )\n#     pprint.pprint( best_params )\n\n#     return best_params\n\n# roc_auc = make_scorer( roc_auc_score, greater_is_better = True, needs_threshold = True )\n# skf = StratifiedKFold( n_splits = 10, shuffle = True, random_state = 0 )\n\n# search_spaces = {\n#     # LGBMClassifier\n#     'learning_rate': Real( 0.01, 0.1, 'log-uniform' ),   # Boosting learning rate\n#     'bagging_fraction': Real( 0.8, 1, 'log-uniform' ),   # \n#     'bagging_freq': Integer( 1, 100 ),                   # \n#     'feature_fraction': Real( 0.5, 1, 'log-uniform' ),   # \n#     'n_estimators': Integer( 10, 1500 ),                 # Number of boosted trees to fit\n#     'num_leaves': Integer( 20, 80, 'uniform' ),          # Maximum tree leaves for base learners\n#     'max_depth': Integer( -1, 10 ),                      # Maximum tree depth for base learners, <=0 means no limit\n#     'min_child_samples': Integer( 1, 256 ),              # Minimal number of data in one leaf\n#     'max_bin': Integer( 10, 20 ),                        # Max number of bins that feature values will be bucketed\n#     'subsample': Real( 0.01, 1.0, 'uniform' ),           # Subsample ratio of the training instance\n#     'subsample_freq': Integer( 0, 10 ),                  # Frequency of subsample, <=0 means no enable\n#     'colsample_bytree': Real( 0.01, 1.0, 'uniform' ),    # Subsample ratio of columns when constructing each tree\n#     'min_child_weight': Real( 0.01, 10.0, 'uniform' ),   # Minimum sum of instance weight (hessian) needed in a child (leaf)\n#     'reg_lambda': Real( 1e-9, 100.0, 'log-uniform' ),    # L2 regularization\n#     'reg_alpha': Real( 1e-9, 100.0, 'log-uniform' ),     # L1 regularization\n#     'scale_pos_weight': Real( 1.0, 500.0, 'uniform' ),   # Weighting of the minority class (Only for binary classification)\n\n#     # HistGradientBoostingClassifier\n# #     'l2_regularization': Real( 0.1, 0.5, 'log-uniform' ),\n# #     'learning_rate': Real( 0.01, 0.1, 'log-uniform' ),\n# #     'min_samples_leaf': Integer( 500, 1500, 'uniform' ),\n\n#     # KNN\n# #     'n_neighbors': Integer( 5, 20 ),\n\n#     # GaussianNB\n# #     'var_smoothing': Real( 1e-10, 1e-5, 'log-uniform' )\n# }\n\n# # Classificador genérico\n# clf = LGBMClassifier(\n#     metric = 'auc',\n#     objective = 'binary',\n#     is_unbalance = False,\n#     n_jobs = 1, \n#     verbose = -1,\n# )\n\n# # clf = HistGradientBoostingClassifier(\n# #     scoring = 'roc_auc',\n# #     max_iter = 10000,\n# #     max_leaf_nodes = None,\n# #     random_state = 321,\n# # )\n\n# # clf = KNeighborsClassifier()\n# # clf = GaussianNB()\n\n# opt = BayesSearchCV(\n#     estimator = clf,                                    \n#     search_spaces = search_spaces,                      \n#     scoring = roc_auc,                                  \n#     cv = skf,                                           \n#     n_iter = 3000,                                      # max number of trials\n#     n_points = 5,                                       # number of hyperparameter sets evaluated at the same time\n#     n_jobs = -1,                                        # number of jobs\n#     return_train_score = True,                         \n#     refit = False,                                      \n#     optimizer_kwargs = { 'base_estimator': 'GP' },      # optmizer parameters: we use Gaussian Process (GP)\n#     random_state = 54321\n# )\n\n# overdone_control = DeltaYStopper( delta = 0.0001 )               # We stop if the gain of the optimization becomes too small\n# time_limit_control = DeadlineStopper( total_time = 60 * 45 )     # We impose a time limit (45 minutes)\n\n# best_params = report_perf( opt, scaled_X_train, y_train, title = 'HistGradientBoostingClassifier', callbacks = [ overdone_control, time_limit_control ] )\n\n# ############################################\n# # Resultados obtidos em execuções distintas\n# ############################################\n# # OrderedDict([('colsample_bytree', 0.9490988546546835),\n# #              ('learning_rate', 0.3043045342848891),\n# #              ('max_bin', 398),\n# #              ('max_depth', 226),\n# #              ('min_child_samples', 210),\n# #              ('min_child_weight', 8.093138127627356),\n# #              ('n_estimators', 275),\n# #              ('num_leaves', 57),\n# #              ('reg_alpha', 5.906829172095262e-06),\n# #              ('reg_lambda', 1e-09),\n# #              ('scale_pos_weight', 81.96572472658119),\n# #              ('subsample', 0.9505995525749752),\n# #              ('subsample_freq', 1)])\n# # OrderedDict([('bagging_fraction', 0.9921221841283633),\n# #              ('bagging_freq', 3),\n# #              ('colsample_bytree', 0.7427283018063733),\n# #              ('feature_fraction', 0.6867905281498825),\n# #              ('learning_rate', 0.16418697018092526),\n# #              ('max_bin', 425),\n# #              ('max_depth', 49),\n# #              ('min_child_weight', 2.5079383412516583),\n# #              ('n_estimators', 300),\n# #              ('num_leaves', 100),\n# #              ('reg_alpha', 1.4312963366169807e-07),\n# #              ('reg_lambda', 0.06283633693620673),\n# #              ('scale_pos_weight', 138.5752166578494),\n# #              ('subsample', 0.01),\n# #              ('subsample_freq', 7)])\n# # OrderedDict([('bagging_fraction', 0.9921221841283633),\n# #              ('bagging_freq', 3),\n# #              ('colsample_bytree', 0.7427283018063733),\n# #              ('feature_fraction', 0.6867905281498825),\n# #              ('learning_rate', 0.16418697018092526),\n# #              ('max_bin', 425),\n# #              ('max_depth', 49),\n# #              ('min_child_weight', 2.5079383412516583),\n# #              ('n_estimators', 300),\n# #              ('num_leaves', 100),\n# #              ('reg_alpha', 1.4312963366169807e-07),\n# #              ('reg_lambda', 0.06283633693620673),\n# #              ('scale_pos_weight', 138.5752166578494),\n# #              ('subsample', 0.01),\n# #              ('subsample_freq', 7)])\n# # OrderedDict([('bagging_fraction', 0.310705101713577),\n# #              ('bagging_freq', 24),\n# #              ('colsample_bytree', 0.3286602708105357),\n# #              ('feature_fraction', 0.7690035470860215),\n# #              ('learning_rate', 0.08365988171015928),\n# #              ('max_bin', 249),\n# #              ('max_depth', 24),\n# #              ('min_child_weight', 5.8690603372847505),\n# #              ('n_estimators', 948),\n# #              ('num_leaves', 26),\n# #              ('reg_alpha', 0.001590540465822274),\n# #              ('reg_lambda', 20.61610545435179),\n# #              ('scale_pos_weight', 84.23359790575388),\n# #              ('subsample', 0.1371355611172356),\n# #              ('subsample_freq', 6)])\n# # OrderedDict([('bagging_fraction', 1.0),\n# #              ('bagging_freq', 1),\n# #              ('colsample_bytree', 0.9015405966870378),\n# #              ('feature_fraction', 0.26931696885557715),\n# #              ('learning_rate', 0.04191122428215176),\n# #              ('max_bin', 544),\n# #              ('max_depth', 50),\n# #              ('min_child_samples', 256),\n# #              ('min_child_weight', 0.01),\n# #              ('n_estimators', 1500),\n# #              ('num_leaves', 110),\n# #              ('reg_alpha', 100.0),\n# #              ('reg_lambda', 100.0),\n# #              ('subsample', 0.01),\n# #              ('subsample_freq', 10)])\n# # OrderedDict([('bagging_fraction', 0.8),\n# #              ('bagging_freq', 1),\n# #              ('colsample_bytree', 0.01),\n# #              ('feature_fraction', 0.8),\n# #              ('learning_rate', 0.1),\n# #              ('max_bin', 20),\n# #              ('max_depth', 8),\n# #              ('min_child_samples', 158),\n# #              ('min_child_weight', 10.0),\n# #              ('n_estimators', 1359),\n# #              ('num_leaves', 200),\n# #              ('reg_alpha', 1.2411958545694705e-08),\n# #              ('reg_lambda', 0.09431461170037031),\n# #              ('scale_pos_weight', 1.0),\n# #              ('subsample', 0.01),\n# #              ('subsample_freq', 10)])\n# # HistGradientBoostingClassifier took 7254.047643661499 seconds. Candidates checked: 5. Best CV score: 0.8852596335560492 ± 0.006575920281929943.\n# # Best parameters:\n# # OrderedDict([('l2_regularization', 0.44243556998827427),\n# #              ('learning_rate', 0.05506795415296215),\n# #              ('min_samples_leaf', 1068)])\n\n# # OrderedDict([('bagging_fraction', 0.8330075258355067),\n# #              ('bagging_freq', 56),\n# #              ('colsample_bytree', 0.09178544236464188),\n# #              ('feature_fraction', 0.8576383404649194),\n# #              ('learning_rate', 0.02818094163227878),\n# #              ('max_bin', 19),\n# #              ('max_depth', 9),\n# #              ('min_child_samples', 200),\n# #              ('min_child_weight', 8.948517347856354),\n# #              ('n_estimators', 1133),\n# #              ('num_leaves', 74),\n# #              ('reg_alpha', 13.268122393683749),\n# #              ('reg_lambda', 0.043729852822159215),\n# #              ('scale_pos_weight', 29.964531454818747),\n# #              ('subsample', 0.4945354813331461),\n# #              ('subsample_freq', 0)])","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:47:58.826372Z","iopub.execute_input":"2022-07-19T20:47:58.826872Z","iopub.status.idle":"2022-07-19T20:47:58.845600Z","shell.execute_reply.started":"2022-07-19T20:47:58.826835Z","shell.execute_reply":"2022-07-19T20:47:58.844574Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # submissao = '6'\n\n# # clf = LGBMClassifier(\n# # #     boosting_type = 'gbdt',\n# #     metric = 'auc',\n# #     objective = 'binary',\n# #     is_unbalance = True,\n# #     n_jobs = 1, \n# #     verbose = -1,\n# # #     random_state = 0,\n# # #     force_col_wise = True,\n# #     **best_params\n# # )\n\n# # clf = HistGradientBoostingClassifier(\n# #     scoring = 'roc_auc',\n# #     max_iter = 10000,\n# #     max_leaf_nodes = None,\n# #     random_state = 321,\n# #     **best_params\n# # )\n\n# # clf = KNeighborsClassifier(\n# #     **best_params\n# # )\n\n# # clf = GaussianNB( var_smoothing = 6.837286185891733e-10 )\n    \n# # clf.fit( scaled_X_train, y_train )\n\n# # joblib.dump( clf, f'estim_{clf.__class__.__name__}_{submissao}.pkl' )\n\n# # # Baseado em:\n# # # https://stackoverflow.com/questions/63615007/brute-force-model-selection-with-sklearn\n# # # https://www.kaggle.com/code/ihelon/titanic-hyperparameter-tuning-with-gridsearchcv\n\n# classifiers = {\n# # #     'AdaBoost': AdaBoostClassifier(),\n# # #     'CatBoost': CatBoostClassifier( verbose = False ),\n# # #     'DecisionTree': DecisionTreeClassifier(),\n# # #     'MLP': MLPClassifier(),\n# # #     'KNN': KNeighborsClassifier(),\n# # #     'LogisticRegression': LogisticRegression(),\n# #     'RandomForest': RandomForestClassifier(),\n# #     'XGBoost': XGBClassifier(\n# #         objective = 'binary:logistic',\n# #         eval_metric = 'auc',\n# #         learning_rate = 0.05,\n# #         max_depth = 3,\n# #         colsample_bytree = 0.3,\n# #         subsample = 0.8,\n# #         min_child_weight = 50,\n# #         gamma = 10,\n# #     ),\n# # #     'ExtraTrees': ExtraTreesClassifier( n_estimators = 1000 ),\n# #     'GaussianNB': GaussianNB(),\n# # #     'LDA': LinearDiscriminantAnalysis(),\n# #     'LightGBM': LGBMClassifier( \n# #         objective = 'binary',\n# #         boosting = 'gbdt',\n# #         boost_from_average = False,\n# #         seed = 1234,\n# #         bagging_seed = 1234,\n# # #         max_depth = 30,\n# #         metric = 'auc',\n# #         n_jobs = 1, \n# #         verbose = -1,\n# #     ),\n# # #     'LSVC': LinearSVC( max_iter = 100000 ),\n# # #     'NuSVC': NuSVC( nu = 0.25, gamma = 'scale' ),\n# # #     'Ridge': RidgeClassifier(),\n# }\n\n# print( '.................................................................................' )\n# print( f'. {submissao}a submissao ..................................................................')\n\n# for clf_name, clf in classifiers.items():\n#     print( '.................................................................................' )\n#     print( 'Treinamento:', clf_name )\n#     print( '.................................................................................' )\n    \n# # #     params = parameters[ clf_name ]\n\n#     if clf_name != 'LightGBM':\n#         params = {}\n#     else:\n#         params = { \n# #             'num_leaves': [ 60, 61, 62, 63, 64, 65 ],\n# #             'learning_rate': [ 0.01, 0.03, 0.05 ],\n# #             'max_bin': [ 20 ],\n# #             'subsample': [ None ],\n# #             'colsample_bytree': [ None ],\n# #             'min_child_weight': [ None ],\n# #             'min_child_samples': [ None ],\n# #             'subsample_freq': [ None ],\n            \n# #             'bagging_fraction': [0.8330075258355067],\n# #             'bagging_freq': [ 56 ],\n# #             'colsample_bytree': [ 0.09178544236464188 ],\n# #             'feature_fraction': [ 0.8576383404649194 ],\n# #             'learning_rate': [ 0.02818094163227878 ],\n# #             'max_bin': [ 19 ],\n# #             'max_depth': [ 9 ],\n# #             'min_child_samples': [ 200 ],\n# #             'min_child_weight': [ 8.948517347856354 ],\n# #             'n_estimators': [ 1133 ],\n# #             'num_leaves': [ 74 ],\n# #             'reg_alpha': [ 13.268122393683749 ],\n# #             'reg_lambda': [ 0.043729852822159215 ],\n# #             'scale_pos_weight': [ 29.964531454818747 ],\n# #             'subsample': [ 0.4945354813331461 ],\n# #             'subsample_freq': [ 0 ],\n            \n#             # Core Parameters\n#             'learning_rate': [ 0.01 ],\n#             'num_leaves': [ 15 ],\n#             'tree_learner': [ 'serial' ],\n#             'num_threads': [ 8 ],\n\n#             # Learning Control Parameters\n#             'max_depth': [ -1 ],\n#             'min_data_in_leaf': [ 50 ],\n#             'min_sum_hessian_in_leaf': [ 10 ],  \n#             'bagging_fraction': [ 0.6 ],\n#             'bagging_freq': [ 5 ],\n#             'feature_fraction': [ 0.05 ],\n#             'lambda_l1': [ 1.0 ],\n#         }\n    \n#     grid = GridSearchCV(\n#         estimator = clf,\n#         param_grid = params,\n#         cv = 5,\n#         return_train_score = True,\n#         scoring = 'roc_auc',\n#         verbose = 3,\n#     )\n    \n#     grid.fit( scaled_X_train, y_train )\n    \n#     best_dict = {\n#         'best_param': grid.best_params_,\n#         'best_param_test_score_mean': grid.cv_results_[ 'mean_test_score' ][ grid.best_index_ ],\n#         'best_param_test_score_std': grid.cv_results_[ 'std_test_score' ][ grid.best_index_ ],\n#         'best_param_train_score_mean': grid.cv_results_[ 'mean_train_score' ][ grid.best_index_ ],\n#         'best_param_train_score_std': grid.cv_results_[ 'std_train_score' ][ grid.best_index_ ],\n#     },\n      \n#     print( best_dict )\n    \n#     joblib.dump( grid.best_estimator_, f'estim_{grid.best_estimator_.__class__.__name__}_{submissao}.pkl' )","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-19T20:47:58.847068Z","iopub.execute_input":"2022-07-19T20:47:58.847871Z","iopub.status.idle":"2022-07-19T20:48:46.404316Z","shell.execute_reply.started":"2022-07-19T20:47:58.847832Z","shell.execute_reply":"2022-07-19T20:48:46.403010Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Testes dos melhores modelos\n#### Submissão 1\nSabendo que os modelos foram treinados em momentos distintos e que os dados do grid não foram salvos no momento do treinamento (lapso/equívoco), serão realizados novos treinamentos utilizando o `GridSearchCV` para os melhores parâmetros encontrados.\n\nEspera-se, portanto, que o score obtido nos novos treinamentos sejam aproximados, mas não exatamente iguais aos anteriores.\n\nOs dados dos modelos treinados serão salvos e ficarão armazenados em dataset específico após o segundo treinamento.\n\n#### Submissão 2\nNão houve alteração do teste anterior, uma vez que o modelo treinado foi salvo logo após o treinamento.","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# # Os arquivos *.pkl foram salvos após o segundo treinamento com os melhores parâmetros.\n# files = []\n\n# # models_dir = '../input/desafio-santander-transaction-prediction/'\n\n# # for dirname, _, filenames in os.walk( models_dir ):\n# #     for filename in filenames:\n# #         if filename.endswith( '.pkl' ):\n# #             print( filename )\n# #             files.append( os.path.join( models_dir, filename ) )\n            \n# working_dir = '../working/'\n\n# for dirname, _, filenames in os.walk( working_dir ):\n#     for filename in filenames:\n#         if 'LGBM' not in filename:\n#             continue\n            \n#         if filename.endswith( '.pkl' ):\n#             print( filename )\n#             files.append( os.path.join( working_dir, filename ) )\n\n# files = sorted( files )\n\n# # Modelos salvos\n# models = [ joblib.load( file ) for file in files ]","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:48:46.405586Z","iopub.execute_input":"2022-07-19T20:48:46.405974Z","iopub.status.idle":"2022-07-19T20:48:46.421237Z","shell.execute_reply.started":"2022-07-19T20:48:46.405941Z","shell.execute_reply":"2022-07-19T20:48:46.420075Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Avaliação e teste dos modelos (versões anteriores)\n\nUma vez que o melhor modelo tenha sido selecionado, cabe realizar o teste com os dados segmentados no início do processo (`X_test` e `y_test`).","metadata":{"_kg_hide-input":true,"_kg_hide-output":true}},{"cell_type":"code","source":"# # Baseado em https://queirozf.com/entries/visualizing-machine-learning-models-examples-with-scikit-learn-and-matplotlib\n# # if 'scaler' in locals():\n# #     scaled_X_test = scaler.transform( X_test )\n# #     scaled_X_sub = scaler.transform( df_test )\n# # #     scaled_X_sub = scaler.transform( df_real_test )\n# # else:\n# #     scaled_X_test = X_test\n# #     scaled_X_sub = df_test\n\n# scaled_X_test = X_test\n# scaled_X_sub = df_test\n\n# # clf = GaussianNB( var_smoothing = 1.5774315166992275e-10)\n    \n# # clf.fit( scaled_X_train, y_train )\n\n# # scaled_X_test = X_test\n# # scaled_X_sub = df_test\n\n# # print( scaled_X_test.shape )\n# # print( scaled_X_sub.shape )\n\n# # print( 'Classificador:', clf )\n\n# # if hasattr( clf, 'predict_proba' ):\n# #     y_preds = clf.predict_proba( X_test )\n# #     preds = y_preds[ :, 1 ]\n\n# # elif hasattr( clf, 'decision_function' ):\n# #     y_preds = clf.decision_function( X_test )\n# #     preds = y_preds[ : ]\n    \n# # preds_sub = clf.predict( scaled_X_sub )\n\n# # print( preds )\n# # print( preds_sub )\n\n# # fpr, tpr, _ = metrics.roc_curve( y_test, preds )\n# # auc_score = metrics.auc( fpr, tpr )\n\n# # print( auc_score )\n\n# # sub = pd.DataFrame(\n# #     {\n# #         'ID_code': pd.read_csv( '/kaggle/input/santander-customer-transaction-prediction/test.csv' ).ID_code,\n# #         'target': preds_sub,\n# #     }\n# # )\n\n# # model_name = clf.__class__.__name__\n\n# # sub.to_csv( f'sub_{model_name}_{submissao}.csv', index = False )\n\n\n\n\n# # if 'pca' in locals():\n# #     scaled_X_test = pca.transform( scaled_X_test )\n# #     scaled_X_sub = pca.transform( scaled_X_sub )\n    \n# # elif 'pca_fe' in locals():\n# #     df_pca_X_test = pca_fe.transform( scaled_X_test )\n# #     scaled_X_test_pca = np.concatenate( [ scaled_X_test, df_pca_X_test ], axis = 1 )\n# #     df_pca_X_sub = pca_fe.transform( scaled_X_sub )\n# #     scaled_X_sub_pca = np.concatenate( [ scaled_X_sub, df_pca_X_sub ], axis = 1 )\n\n# # Tipo de entrada de acordo com a submissão\n# entradas_por_submissao = {\n# #     '1': ( scaled_X_test[ :, :200 ], scaled_X_sub[ :, :200 ] ),\n# #     '2': ( scaled_X_test[ :, :200 ], scaled_X_sub[ :, :200 ] ),\n# #     '3': ( scaled_X_test, scaled_X_sub ),\n# #     '4': ( scaled_X_test[ :, :200 ], scaled_X_sub[ :, :200 ] ),\n# #     '5': ( scaled_X_test, scaled_X_sub ),\n#     '6': ( scaled_X_test, scaled_X_sub ),\n# }\n\n# # Gráfico\n# num_cols = 4\n# num_rows = math.ceil( len( models ) / num_cols )\n\n# plt.clf()\n\n# fig,axes = plt.subplots( num_rows, num_cols, sharey = True )\n# fig.set_size_inches( num_cols * 5, num_rows * 5 )\n\n# best_auc_score = 0.00\n# best_model = None\n\n# for i, model in enumerate( models ):\n#     model_name = model.__class__.__name__\n    \n#     filename = files[ i ].split( '/' )[ -1 ]\n#     filename = filename.replace( '.pkl', '' )\n    \n#     print( filename )\n    \n#     # Definição da entrada a partir do dicionário entradas_por_submissao\n#     # Motivo: O número de variáveis de entrada foi modificado ao longo das submissões\n#     chave_entrada = filename.split( '_' )[ -1 ]\n    \n#     if chave_entrada not in entradas_por_submissao:\n#         continue\n    \n#     entrada_teste = entradas_por_submissao[ chave_entrada ][ 0 ]\n    \n#     if hasattr( model, 'predict_proba' ):\n#         y_preds = model.predict_proba( entrada_teste )\n#         preds = y_preds[ :, 1 ]\n\n#     elif hasattr( model, 'decision_function' ):\n#         y_preds = model.decision_function( entrada_teste )\n#         preds = y_preds[ : ]\n\n#     print( model_name )\n#     print( preds )\n    \n#     fpr, tpr, _ = metrics.roc_curve( y_test, preds )\n    \n#     auc_score = metrics.auc( fpr, tpr )\n    \n#     if auc_score > best_auc_score:\n#         best_auc_score = auc_score\n#         best_model = model\n    \n#     if num_rows > 1:\n#         ax = axes[ i // num_cols, i % num_cols ]\n#     else:\n#         ax = axes[ i % num_cols ]\n\n#     ax.set_title( f'{filename}', fontsize = 9 )\n#     ax.plot( fpr, tpr, label = f'AUC = {auc_score:.3f}' )\n#     ax.legend( loc = 'lower right' )\n#     ax.plot( [0,1], [0,1], 'k--' )\n#     ax.set_xlim( [ -0.1, 1.1 ] )\n#     ax.set_ylim( [ -0.1, 1.1 ] )\n#     ax.set_ylabel( 'True Positive Rate' )\n#     ax.set_xlabel( 'False Positive Rate' )\n    \n#     entrada_sub = entradas_por_submissao[ chave_entrada ][ 1 ]\n    \n#     preds_sub = model.predict( entrada_sub )\n\n#     sub = pd.DataFrame(\n#         {\n#             'ID_code': pd.read_csv( '/kaggle/input/santander-customer-transaction-prediction/test.csv' ).ID_code,\n#             'target': preds_sub,\n#         }\n#     )\n    \n#     sub.to_csv( f'sub_{model_name}_{submissao}.csv', index = False )\n\n#     print( model_name, filename, f'sub_{model_name}_{submissao}.csv' )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:49:46.168400Z","iopub.execute_input":"2022-07-19T20:49:46.168938Z","iopub.status.idle":"2022-07-19T20:49:59.274625Z","shell.execute_reply.started":"2022-07-19T20:49:46.168893Z","shell.execute_reply":"2022-07-19T20:49:59.273406Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model = best_model\n# modelname = model.__class__.__name__\n\n# filename = files[ models.index( model ) ].split( '/' )[ -1 ]\n\n# preds = model.predict( scaled_X_sub )\n\n# sub = pd.DataFrame(\n#     {\n#         'ID_code': pd.read_csv( '/kaggle/input/santander-customer-transaction-prediction/test.csv' ).ID_code,\n#         'target': preds,\n#     }\n# )\n\n# sub.to_csv( f'sub_{modelname}_{submissao}.csv', index = False )\n\n# print( modelname, filename, f'sub_{modelname}_{submissao}.csv' )","metadata":{"execution":{"iopub.status.busy":"2022-07-19T20:48:46.639804Z","iopub.status.idle":"2022-07-19T20:48:46.640319Z","shell.execute_reply.started":"2022-07-19T20:48:46.640076Z","shell.execute_reply":"2022-07-19T20:48:46.640097Z"},"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]}]}