# -*- coding: utf-8 -*-
"""w11_Task.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1v695u-ZH-SzGLFUfiInyZz_aBHgsKGRi

video.ittensive.com/machine-learning/prudential/train.csv.gz
"""

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import cohen_kappa_score, confusion_matrix, make_scorer
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn import preprocessing
from sklearn.model_selection import GridSearchCV

data = pd.read_csv("https://video.ittensive.com/machine-learning/prudential/train.csv.gz")

data["Product_Info_2_1"] = data["Product_Info_2"].str.slice(0, 1)
data["Product_Info_2_2"] = pd.to_numeric(data["Product_Info_2"].str.slice(1, 2))
data.drop(labels=["Product_Info_2"], axis=1, inplace=True)
for l in data["Product_Info_2_1"].unique():
    data["Product_Info_2_1" + l] = data["Product_Info_2_1"].isin([l]).astype("int8")
data.drop(labels=["Product_Info_2_1"], axis=1, inplace=True)
data.fillna(value=-1, inplace=True)

columns_groups = ["Insurance_History", "InsurеdInfo", "Medical_Keyword",
                  "Family_Hist", "Medical_History", "Product_Info"]
columns = ["Wt", "Ht", "Ins_Age", "BMI"]
for cg in columns_groups:
    columns.extend(data.columns[data.columns.str.startswith(cg)])

scaler = preprocessing.StandardScaler()
data_transformed = pd.DataFrame(scaler.fit_transform(pd.DataFrame(data,
                                            columns=data.columns)))
columns_transformed = data_transformed.columns
data_transformed["Response"] = data["Response"]

def reduce_mem_usage (df):
    start_mem = df.memory_usage().sum() / 1024**2    
    for col in df.columns:
        col_type = df[col].dtypes
        if str(col_type)[:5] == "float":
            c_min = df[col].min()
            c_max = df[col].max()
            if c_min > np.finfo("f2").min and c_max < np.finfo("f2").max:
                df[col] = df[col].astype(np.float16)
            elif c_min > np.finfo("f4").min and c_max < np.finfo("f4").max:
                df[col] = df[col].astype(np.float32)
            else:
                df[col] = df[col].astype(np.float64)
        elif str(col_type)[:3] == "int":
            c_min = df[col].min()
            c_max = df[col].max()
            if c_min > np.iinfo("i1").min and c_max < np.iinfo("i1").max:
                df[col] = df[col].astype(np.int8)
            elif c_min > np.iinfo("i2").min and c_max < np.iinfo("i2").max:
                df[col] = df[col].astype(np.int16)
            elif c_min > np.iinfo("i4").min and c_max < np.iinfo("i4").max:
                df[col] = df[col].astype(np.int32)
            elif c_min > np.iinfo("i8").min and c_max < np.iinfo("i8").max:
                df[col] = df[col].astype(np.int64)
        else:
            df[col] = df[col].astype("category")
    end_mem = df.memory_usage().sum() / 1024**2
    print('Потребление памяти меньше на', round(start_mem - end_mem, 2), 'Мб (минус', round(100 * (start_mem - end_mem) / start_mem, 1), '%)')
    return df

data_transformed = reduce_mem_usage(data_transformed)

data_train, data_test = train_test_split(data_transformed,
                                         test_size=0.2)

"""KNN"""

model_knn = KNeighborsClassifier(n_neighbors=100)

y = data_train['Response']
x = data_train.drop('Response',axis=1)

model_knn.fit(x,y)

test_data = data_test.drop('Response',axis=1)

test_data['target'] = model_knn.predict(test_data)

cohen_kappa_score(test_data['target'],data_test['Response'])

"""Multiple Log Regs
### Логистическая регрессия
В обучающих данных пометим все классы, кроме 6 и 8, как 0 - и проведем обучение по такому набору данных.

Затем в оставшихся данных (в которых класс не равен 6 или 8) заменим все классы, кроме 7 и 1, на 0 - и снова проведем обучение. И т.д. Получим иерархию классификаторов:
8/6/нет -> 7/1/нет -> 2/5/нет -> 4/3
"""

def regression_model(df,columns):
  x = pd.DataFrame(df,columns=columns)
  y = df['Response']
  model = LogisticRegression(max_iter=10000)
  model.fit(x,y)
  return model
def logistic_regression(columns,df_train):
  model = regression_model(df_train,columns)
  logr_model = GridSearchCV(model, {},cv=5,n_jobs=2,scoring=make_scorer(cohen_kappa_score))
  x = pd.DataFrame(df_train,columns=columns)
  y = df_train['Response']
  logr_model.fit(x,y)
  return logr_model.best_score_

def find_opt_params(data_train):
  kappa_score_opt = 0
  columns_opt = []
  for col in columns_transformed:
    kappa_score = logistic_regression([col],data_train)
    if kappa_score > kappa_score_opt:
      columns_opt = [col]
      kapp_score = kappa_score_opt
  for col in columns_transformed:
    if col not in columns_opt:
      columns_opt.append(col)
      kappa_score = logistic_regression(columns_opt,data_train)
      if kappa_score < kappa_score_opt:
        columns_opt.pop()
      else:
        kappa_score_opt = kappa_score
  return kappa_score_opt,columns_opt

data_transformed = data_transformed.iloc[:1000]
data_train, data_test = train_test_split(data_transformed,
                                         test_size=0.2)

responses = [[6,8],[2,5],[3,4],[1,7]]
logr_models = [{}] * len(responses)
i = 0
data_train_current = data_train.copy()

for response in responses:
  state_train = data_train_current.copy()
  if response != [3,4]:
    state_train['Response'] = state_train['Response'].apply(lambda x: 0 if x not in response else x)
  kappa_score,columns_opt = find_opt_params(state_train)
  print(i,kappa_score,columns_opt)
  logr_models[i] = {
      'model': regression_model(state_train,columns_opt),
      'columns': columns_opt
  }
  if response != [3,4]:
    data_train_current = data_train_current[~data_train_current['Response'].isin(response)]
  i += 1

logr_models[1]

def logr_hierarchy(x):
  for response in range(len(responses)):
    if x['target' + str(response)] > 0:
      x['target'] = x['target' + str(response)]
      break
  return x

for response in range(len(responses)):
  model = logr_models[response]['model']
  columns = logr_models[response]['columns']
  x = pd.DataFrame(data_test,columns=columns)
  data_test['target' + str(response)] = model.predict(x)

data_test = data_test.apply(logr_hierarchy,axis=1,result_type='expand')

data_test.head()

cohen_kappa_score(data_test['target'],data_test['Response'])

