"""
# LightGBM GPU Build Installation

* Poor accuracy

* Didn't speedup at all(even after using recommended settings)

[https://lightgbm.readthedocs.io/en/latest/GPU-Performance.html#:~:text=In%20LightGBM%2C%20the%20main%20computation,ranking%2C%20regression%2C%20etc).]
"""
#%%bash
#apt-get install --no-install-recommends git cmake build-essential libboost-dev libboost-system-dev libboost-filesystem-dev
#git clone --recursive https://github.com/microsoft/LightGBM
#cd LightGBM
#mkdir build
#cd build
#cmake -DUSE_GPU=1 -DOpenCL_LIBRARY=/usr/local/cuda/lib64/libOpenCL.so -DOpenCL_INCLUDE_DIR=/usr/local/cuda/include/ ..
#make -j$(nproc)
#cd ..
#cd LightGBM/python-package/;python3 setup.py install --precompile
#mkdir -p /etc/OpenCL/vendors && echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd
#rm -r LightGBM
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 15,15
import seaborn as sns

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

import xgboost as xgb
import lightgbm as lgb
from catboost import CatBoostClassifier

from sklearn.model_selection import train_test_split,StratifiedShuffleSplit,StratifiedKFold
from sklearn.preprocessing import LabelEncoder,RobustScaler
from sklearn.metrics import roc_auc_score,accuracy_score ,confusion_matrix

import warnings
warnings.filterwarnings("ignore")

from imblearn.under_sampling import TomekLinks
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from imblearn.over_sampling import RandomOverSampler
from imblearn.combine import SMOTETomek
from imblearn.under_sampling import ClusterCentroids , NearMiss

from tqdm.notebook import tqdm ,tnrange
train_data = pd.read_csv('../input/healthcareanalyticsii/train.csv')
test_data = pd.read_csv('../input/healthcareanalyticsii/test.csv')
print(train_data.shape)
train_data.head()
print(test_data.shape)
test_data.head()
def nullColumns(train_data):
    list_of_nullcolumns =[]
    for column in train_data.columns:
        total= train_data[column].isna().sum()
        try:
            if total !=0:
                print('Total Na values is {0} for column {1}' .format(total, column))
                list_of_nullcolumns.append(column)
        except:
            print(column,"-----",total)
    print('\n')
    return list_of_nullcolumns


def percentMissingFeature(data):
    data_na = (data.isnull().sum() / len(data)) * 100
    data_na = data_na.drop(data_na[data_na == 0].index).sort_values(ascending=False)[:30]
    missing_data = pd.DataFrame({'Missing Ratio' :data_na})
    return data_na


def plotMissingFeature(data_na):
    f, ax = plt.subplots(figsize=(15, 12))
    plt.xticks(rotation='90')
    if(data_na.empty ==False):
        sns.barplot(x=data_na.index, y=data_na)
        plt.xlabel('Features', fontsize=15)
        plt.ylabel('Percent of missing values', fontsize=15)
        plt.title('Percent missing data by feature', fontsize=15)
print('train data')
print(nullColumns(train_data))
print(percentMissingFeature(train_data))
print('\n')
print('test_data')
print(nullColumns(test_data))
print(percentMissingFeature(test_data))
stay = train_data.loc[:,"Stay"].value_counts().rename('Count')
plt.xlabel("Stay")
plt.ylabel('Count')
sns.barplot(stay.index , stay.values).set_title('Stay')
sns.set(style="white", palette="muted", color_codes=True)

f, axes = plt.subplots(3, 2, figsize=(15, 15))

radiotherapy = train_data[train_data.Department =='radiotherapy']["Stay"].value_counts().rename('Count')

anesthesia = train_data[train_data.Department =='anesthesia']["Stay"].value_counts().rename('Count')

gynecology = train_data[train_data.Department =='gynecology']["Stay"].value_counts().rename('Count')

surgery = train_data[train_data.Department =='surgery']["Stay"].value_counts().rename('Count')

tb = train_data[train_data.Department =='TB & Chest disease']["Stay"].value_counts().rename('Count')

sns.barplot(radiotherapy.index,radiotherapy,  color="b", ax=axes[0, 0]).set_title('Department : radiotherapy')

sns.barplot(anesthesia.index,anesthesia,   color="r", ax=axes[0, 1]).set_title('Department : anesthesia')

sns.barplot(gynecology.index,gynecology,  color="g", ax=axes[1, 0]).set_title('Department : gynecology')

sns.barplot(surgery.index,surgery, color="m", ax=axes[1, 1]).set_title('Department : surgery')

sns.barplot(tb.index,tb, color="m", ax=axes[2, 0]).set_title('Department : TB & Chest disease')

sns.barplot(stay.index,stay, color="m", ax=axes[2, 1]).set_title('Department : ALL')

plt.xlabel("Stay")

plt.setp(axes,yticks = np.arange(0,50000,5000))

for ax in f.axes:
    
    plt.sca(ax)
    
    plt.xticks(rotation=45)

plt.tight_layout()

sns.set(style="white", palette="muted", color_codes=True)

f, axes = plt.subplots(6, 2, figsize=(15, 15))

stay0 = train_data[train_data.Stay =='0-10']["Department"].value_counts().rename('Count')

stay1 = train_data[train_data.Stay =='11-20']["Department"].value_counts().rename('Count')

stay2 = train_data[train_data.Stay =='21-30']["Department"].value_counts().rename('Count')

stay3 = train_data[train_data.Stay =='31-40']["Department"].value_counts().rename('Count')

stay4 = train_data[train_data.Stay =='41-50']["Department"].value_counts().rename('Count')

stay5 = train_data[train_data.Stay =='51-60']["Department"].value_counts().rename('Count')

stay6 = train_data[train_data.Stay =='61-70']["Department"].value_counts().rename('Count')

stay7 = train_data[train_data.Stay =='71-80']["Department"].value_counts().rename('Count')

stay8 = train_data[train_data.Stay =='81-90']["Department"].value_counts().rename('Count')

stay9 = train_data[train_data.Stay =='91-100']["Department"].value_counts().rename('Count')

stay10 = train_data[train_data.Stay =='More than 100 Days']["Department"].value_counts().rename('Count')

sns.barplot(stay0.index,stay0,  color="b", ax=axes[0, 0]).set_title('Stay : 0-10')
                   
sns.barplot(stay1.index,stay2,  color="r", ax=axes[0, 1]).set_title('Stay : 11-20')

sns.barplot(stay2.index,stay2,  color="b", ax=axes[1, 0]).set_title('Stay : 21-30')

sns.barplot(stay3.index,stay3,  color="g", ax=axes[1, 1]).set_title('Stay : 31-40')

sns.barplot(stay4.index,stay4,  color="b", ax=axes[2, 0]).set_title('Stay : 41-50')

sns.barplot(stay5.index,stay5,  color="b", ax=axes[2, 1]).set_title('Stay : 51-60')

sns.barplot(stay6.index,stay6,  color="m", ax=axes[3, 0]).set_title('Stay : 61-70')

sns.barplot(stay7.index,stay7, color="b", ax=axes[3, 1]).set_title('Stay : 71-80')

sns.barplot(stay8.index,stay8,  color="b", ax=axes[4, 0]).set_title('Stay : 81-90')

sns.barplot(stay9.index,stay9,  color="g", ax=axes[4, 1]).set_title('Stay : 91-100')

sns.barplot(stay10.index,stay10, color="r", ax=axes[5, 0]).set_title('Stay : >100')

plt.setp(axes, yticks = np.arange(0,20000,5000))


for ax in f.axes:
    
    plt.sca(ax)
    
    plt.xticks(rotation=45)

plt.tight_layout()
sns.set(style="white", palette="muted", color_codes=True)

f, axes = plt.subplots(3, 1, figsize=(15, 15))

emergency = train_data[train_data['Type of Admission'] =='Emergency']["Stay"].value_counts().rename('Count')

trauma = train_data[train_data['Type of Admission'] =='Trauma']["Stay"].value_counts().rename('Count')

urgent = train_data[train_data['Type of Admission'] =='Urgent']["Stay"].value_counts().rename('Count')

sns.barplot(emergency.index,emergency,  color="b", ax=axes[0]).set_title('Admn. Type : Emergency')

sns.barplot(trauma.index,trauma,   color="r", ax=axes[1]).set_title('Admn. Type : Trauma')

sns.barplot(urgent.index,urgent,  color="g", ax=axes[2]).set_title('Admn. Type : Urgent')

plt.setp(axes, yticks = np.arange(0,50000,10000))

for ax in f.axes:
    
    plt.sca(ax)
    
    plt.xticks(rotation=45)

plt.tight_layout()
train_data['City_Code_Patient'] = train_data['City_Code_Patient'].fillna(-1)
train_data['Bed Grade'] = train_data['Bed Grade'].fillna(-1)
test_data['City_Code_Patient'] = test_data['City_Code_Patient'].fillna(-1)
test_data['Bed Grade'] = test_data['Bed Grade'].fillna(-1)
cat_cols = ['Hospital_code','Hospital_type_code','City_Code_Hospital','Hospital_region_code'
            ,'Department','Ward_Type','Ward_Facility_Code','Bed Grade','City_Code_Patient',
           # 'Type of Admission','Severity of Illness',
            'Age']
label = 'Stay'
def encode_cat_cols(train, test, cat_cols): #target

    train_df = train_data.copy()
    
    test_df = test_data.copy()
    
    # Making a dictionary to store all the labelencoders for categroical columns to transform them later.
    
    le_dict = {}

    for col in cat_cols:
        
        le = LabelEncoder()
        
        le.fit(train_df[col].unique().tolist() + test_df[col].unique().tolist())
        
        train_df[col] = le.transform(train_df[[col]])
        
        test_df[col] = le.transform(test_df[[col]])

        le_dict[col] = le

    le = LabelEncoder()
    
    train_df[label] = le.fit_transform(train_df[[label]])
    
    le_dict[label] = le
    
    train_df['Type of Admission'] = train_df['Type of Admission'].map({'Urgent':0,'Emergency':1,'Trauma':2})
    
    train_df['Severity of Illness'] = train_df['Severity of Illness'].map({'Minor':0,'Moderate':1,'Extreme':2})
    
    test_df['Type of Admission'] = test_df['Type of Admission'].map({'Urgent':0,'Emergency':1,'Trauma':2})
    
    test_df['Severity of Illness'] = test_df['Severity of Illness'].map({'Minor':0,'Moderate':1,'Extreme':2})
    
    return train_df, test_df, le_dict
def feature_importance(model, X_train):

    fI = model.booster_.feature_importance(importance_type='gain')
    
    print(fI)
    
    names = X_train.columns.values
    
    ticks = [i for i in range(len(names))]
    
    plt.bar(ticks, fI)
    
    plt.xticks(ticks, names,rotation = 90)
    
    plt.show()
train_df, test_df, le_dict = encode_cat_cols(train_data,test_data,cat_cols)
#After Feature Engineering
# https://www.kaggle.com/gcspkmdr/lets-get-rid-of-the-patients-feature-engineering

combined_data = pd.read_csv('../input/lets-get-rid-of-the-patients-feature-engineering/combined.csv')
train_df = combined_data[combined_data['train']==1]

test_df = combined_data[combined_data['train']==0]
train_df.drop(columns = ['case_id','train','patientid','Hospital_code',
                         'Hospital_type_code','City_Code_Hospital','Ward_Facility_Code'],inplace = True)

target = train_df.pop('Stay')

test_df.drop(columns = ['case_id','train','Stay','patientid','Hospital_code',
                        'Hospital_type_code','City_Code_Hospital','Ward_Facility_Code'],inplace = True)
cat_features = ['Hospital_region_code','Department','Ward_Type','Bed Grade','City_Code_Patient','Type of Admission','Severity of Illness','Age']

for f in cat_features:
    
    train_df[f] = train_df[f].astype('category')
    
    test_df[f] = test_df[f].astype('category')
"""
# Cross Validation
![](https://4.bp.blogspot.com/-wpr6O3EBAfU/WbHyt6UCOVI/AAAAAAAAjPw/Y1DaO6qcV8oDYjJHzJ1PaPB2EXHmYtBBQCLcBGAs/s1600/%25E6%2593%25B7%25E5%258F%2596.JPG)

* **The CV score generated using the methodology shown in the above figure is a better indicator of model performance than public LB**
"""
%%time

##LightGBM

scores = []

avg_loss = []

X_train_cv,y_train_cv = train_df.copy(), target.copy()

sssf = StratifiedShuffleSplit(n_splits=5, test_size = 0.45 ,random_state=1)

for i, (idxT, idxV) in enumerate(sssf.split(X_train_cv, y_train_cv)):
    
    print('Fold',i)
    
    print(' rows of train =',len(idxT),'rows of holdout =',len(idxV))
    
    clf = lgb.LGBMClassifier(n_estimators=10000,
                             max_depth=8,
                             learning_rate=0.1,
                             subsample=0.85,
                             colsample_bytree=0.5,
                             #device ='gpu',
                             #gpu_platform_id = 0,
                             #gpu_device_id =  0,
                             objective ='multiclass',
                             #max_bin=63,
                             #gpu_use_dp=False,
                             random_state = 1,
                             #categorical_columns = cat_features
                            )        
    
    h = clf.fit(X_train_cv.iloc[idxT], y_train_cv.iloc[idxT], 
                eval_set=[(X_train_cv.iloc[idxV],y_train_cv.iloc[idxV])],
                verbose=100,eval_metric=['multi_logloss'],
                early_stopping_rounds=50)
    
    acc = accuracy_score(y_train_cv.iloc[idxV],np.argmax(clf.predict_proba(X_train_cv.iloc[idxV]),axis =1))*100
    
    scores.append(acc)

    avg_loss.append(clf.best_score_['valid_0']['multi_logloss'])
    
    print ('LGB Val CV=',acc)
    
    print('#'*100)
    
    if i==0:
        feature_importance(clf,X_train_cv)

print("Multi Log Loss Stats {0:.5f},{1:.5f}".format(np.array(avg_loss).mean(), np.array(avg_loss).std()))

print('%.3f (%.3f)' % (np.array(scores).mean(), np.array(scores).std()))
"""
# Model Building
"""
trees = 5

seeds = [32,432,73]

submission = pd.read_csv('../input/healthcareanalyticsii/sample_submission.csv')

probs = np.zeros(shape=(len(test_df),11))

submission_probs = pd.DataFrame(columns = ['case_id'] + list(le_dict['Stay'].classes_))

submission_probs.iloc[:,0] = submission.iloc[:,0]

submission_probs.iloc[:,1:] = 0
%%time

##LightGBM

#groups = train_df['patientid'].values

scores = []

avg_loss = []

submission_name = [] 

X_train_cv,y_train_cv = train_df.copy(), target.copy()

for seed in tnrange(len(seeds)):

    sssf = StratifiedShuffleSplit(n_splits=5, test_size = 0.3 ,random_state=seeds[seed])

    for j, (idxT, idxV) in tqdm(enumerate(sssf.split(X_train_cv, y_train_cv))):

        print('Fold',j)

        print(' rows of train =',len(idxT),'rows of holdout =',len(idxV))

        model_lgb = [0] *trees

        for i in tnrange(trees):

            print('Tree',i)

            model_lgb[i] = lgb.LGBMClassifier(n_estimators=1000,
                                     max_depth=8,
                                     learning_rate=0.1,
                                     subsample=0.8,
                                     colsample_bytree=0.5,
                                     #device ='gpu',
                                     #gpu_platform_id = 0,
                                     #gpu_device_id =  0,
                                     objective ='multiclass',
                                     random_state = i*27
                                    )        

            model_lgb[i].fit(X_train_cv.iloc[idxT], y_train_cv.iloc[idxT], 
                        eval_set=[(X_train_cv.iloc[idxV],y_train_cv.iloc[idxV])],
                        verbose=100,eval_metric=['multi_logloss'],
                        early_stopping_rounds=50)

            probs_file_name = 'probs_'+str(seeds[seed])+'_'+str(j)+'_'+str(i)+".csv"
            
            submisssion_file_name  = 'submission_'+str(seeds[seed])+'_'+str(j)+'_'+str(i)+".csv"
            
            model_lgb_probs = model_lgb[i].predict_proba(test_df)
            
            submission_probs.iloc[:,1:] = model_lgb_probs
            
            # probablity file per seed per split per tree
            submission_probs.to_csv(probs_file_name,index = False)
            
            submission['Stay'] = le_dict['Stay'].inverse_transform(np.argmax(model_lgb_probs,axis =1))
            
            # submission file per seed per split per tree
            submission.to_csv(submisssion_file_name,index =False)
            
            probs += model_lgb_probs
            
            acc = accuracy_score(y_train_cv.iloc[idxV],np.argmax(model_lgb[i].predict_proba(X_train_cv.iloc[idxV]),axis =1))*100
            
            scores.append(acc)
            
            submission_name.append(submisssion_file_name)
            
            avg_loss.append(model_lgb[i].best_score_['valid_0']['multi_logloss'])

            #print ('LGB Accuracy Split =',acc)
            
            print('#'*100)
    

print("Average Multi Log Loss Stats {0:.5f},{1:.5f}".format(np.array(avg_loss).mean(), np.array(avg_loss).std()))

#print('%.3f (%.3f)' % (np.array(scores).mean(), np.array(scores).std()))
submission_probs.iloc[:,1:] = probs

# probablity combined
submission_probs.to_csv('probs.csv',index =False)
submission['Stay'] = le_dict['Stay'].inverse_transform(np.argmax(probs,axis =1))

# submission file combined            
submission.to_csv('submission.csv',index =False)
            
model_stats = pd.DataFrame({'submission':submission_name,'accuracy':scores,'validation_loss':avg_loss})
model_stats.head()
model_stats.to_csv('model_stats.csv',index =False)
# Ensembles
# https://www.kaggle.com/gcspkmdr/lets-get-rid-of-the-patients-xgboost?select=probs.csv
# https://www.kaggle.com/gcspkmdr/lets-get-rid-of-the-patients-catboost/output    