"""
# No need of imputation for missing values in the given dataset, you can still achieve a very good score on LB.
"""
"""

# This Notebook achieved a score of 0.85948 on LB.
"""
"""
# Aim and Objectives:

**This Notebook was created purposely to share ideas, learn and to reveal some underlying facts inside the given WIDS datasets.**
"""
"""
# Feel free to fork or replicate this Notebook.
"""
"""




# Note: Please, don't forget to upvote this Notebook if you find it very useful. 


"""
"""

# The following steps below were taken to achieve this aforementioned score on the Leaderboard:

- Groupby count of categorical variables using 'encounter_id'.
- Get rid of unwanted features e.g hospital_id & constant variable "read-admission". 
- Fill nan's with "9999" and performing some filling missing values techniques on features like "age" & gender respectively.
- Implementating Exploratory Data Analysis (EDA) showing some relationships between feature "age" and all categorical features in the given dataset.
- Creating dummy for all categorical features.
- Applying Oversampling technique on the minority class "1" of the target variable "diabetes_mellitus".
- Three different types of LGBClassifier models were implemented (each with accuracy score of over 85% respectively).
"""
# 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
pip install --upgrade pip
import numpy as np
import pandas as pd
import random
seed = 44  
random.seed(seed)
np.random.seed(seed)
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import plotly.graph_objects as go

import warnings
warnings.filterwarnings("ignore")
train =  pd.read_csv("/kaggle/input/wids-datasets/TrainingWiDS2021.csv")
test = pd.read_csv("/kaggle/input/wids-datasets/UnlabeledWiDS2021.csv")
submission = pd.read_csv("/kaggle/input/wids-datasets/SolutionTemplateWiDS2021.csv")
train = train.drop(['Unnamed: 0'], axis =1)
train.head()
test = test.drop(['Unnamed: 0'], axis =1)
test.head()
submission.head()
train.shape, test.shape, submission.shape
train.info()
train.dtypes
train.columns
"""
# Getting rid of unwanted features:
"""
train = train.drop(['hospital_id'], axis = 1)   # "hospital_id" has no positive effcet on model performance
test = test.drop(['hospital_id'], axis = 1)

train = train.drop(['readmission_status'], axis = 1) # "readmission_status" being a constant feature
test = test.drop(['readmission_status'], axis = 1)
train['encounter_id'] = train['encounter_id'].astype("object")
train['icu_id'] = train['icu_id'].astype("object")

test['encounter_id'] = test['encounter_id'].astype("object")
test['icu_id'] = test['icu_id'].astype("object")
"""
# Checking for categorical features
"""
categorical_feats= train.dtypes[train.dtypes == "object"].index; categorical_feats
"""
# Checking for numerical features
"""
numerical_feats= train.dtypes[train.dtypes != "object"].index; numerical_feats
"""
# Feature Engineering:
"""
train['ethnicity_count']= train.groupby(["ethnicity"])["encounter_id"].transform("count")
train['gender_count']= train.groupby(["gender"])["encounter_id"].transform("count")
train['hospital_admit_source_count']= train.groupby(["hospital_admit_source"])["encounter_id"].transform("count")
train['icu_admit_source_count']= train.groupby(["icu_admit_source"])["encounter_id"].transform("count")
train['icu_stay_type_count']= train.groupby(["icu_stay_type"])["encounter_id"].transform("count")
train['icu_type_count']= train.groupby(["icu_type"])["encounter_id"].transform("count")
train['icu_id_count']= train.groupby(["icu_id"])["encounter_id"].transform("count")

test['ethnicity_count']= test.groupby(["ethnicity"])["encounter_id"].transform("count")
test['gender_count']= test.groupby(["gender"])["encounter_id"].transform("count")
test['hospital_admit_source_count']= test.groupby(["hospital_admit_source"])["encounter_id"].transform("count")
test['icu_admit_source_count']= test.groupby(["icu_admit_source"])["encounter_id"].transform("count")
test['icu_stay_type_count']= test.groupby(["icu_stay_type"])["encounter_id"].transform("count")
test['icu_type_count']= test.groupby(["icu_type"])["encounter_id"].transform("count")
test['icu_id_count']= test.groupby(["icu_id"])["encounter_id"].transform("count")
list(numerical_feats)
train.shape, test.shape
"""
# Join train and test together
"""
ntrain = train.shape[0]
ntest = test.shape[0]

all_data = pd.concat((train, test)).reset_index(drop=True)
print("all_data size is : {}".format(all_data.shape))
num_col =  ['age','bmi','elective_surgery','height','pre_icu_los_days','weight', 
            'albumin_apache','apache_2_diagnosis','apache_3j_diagnosis','apache_post_operative','arf_apache',
            'bilirubin_apache','bun_apache','creatinine_apache','fio2_apache','gcs_eyes_apache','gcs_motor_apache',
            'gcs_unable_apache','gcs_verbal_apache','glucose_apache','heart_rate_apache','hematocrit_apache',
            'intubated_apache','map_apache','paco2_apache','paco2_for_ph_apache','pao2_apache','ph_apache',
            'resprate_apache','sodium_apache','temp_apache','urineoutput_apache','ventilated_apache','wbc_apache',
            'd1_diasbp_invasive_max','d1_diasbp_invasive_min','d1_diasbp_max','d1_diasbp_min',
            'd1_diasbp_noninvasive_max','d1_diasbp_noninvasive_min','d1_heartrate_max','d1_heartrate_min',
            'd1_mbp_invasive_max','d1_mbp_invasive_min','d1_mbp_max','d1_mbp_min','d1_mbp_noninvasive_max',
            'd1_mbp_noninvasive_min','d1_resprate_max','d1_resprate_min','d1_spo2_max','d1_spo2_min',
            'd1_sysbp_invasive_max','d1_sysbp_invasive_min','d1_sysbp_max','d1_sysbp_min','d1_sysbp_noninvasive_max',
            'd1_sysbp_noninvasive_min','d1_temp_max','d1_temp_min','h1_diasbp_invasive_max','h1_diasbp_invasive_min',
            'h1_diasbp_max','h1_diasbp_min','h1_diasbp_noninvasive_max','h1_diasbp_noninvasive_min','h1_heartrate_max',
            'h1_heartrate_min','h1_mbp_invasive_max','h1_mbp_invasive_min','h1_mbp_max','h1_mbp_min',
            'h1_mbp_noninvasive_max','h1_mbp_noninvasive_min','h1_resprate_max','h1_resprate_min','h1_spo2_max',
            'h1_spo2_min','h1_sysbp_invasive_max','h1_sysbp_invasive_min','h1_sysbp_max','h1_sysbp_min',
            'h1_sysbp_noninvasive_max','h1_sysbp_noninvasive_min','h1_temp_max','h1_temp_min','d1_albumin_max',
            'd1_albumin_min','d1_bilirubin_max','d1_bilirubin_min','d1_bun_max','d1_bun_min','d1_calcium_max',
            'd1_calcium_min','d1_creatinine_max','d1_creatinine_min','d1_glucose_max','d1_glucose_min',
            'd1_hco3_max','d1_hco3_min','d1_hemaglobin_max','d1_hemaglobin_min','d1_hematocrit_max',
            'd1_hematocrit_min','d1_inr_max','d1_inr_min','d1_lactate_max','d1_lactate_min','d1_platelets_max',
            'd1_platelets_min','d1_potassium_max','d1_potassium_min','d1_sodium_max','d1_sodium_min','d1_wbc_max',
            'd1_wbc_min','h1_albumin_max','h1_albumin_min','h1_bilirubin_max','h1_bilirubin_min','h1_bun_max',
            'h1_bun_min','h1_calcium_max','h1_calcium_min','h1_creatinine_max','h1_creatinine_min','h1_glucose_max',
            'h1_glucose_min','h1_hco3_max','h1_hco3_min','h1_hemaglobin_max','h1_hemaglobin_min','h1_hematocrit_max',
            'h1_hematocrit_min','h1_inr_max','h1_inr_min','h1_lactate_max','h1_lactate_min','h1_platelets_max',
            'h1_platelets_min','h1_potassium_max','h1_potassium_min','h1_sodium_max','h1_sodium_min','h1_wbc_max',
            'h1_wbc_min','d1_arterial_pco2_max','d1_arterial_pco2_min','d1_arterial_ph_max','d1_arterial_ph_min',           
            'd1_arterial_po2_max','d1_arterial_po2_min','d1_pao2fio2ratio_max',
            'd1_pao2fio2ratio_min','h1_arterial_pco2_max','h1_arterial_pco2_min','h1_arterial_ph_max',
            'h1_arterial_ph_min','h1_arterial_po2_max','h1_arterial_po2_min','h1_pao2fio2ratio_max',
            'h1_pao2fio2ratio_min','aids','cirrhosis','hepatic_failure','immunosuppression','leukemia','lymphoma',
            'solid_tumor_with_metastasis','diabetes_mellitus','ethnicity_count','gender_count',
            'hospital_admit_source_count','icu_admit_source_count','icu_stay_type_count','icu_type_count']

cat_col = [col for col in test.columns if col not in num_col]
cat_col
cat_col.remove('encounter_id')
train.describe()
test.describe()
sns.countplot(train.diabetes_mellitus)
"""
**The dataset is skewed towards class 0, consider balancing the dataset.**
"""
print("Are There Missing value in train? :",train.isnull().any().any())
print((train.isnull().sum()/train.shape[0])*100)
print("Are There Missing value in test? :",test.isnull().any().any())
print((test.isnull().sum()/test.shape[0])*100)
"""
# Remember to handle the missing values.
"""
f,ax=plt.subplots(figsize=(8,8))
sns.heatmap(train.corr(),annot=True,linewidth=.5,fmt='.1f',ax=ax)
plt.show()
all_data.head()
def check_categorical_relationship(cat_col,y_col,df):
    for feat in cat_col:
        plt.figure(figsize=(20,5))
        sns.barplot(df[feat],df[y_col])
        plt.show()
        print("\n \n \n ")
check_categorical_relationship(cat_col,'age',all_data)
all_data.gender.unique()
"""
# Fill mising value
"""
all_data = all_data.fillna(9999)
all_data.head()
print("Are There still Missing value in data? :",all_data.isnull().any().any())
print((all_data.isnull().sum()/all_data.shape[0])*100)
all_data.gender.unique()
mapper = {"M":"M","F":'F',9999:'O'}
all_data.gender = all_data.gender.map(mapper)
all_data.gender.unique()
final_data=pd.get_dummies(all_data,columns=cat_col)
all_data.diabetes_mellitus = all_data.diabetes_mellitus.astype(int)
final_data.diabetes_mellitus = final_data.diabetes_mellitus.astype(int)
final_data.drop(columns=['encounter_id'],inplace=True)
#Get the new dataset
train_n = final_data[:ntrain]
test_n = final_data[ntrain:]
TARGET_COL = 'diabetes_mellitus'
train_n[TARGET_COL].value_counts()/len(train_n)
print(train_n.shape,test_n.shape)
# Separate majority and minority classes
from sklearn.model_selection import train_test_split
from sklearn.utils import resample
df_majority = train_n[train_n['diabetes_mellitus']==0]
df_minority = train_n[train_n['diabetes_mellitus']==1]

df_minority_upsampled = resample(df_minority, 
                                 replace=True,     # sample with replacement
                                 n_samples=83798,    # to match majority class
                                 random_state= 303) # reproducible results
 
# Combine majority class with upsampled minority class
df_upsampled = pd.concat([df_majority, df_minority_upsampled])
 
# Display new class counts
df_upsampled.diabetes_mellitus.value_counts()
train_n = df_upsampled
X= train_n.drop(columns=['diabetes_mellitus'])
y= train_n.diabetes_mellitus
"""
# LGBMClassifier 1:
"""
!pip install lightgbm
import lightgbm as lgb   
model = lgb.LGBMClassifier(random_state=44,n_estimators=1000,silent=False,
                           scale_pos_weight= 1,colsample_bylevel=0.8,subsample=0.8)  
model.fit(X,y)
fea_imp = pd.DataFrame({'imp': model.feature_importances_, 'col': X.columns})
fea_imp.sort_values(by='imp',ascending=False,inplace=True)
fea_imp.head(30)
index_to_use_later = test['encounter_id'].values
cols=list(X.columns)
output= model.predict_proba(test_n[cols])
submission_df = pd.DataFrame(columns=['encounter_id','diabetes_mellitus'])    
submission_df['encounter_id'] = index_to_use_later
submission_df['diabetes_mellitus'] = output[:,1]              # 0.85382 on LB
submission_df.to_csv('lgb1_sub.csv',index=False)    
submission_df.head()
"""
# LGBMClassifier 2 (with 5kfolds):
"""
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,random_state=42,stratify = y)
import lightgbm as lgb
clf1 = lgb.LGBMClassifier(boosting_type='gbdt', class_weight=None, colsample_bylevel=0.8,
               colsample_bytree=1.0, importance_type='split', learning_rate=0.1,
               max_depth=-1, min_child_samples=20, min_child_weight=0.001,
               min_split_gain=0.0, n_estimators=1000, n_jobs=-1, num_leaves=31,
               objective=None, random_state=44, reg_alpha=0.0, reg_lambda=0.0,
               scale_pos_weight=1, silent=False, subsample=0.8,
               subsample_for_bin=200000, subsample_freq=0)  
from sklearn.model_selection import KFold,StratifiedKFold
kf = StratifiedKFold(n_splits= 5, shuffle=True)

predicts = []
for train_index, test_index in kf.split(X, y):
    print("###")
    X_train, X_val = X.iloc[train_index], X.iloc[test_index]
    y_train, y_val = y.iloc[train_index], y.iloc[test_index]
    clf1.fit(X_train, y_train, eval_set=[(X_val, y_val)], early_stopping_rounds=100,verbose=200)
    predicts.append(clf1.predict_proba(X_test))  
test_pred = clf1.predict_proba(test_n[cols])
submit = pd.DataFrame({'encounter_id':index_to_use_later})
submit['diabetes_mellitus'] = test_pred[:,1]
submit.to_csv("sub_lgb2_5kfold.csv", index = False)           # 0.85005 on LB                                                        
submit.head()
"""
# LGBMClassifier 3:
"""
model= lgb.LGBMClassifier(random_state=44,early_stopping_rounds = 250,
                      n_estimators=10000,min_data_per_group=5, # reduce overfitting when using categorical_features
                      boosting_type='gbdt',num_leaves=151,max_depth=- 1,
                      learning_rate=0.02,subsample_for_bin=200000, 
                      min_split_gain=0.0,min_child_weight=0.001,min_child_samples=20,
                      subsample=1.0,subsample_freq=0,colsample_bytree=.75,reg_alpha=1.3, 
                      reg_lambda=0.1,n_jobs=- 1,cat_smooth=1.0, 
                      silent=True, importance_type='split')                                   
model.fit(X_train,y_train,eval_set=[(X_test, y_test)],eval_metric = 'auc',verbose=False)
from sklearn.metrics import accuracy_score
from sklearn import metrics
print(f"accuracy score is {accuracy_score(y_test, model.predict(X_test))}")              
print(metrics.classification_report(y_test, model.predict(X_test), labels=[0, 1]))
test_pred = model.predict_proba(test_n[cols])
submit = pd.DataFrame({'encounter_id':index_to_use_later})
submit['diabetes_mellitus'] = test_pred[:,1]
submit.to_csv("sub_lgb3.csv", index = False)         # 0.85948                                                           
submit.head()
"""
# Grid Search Approach
"""
#def algorithm_pipeline(X_train_data, X_test_data, y_train_data, y_test_data, X_test,y_test,
#                       model, param_grid, cv=10, scoring_fit='neg_mean_squared_error',
#                       do_probabilities = False):
#    gs = GridSearchCV(
#        estimator=model,
#        param_grid=param_grid, 
#        cv=cv, 
#        n_jobs=-1, 
#        scoring=scoring_fit,
#        verbose=2
#    )
#    fitted_model = gs.fit(X_train_data, y_train_data, eval_set=[(X_test, y_test)], eval_metric='l1')
    
#    if do_probabilities:
#      pred = fitted_model.predict_proba(X_test_data)
#    else:
#      pred = fitted_model.predict(X_test_data)
    
#    return fitted_model, pred
#from sklearn.model_selection import GridSearchCV, RandomizedSearchCV

#model = lgb.LGBMClassifier()
#param_grid = {
#    'learning_rate' : [0.03,0.04,0.05,0.06],
#    'n_estimators': [1000],
#     'colsample_bytree': [0.7],
#     'max_depth': [20],
#     'num_leaves': [50, 100, 200],
#     'reg_alpha': [1.1, 1.2, 1.3],
#     'reg_lambda': [1.1, 1.2, 1.3],
#     'min_split_gain': [0.3, 0.4],
#     'subsample': [0.7, 0.8, 0.9],
#     'subsample_freq': [20]
#}

#model, pred = algorithm_pipeline(X_train, X_test, y_train, y_test,X_test,y_test, model, 
#                                 param_grid, cv=5, scoring_fit='accuracy')

#print(model.best_score_)
#print(model.best_params_)