# 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.metrics import accuracy_score
import matplotlib.pyplot as plt
import seaborn as sns

import warnings
warnings.filterwarnings('ignore')

# 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

train=pd.read_csv('/kaggle/input/titanic/train.csv',header=0)
test=pd.read_csv('/kaggle/input/titanic/test.csv',header=0)

"""
# Feature Engineering
"""
# I expect that having other people to think about will 
# affect someone's chance of survival
train["Alone"] = train["Parch"] == 0
train["Relatives"] = train["Parch"] + train["SibSp"]

test["Alone"] = test["Parch"] == 0
test["Relatives"] = test["Parch"] + test["SibSp"]

train.sample(5)
median = train['Age'].median()
train['Age'].fillna(median, inplace = True)
test['Age'].fillna(median, inplace = True)

bins = [0, 2, 12, 17, 60, np.inf]
labels = ['baby', 'child', 'teenager', 'adult', 'elderly']
age_groups = pd.cut(train.Age, bins, labels = labels)
train['AgeGroup'] = age_groups

age_groups = pd.cut(test.Age, bins, labels = labels)
test['AgeGroup'] = age_groups
sns.barplot(x="AgeGroup", y="Survived", data=train)
plt.show()
median = train['Fare'].median()
train['Fare'].fillna(median, inplace = True)
test['Fare'].fillna(median, inplace = True)
from sklearn.preprocessing import KBinsDiscretizer

continuous = ['Age', 'Fare']

fig, axs = plt.subplots(1, len(continuous),figsize=(len(continuous) * 6,6))

for ind,feature in enumerate(continuous):
    bin_feature = feature + 'Bin'
    est = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='uniform')
    est.fit(train[[feature]])
    train[bin_feature] = est.transform(train[[feature]])
    test[bin_feature]= est.transform(test[[feature]])
    sns.barplot(x=bin_feature, y="Survived", data=train, ax = axs[ind])
    
train
from sklearn.preprocessing import LabelEncoder

categorical = ['Sex', 'AgeBin','FareBin','AgeGroup']
for feature in categorical:
    label = LabelEncoder()
    print(feature)
    label.fit(train[feature])
    train[feature] = label.transform(train[feature])
    test[feature] = label.transform(test[feature])
train
features = ['Sex', 'Pclass', 'SibSp', 'Parch', 'Embarked', 'Alone', 'Relatives', 'FareBin']
fig, axs = plt.subplots(1, len(features),figsize=(len(features) * 6,6))
for ind, x in enumerate(features):

    g = sns.countplot(
        data=train, ax = axs[ind],
        x=x,  palette="dark", alpha=.6
    )
features = ['Sex', 'Pclass', 'SibSp', 'Parch', 'Embarked', 'Alone', 'Relatives', 'FareBin']
fig, axs = plt.subplots(1, len(features),figsize=(len(features) * 6,6))
for ind, x in enumerate(features):
    print('Survival Probability by', x)
    print(train[[x, "Survived"]].groupby(x, as_index=False).mean()) 
    print()
    print()

    sns.barplot(x, y="Survived", data=train, ax = axs[ind])
    
"""
We learn that 
 - Being alone reduces survival probability but having too many relatives reduces chances
 - Women are a lot more likely to survive
 - The rich are more likely to survive (position of rooms like in the movie?)
 - Where you got on board affects survival probability
 
## Questions
 - Do the ports of embarkation correlate with class? Do the poor people come from S? Are Embarked and Pclass collinear?
"""
# Collinearity of Port and class
one_hot_train = pd.get_dummies(train[["Pclass", "Embarked"]],  columns=["Pclass", "Embarked"])
corr = one_hot_train.corr()

cmap = sns.diverging_palette(210, 20, as_cmap=True)
sns.heatmap(corr, cmap=cmap,
            square=True, linewidths=.5)

corr
"""
No, looks like a very weak correlation between port and pclass.
"""
corr = pd.get_dummies(train[["FareBin", "Pclass"]], columns=["FareBin", "Pclass"]).corr()

cmap = sns.diverging_palette(210, 20, as_cmap=True)
sns.heatmap(corr, cmap=cmap,
            square=True, linewidths=.5)

corr
main_features = ['Sex',"Relatives",'AgeBin',"FareBin"]
X_test = test[main_features]
X_train = train[main_features]
y_train = train['Survived']

from sklearn.model_selection import cross_validate
from sklearn.ensemble import VotingClassifier, RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

ensemble = [
    ("RandomForestClassifier", RandomForestClassifier(max_leaf_nodes=10)), 
    ("KNeighborsClassifier", KNeighborsClassifier(n_neighbors=3)),
    ("SVM Classifier",make_pipeline(StandardScaler(), SVC(gamma='auto')))
]

voting = VotingClassifier(ensemble, voting='hard')

cv_results = cross_validate(voting, X_train, y_train, cv=5)
print(cv_results['test_score'].mean())

voting.fit(X_train, y_train)
y_pred = voting.predict(X_test)
output = pd.DataFrame({'PassengerId': test.PassengerId, 'Survived': y_pred.astype(int)})
output.to_csv('submission.csv', index=False)