# -- Code Cell --
# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# 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" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session

# -- Code Cell --
import pandas as pd


# -- Code Cell --
df_train = pd.read_csv("/kaggle/input/competitions/playground-series-s6e3/train.csv").drop(["id"], axis= 1)
df_test = pd.read_csv("/kaggle/input/competitions/playground-series-s6e3/test.csv")
id_test = df_test["id"]
df_test = df_test.drop(["id"], axis = 1)
df_train.head(5)

# -- Code Cell --
X_train = df_train.drop(["Churn"], axis = 1)
y_train = df_train["Churn"]
X_test  = df_test

# -- Code Cell --
from sklearn.preprocessing import LabelEncoder
lbl = LabelEncoder()
y_train = lbl.fit_transform(y_train)

# -- Code Cell --
cat_col = [col for col in X_train.columns if X_train[col].dtype == "O"]
num_col = [col for col in X_train.columns if X_train[col].dtype != "O"]


# -- Code Cell --
from sklearn.preprocessing import StandardScaler, OrdinalEncoder
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
cat_pipeline = Pipeline([
    ("imp", SimpleImputer(strategy = "most_frequent")),
    ("enc", OrdinalEncoder())
])
num_pipeline = Pipeline([
    ("imp", SimpleImputer(strategy = "median")),
    ("enc", StandardScaler())
])
pipeline = ColumnTransformer([
    ("cat",cat_pipeline , cat_col),
    ("num",num_pipeline , num_col),
    
])

# -- Code Cell --
X_train = pipeline.fit_transform(X_train)
X_test = pipeline.transform(X_test)

# -- Markdown Cell --
# PYTORCH

# -- Code Cell --
# Crearea de dataset 3GB Dataset:
# __init__ -> initializam datele
# __len__ -> cat de mare e dataset ul
# __getitem__ -> Ce face la fiecare index
from torch.utils.data import Dataset
import torch
class date_tabulare_dataset(Dataset):
    def __init__(self, X, y, test = False):
        self.X = torch.tensor(X).float()
        self.test = test
        if self.test == False:
            self.y = torch.tensor(y).float()
    def __len__(self):
        return len(self.X)
    def __getitem__(self, index):
        if self.test == False:
            return self.X[index], self.y[index]
        else:
            return self.X[index]

# -- Code Cell --
from sklearn.model_selection import train_test_split
X_tr, X_vl, y_tr, y_vl = train_test_split(X_train, y_train, test_size = 0.2)

# -- Code Cell --
train_dataset =  date_tabulare_dataset(X_tr, y_tr)
valid_dataset =  date_tabulare_dataset(X_vl, y_vl)
test_dataset =  date_tabulare_dataset(X_test,y = None ,test = True)

# -- Code Cell --
train_dataset[0][0].shape

# -- Code Cell --
#DataLoader -> Stacheaza mai mult entry uri
from torch.utils.data import DataLoader
train_loader = DataLoader(train_dataset, batch_size = 32)
valid_loader = DataLoader(valid_dataset, batch_size = 32)
test_loader = DataLoader(test_dataset, batch_size = 32)

# -- Code Cell --
#Definim modelul nostru 
import torch.nn as nn #NN -> Neural network
#FORWARD PROPAGATION
class model_smecher_bengos(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer_0 = nn.Linear(19, 32)
        self.layer_1 = nn.Linear(32, 64)
        self.layer_2 = nn.Linear(64, 16)
        self.layer_3 = nn.Linear(16, 1)
        self.act_1 = nn.ReLU()
        self.act_2 = nn.Sigmoid()
    def forward(self, x):
        x = self.layer_0(x)
        x = self.act_1(x)
        x = self.layer_1(x)
        x = self.act_1(x)
        x = self.layer_2(x)
        x = self.act_1(x)
        x = self.layer_3(x)
        x = self.act_2(x)
        return x

# -- Code Cell --
loss_fn = nn.BCELoss()
model = model_smecher_bengos()
optim = torch.optim.Adam(model.parameters())
epochs = 10

# -- Code Cell --
from sklearn.metrics import roc_auc_score, f1_score
from tqdm.notebook import tqdm
for epoch in range(epochs):
    labels = []
    predicted = []
    for batch in tqdm(train_loader, total = len(train_loader)):
        X = batch[0]
        y = batch[1]

        #Predictia:
        y_hat = model(X).squeeze(1)

        #calc loss
        loss = loss_fn(y_hat, y)

        #Actualizam weight urile
        optim.zero_grad() # Curata
        loss.backward() #Calculeaza
        optim.step() #Actioneaza
        # CCA 
        predicted.extend((y_hat.detach() > 0.5).int().numpy().tolist())
        labels.extend(y.detach().numpy().tolist())
    print(f"Training:{f1_score(np.array(predicted), np.array(labels))}")
    labels = []
    predicted = []
    for batch in tqdm(valid_loader, total = len(valid_loader)):
        X = batch[0]
        y = batch[1]

        #Predictia:
        y_hat = model(X).squeeze(1)
        predicted.extend((y_hat.detach() > 0.5).int().numpy().tolist())
        labels.extend(y.detach().numpy().tolist())
    print(f"Validation:{f1_score(np.array(predicted), np.array(labels))}")

# -- Code Cell --
y_pred =[]
for batch in tqdm(test_loader, total = len(test_loader)):
    X = batch
    y_hat = model(X).squeeze(1)
    y_pred.extend((y_hat.detach() > 0.5).int().numpy().tolist())

# -- Code Cell --
pd.DataFrame({
    "id" : id_test,
    "Churn" :y_pred
}).to_csv("subi.csv", index = False)