# 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)
from sklearn.preprocessing import OrdinalEncoder
# 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
#Input and test data
df_train = pd.read_csv("/kaggle/input/titanic/train.csv")
df_test = pd.read_csv("/kaggle/input/titanic/test.csv")
#feature importance identification for continuous and categorical variables
#using mutual_information and chi-square test and crammer's v


from sklearn import feature_selection
import math
from scipy import stats
from collections import defaultdict
def feature_importance_classification(features, target, cont_cols, cat_cols, n_neighbors=3,
                                      random_state=None):
    '''chisquare test'''
    cont = features[cont_cols]
    disc = features[cat_cols]

    cont_imp = pd.DataFrame(index=cont.columns)
    disc_imp = pd.DataFrame(index=disc.columns)

    # Continuous features
    if cont_imp.index.size > 0:
        # F-test
        f_test = feature_selection.f_classif(cont, target)
        cont_imp['f_statistic'] = f_test[0]
        cont_imp['f_p_value'] = f_test[1]

        # Mutual information
        mut_inf = feature_selection.mutual_info_classif(cont, target, discrete_features=False,
                                                        n_neighbors=n_neighbors,
                                                        random_state=random_state)
        cont_imp['mutual_information'] = mut_inf

    # Discrete features
    if disc_imp.index.size > 0:

        # Chi²-test
        chi2_tests = defaultdict(dict)

        for feature in disc.columns:
            #             if disc[feature].dtype != np.int32 and disc[feature].dtype != np.int64:
            #                 disc[feature] = disc[feature].apply(lambda x: x.lower())
            cont = pd.crosstab(disc[feature], target)
            statistic, p_value, _, _ = stats.chi2_contingency(cont)
            chi2_tests[feature]['chi2_statistic'] = statistic
            chi2_tests[feature]['chi2_p_value'] = p_value

        chi2_tests_df = pd.DataFrame.from_dict(chi2_tests, orient='index')
        disc_imp['chi2_statistic'] = chi2_tests_df['chi2_statistic']
        disc_imp['chi2_p_value'] = chi2_tests_df['chi2_p_value']

        # Cramér's V (corrected)
        disc_imp['cramers_v'] = [
            cramers_vcorrected_stat(pd.crosstab(feature, target).values)
            for obj_first, feature in disc.iteritems()
        ]

    return cont_imp, disc_imp

def cramers_vcorrected_stat(confusion_matrix):
    """Calculate Cramérs V statistic for categorial-categorial association.

    Uses correction from Bergsma and Wicher, Journal of the Korean Statistical
    Society 42 (2013): 323-328.
    """
    chi2 = stats.chi2_contingency(confusion_matrix)[0]
    number_of_rows = confusion_matrix.sum()
    phi2 = chi2 / number_of_rows
    row, key = confusion_matrix.shape
    phi2_corr = max(0, phi2 - ((key - 1) * (row - 1)) / (number_of_rows - 1))
    r_corr = row - ((row - 1) ** 2) / (number_of_rows - 1)
    k_corr = key - ((key - 1) ** 2) / (number_of_rows - 1)
    return math.sqrt(phi2_corr / min((r_corr - 1), (k_corr - 1)))
#target variable set
target = "Survived"
target_arr = ["Survived"]

#manually separating columns based on their data
cat_cols = ["Pclass","Sex","Embarked","Cabin"]
cont_cols = ["SibSp","Parch","Fare","Age"]
print(df_train[cat_cols+cont_cols+target_arr].shape)
df_final = df_train[cat_cols+cont_cols+target_arr]
df_final[cat_cols] = df_final[cat_cols].fillna(df_final[cat_cols].mode().iloc[0])
df_final[cont_cols] = df_final[cont_cols].fillna(df_final[cont_cols].mean())
feature_importance_classification(df_final,df_final[target],cont_cols,cat_cols)
#After running the feature selection we will select the following
final_cat = ["Pclass","Sex","Cabin"]
final_cont = ["Fare"]
from sklearn.naive_bayes import GaussianNB,CategoricalNB
gc = GaussianNB()
cont_classifier = gc.fit(df_final[cont_cols],df_final[target])
cont_classifier.class_prior_
Cc = CategoricalNB()
oenc = OrdinalEncoder()
out_df = pd.DataFrame(data=oenc.fit_transform(df_final[cat_cols]),columns=cat_cols)
mod = Cc.fit(out_df,df_final[target])
np.exp(mod.class_log_prior_)
"""
we can take prior probability of the classes from cont_classifier as cont_classifier.class_prior_ or from CategoricalNB as np.exp(mod.class_log_prior_)
"""
print(df_test[cat_cols+cont_cols].shape)
# test_final = df_test[cat_cols+cont_cols].dropna()
df_test[cat_cols] = df_test[cat_cols].fillna(df_test[cat_cols].mode().iloc[0])
df_test[cont_cols] = df_test[cont_cols].fillna(df_test[cont_cols].mean())
test_final = df_test[cat_cols+cont_cols]
print(test_final.shape)
test_out_df = oenc.fit_transform(test_final[cat_cols])
pred2 = cont_classifier.predict_log_proba(test_final[cont_cols])
pred1 = mod.predict_log_proba(test_out_df)
n = len(cat_cols)+len(cont_cols)
#jll - sum of log probability of continuous and categorical data

log_prior = mod.class_log_prior_
jlls = []
jlls.append(cont_classifier._joint_log_likelihood(test_final[cont_cols]))
jlls.append(mod._joint_log_likelihood(np.array(test_out_df.astype(int))))

jlls = np.hstack([jlls])

jlls = jlls - log_prior
jll = jlls.sum(axis=0) + log_prior
#Standardising the results
fo = np.exp(jll)
sumso = np.sum(fo, axis = 1, keepdims = True) 
result = fo/sumso
#Output calculation
y_pred = np.argmax(result,axis=1)
zz = zip(df_test["PassengerId"],y_pred)
out = [[a[0],a[1]] for a in zz]
my_submission = pd.DataFrame(out,columns=["PassengerId","Survived"])
my_submission.to_csv('submission_1.csv', index=False)

# df_test["PassengerId"].shape
# y_pred.shape