import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from sklearn import svm
import warnings
import seaborn as sns
import csv as csv

from sklearn.linear_model import SGDClassifier
from sklearn.utils import check_array
from sklearn import preprocessing
from sklearn.cross_validation import train_test_split
from sklearn.cross_validation import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import make_scorer, accuracy_score
from sklearn.cluster import KMeans
from sklearn import linear_model

warnings.filterwarnings("ignore")

le = preprocessing.LabelEncoder()


def process_Cabin(df):
    df['Cabin'].fillna('N')
    # cleaning up data
    df['Cabin'] = df['Cabin'].apply(lambda x: x[0] if isinstance(x, str) else '$')
    le = preprocessing.LabelEncoder()
    df['Cabin'] = le.fit_transform(df['Cabin'])
    return df


def process_Ticket(df):
    df['Ticket'].fillna('N')
    # cleaning up data
    df['Ticket'] = df['Ticket'].apply(lambda x: x[0:1] if isinstance(x, str) else '$')
    le = preprocessing.LabelEncoder()
    df['Ticket'] = le.fit_transform(df['Ticket'])
    return df


def process_ports(df):
    if len(df.Age[df.Embarked.isnull()]) > 0:
        df.loc[(df.Embarked.isnull()), 'Embarked'] = '$'
    le = preprocessing.LabelEncoder()
    df['Embarked'] = le.fit_transform(df['Embarked'])
    return df


def process_gender(df):
    df['Sex'] = df['Sex'].map({'female': 0, 'male': 1}).astype(int)
    return df


def process_age(df):
    df.Age = df.Age.fillna(-0.5)
    bins = (-1, 0, 5, 12, 18, 25, 35, 60, 120)
    group_names = ['Unknown', 'Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Senior']
    categories = pd.cut(df.Age, bins, labels=group_names)
    df.Age = categories

    df['Age'] = le.fit_transform(df['Age'])
    return df


def process_names(df):
    df['Lname'] = df.Name.apply(lambda x: x.split(' ')[0])
    df['Lname'] = le.fit_transform(df['Lname'])
    df['NamePrefix'] = df.Name.apply(lambda x: x.split(' ')[1])
    # print(df['NamePrefix'].unique())
    df['NamePrefix'] = le.fit_transform(df['NamePrefix'])
    return df


def drop_Features(df):
    return df.drop(['Parch', 'Ticket', 'Fare', 'Embarked', 'Lname', 'NamePrefix', 'Cabin', 'SibSp'], axis=1)


def run_kfold(clf, X_all, y_all, folds):
    kf = KFold(X_all.count()[0], n_folds=folds)
    outcomes = []
    fold = 0

    X_all = X_all.copy()

    median_age = X_all['Age'].dropna().median()
    if len(X_all.Age[X_all.Age.isnull()]) > 0:
        X_all.loc[(X_all.Age.isnull()), 'Age'] = median_age

    for train_index, test_index in kf:
        fold += 1
        X_train, X_test = X_all.values[train_index], X_all.values[test_index]
        y_train, y_test = y_all.values[train_index], y_all.values[test_index]
        clf.fit(X_train, y_train)
        predictions = clf.predict(X_test)
        accuracy = accuracy_score(y_test, predictions)
        outcomes.append(accuracy)
        print("Fold {0} accuracy: {1}".format(fold, accuracy))
    mean_outcome = np.mean(outcomes)
    print("Mean Accuracy: {0}".format(mean_outcome))


def getMajority(classifiers, weight, param):
    sum = 0
    prediction = classifiers[0].predict(param)
    prediction = -1 if prediction == 0 else 1
    sum = sum + weight[0] * prediction

    prediction = classifiers[1].predict(param)
    prediction = -1 if prediction == 0 else 1
    sum = sum + weight[1] * prediction

    prediction = classifiers[2].predict(param)
    prediction = -1 if prediction == 0 else 1
    sum = sum + weight[2] * prediction

    return 1 if sum > 0 else 0


desired_width = 320
pd.set_option('display.width', desired_width)

data_train = pd.read_csv("../input/train.csv")
data_test = pd.read_csv('../input/test.csv')

data_train = process_Cabin(data_train)
data_train = process_ports(data_train)
data_train = process_gender(data_train)
data_train = process_Ticket(data_train)
data_train = process_age(data_train)
data_train = process_names(data_train)
data_train = drop_Features(data_train)
# All the ages with no input -> make the median of all Ages
num = data_train.count()
print(num[0])

# print(median_age)

# print(data_train.Embarked.unique())
# print(data_train.Ticket.unique())
# print(data_train[0:100])


X_all = data_train.drop(['Survived', 'PassengerId', 'Name'], axis=1)
y_all = data_train['Survived']

# print(X_all[0:100])


num_test = 0.10
X_train, X_test, y_train, y_test = train_test_split(X_all, y_all, test_size=num_test, random_state=23)

classifiers = []
weight = []

clf = RandomForestClassifier(n_estimators=50, n_jobs=-1, criterion='gini')
classifiers.append(clf)
classifiers[0].fit(X_train, y_train)
predictions = classifiers[0].predict(X_test)
accuracy = accuracy_score(y_test, predictions)
weight.append(accuracy)
print("Total accuracy of randomforest: {0}".format(accuracy))

clf = svm.SVC(C=2, probability=True)
classifiers.append(clf)
classifiers[1].fit(X_train, y_train)
predictions = classifiers[1].predict(X_test)
accuracy = accuracy_score(y_test, predictions)
weight.append(accuracy)
print("Total accuracy of SVM: {0}".format(accuracy))

clf = SGDClassifier(alpha=0.0001, average=False, class_weight=None, epsilon=0.2,
                    eta0=0.0, fit_intercept=True, l1_ratio=0.15,
                    learning_rate='optimal', loss='hinge', n_iter=1000000, n_jobs=-1,
                    penalty='l2', power_t=0.5, random_state=None, shuffle=True,
                    verbose=0, warm_start=False)

classifiers.append(clf)
classifiers[2].fit(X_train, y_train)
predictions = classifiers[2].predict(X_test)
accuracy = accuracy_score(y_test, predictions)
weight.append(accuracy)
print("Total accuracy of SGD: {0}".format(accuracy))

# 4th

clf = SGDClassifier(alpha=0.0001, average=False, class_weight=None, epsilon=0.2,
                    eta0=0.0, fit_intercept=True, l1_ratio=0.15,
                    learning_rate='optimal', loss='hinge', n_iter=1000000, n_jobs=-1,
                    penalty='l2', power_t=0.5, random_state=None, shuffle=True,
                    verbose=0, warm_start=False)

classifiers.append(clf)
classifiers[2].fit(X_train, y_train)
predictions = classifiers[2].predict(X_test)
accuracy = accuracy_score(y_test, predictions)
weight.append(accuracy)
print("Total accuracy of SGD: {0}".format(accuracy))

err = 0

for i in range(len(X_test.index)):
    predictions[i] = getMajority(classifiers, weight, X_test.irow(i))

accuracy = accuracy_score(y_test, predictions)
weight.append(accuracy)
print("Total accuracy of VOtes: {0}".format(accuracy))

# print("score is {0}".format(clf.score(X,Y)))


with open("submission.csv", "w") as predictions_file:
    predictions_file_object = predictions_file
    predictions_file_object.write('PassengerId,Survived\r\n')

    test_data = pd.read_csv("../input/test.csv")
    test_passengerId = test_data['PassengerId'].copy()

    test_data = process_gender(test_data)
    test_data = process_Cabin(test_data)
    test_data = process_ports(test_data)
    test_data = process_Ticket(test_data)
    test_data = process_age(test_data)
    test_data = process_names(test_data)
    test_data = drop_Features(test_data)
    # TODO: add cabin and see if it makes difference.
    test_data = test_data.drop(['Name', 'PassengerId'], axis=1)

    test_inputs = test_data

    for ix in range(len(test_data.index)):
        inputVector = test_inputs.irow(ix)
        inputVector = np.nan_to_num(inputVector)
        inputVector = check_array(inputVector, accept_sparse='csr', dtype=np.float64, order="C")
        estimatedLabel = output = getMajority(classifiers, weight, inputVector)
        if estimatedLabel == -1:
            estimatedLabel = 0
        predictions_file_object.write("{0},{1}\r\n".format(test_passengerId[ix], estimatedLabel))

    predictions_file.close()



    # Close out the files

    #
    # [100 rows x 3 columns]
    # Fold
    # 1
    # accuracy: 0.7222222222222222
    # Fold
    # 2
    # accuracy: 0.7777777777777778
    # Fold
    # 3
    # accuracy: 0.8333333333333334
    # Fold
    # 4
    # accuracy: 0.8518518518518519
    # Fold
    # 5
    # accuracy: 0.7169811320754716
    # Fold
    # 6
    # accuracy: 0.8490566037735849
    # Fold
    # 7
    # accuracy: 0.7358490566037735
    # Fold
    # 8
    # accuracy: 0.7924528301886793
    # Fold
    # 9
    # accuracy: 0.8113207547169812
    # Fold
    # 10
    # accuracy: 0.7924528301886793
    # Mean
    # Accuracy: 0.7883298392732355
    # Total
    # accuracy: 0.8151260504201681
