"""ver 1.1"""


#Author: Sumit Chandak (Chandaksumit29@gmail.com)
#License: MIT


import pandas as pd
import warnings

from sklearn.calibration import CalibratedClassifierCV


#class PBOB
class PBOB():
  
  """class PBOB(Probablity based Best Out of Best outcome) 
  
  PBOB i.e. Probability based Best Out of Best outcoem
  This returns yous the best output amongst all the output generated by the 
  each individual model based on probability
  
  This accepts multiple model object as input stted in following example
  
  eg......

    clf1 = LogisticRegression()
    clf2 = GaussianNB()
    clf3 = KNeighborsClassifier()
    pbob_obj=PBOB(clf1,clf2,clf3)
    
  
  If nothing is passed then it will simply generate output based on SVC classifiacation
  
  """

  
  def __init__(self,*models ):
    temp=[]
    for each_model in models:
      temp.append(CalibratedClassifierCV(each_model))

    self.model_list=temp
    
    

  def fit(self,X_train,y_train):
    
    """
    For training the models with data provided through thisd method,
    which can be used to generate output 
    
    Accepts data X_train which are fratures of data and y_train which are Label of data. 
    
    X_train : pandas dataframe of shape = [n_samples, n_features]
            The training input samples/features.
            
    y_train : pandas dataframe of shape = [n_samples, label]
            Trining input labels 
            
    Refer following example:
    eg.....
    
    pbob_obj.fit(X_train,y_train)
    
    
    """
    
    self.X_train_data=X_train.reset_index(drop=True)
    self.y_train_data=y_train.reset_index(drop=True)
    
    temp_fitted_model=[]
    for each_model in self.model_list:
      each_model.fit(self.X_train_data,self.y_train_data)
      temp_fitted_model.append(each_model)
    
    self.fitted_model=temp_fitted_model
    
    
     


    
  def predict(self,X_test):
    """
    For prediction using PBOB techineque with provided models trained using fit() 
    method.
    
    Inputs:
    
    X_test: pandas dataframe of shape = [n_samples, n_features]
            Where n_features should be equal to provided in the training dataframe.
            
    Returns/Output:
    
    Returns the target class and probability of respective class along with
    its features provided for preidction in the form pandas dataframe.
    
    
    Refer following Example 
    eg.....
    
    Result = pbob_obj.predict(X_test)
    
    
    """
    self.X_test_data=X_test.reset_index(drop=True)
    
    temp=pd.DataFrame()
    count=0
    for each_model in self.fitted_model:
      count=count+1
      
      temp_str='model_'+str(count)+'_predictions'
      temp[temp_str]=each_model.predict(self.X_test_data)
      
      temp_str='model_'+str(count)+'_probablities'
      out = each_model.predict_proba(self.X_test_data)
      temp[temp_str]=[max(each) for each in out]
      
    """self.outcomes=temp_df
    return self.out()"""
   
   
    
    """columns list form all the predictions and probabalities individually"""
    pred_list=[x for x in temp.columns if x.split('_')[-1]=='predictions']
    prob_list=[x for x in temp.columns if x.split('_')[-1]=='probablities']
    
    """getting max probablity column name out of alla the probablity"""
    
    max_prob=temp[prob_list].max(axis=1)
    max_prob_col_name=temp[prob_list].idxmax(axis=1)
    
    """getting final prediction column name for each instance using max probabaility column name"""
    final_pred_col=[]
    for every in max_prob_col_name:
      final_pred_col.append('_'.join(every.split('_')[:-1])+'_predictions')
      
    """final_pred=[]
    for each in range(len(final_pred_col)):
      final_pred.append(temp[pred_list].loc[each][final_pred_col[i]])"""
    
    final_pred=[]
    for each in range(len(final_pred_col)):
      final_pred.append(temp[pred_list].loc[each][final_pred_col[each]])
    
    
    
    self.final_preditions=pd.DataFrame(final_pred,columns=['prediction'])
    self.final_probablaties=pd.DataFrame(max_prob,columns=['probablity'])
    
   
    return (pd.concat([self.X_test_data, self.final_preditions,self.final_probablaties], axis=1, sort=True))
    
    

      
     
    
   
      



