text: """
  Target Problem:
  ---------------
  * Predict the evolution of brain connectivity over time.
  
  Proposed Solution (Machine Learning Pipeline):
  ----------------------------------------------
  * Constant Feature Elimination -> AdaBoostRegressor -> Decision Tree Regressor
  
  Input to Proposed Solution:
  ---------------------------
  * Directories of training data and labels(measurements at two different timepoints), and testing data in csv file format.
  * These data should be stored in n x m pattern in csv file format.
  
    Typical Example:
    ----------------
    n x m samples in train_t0 csv file (n number of samples, m number of features)
    n x m samples in train_t1 csv file (n number of samples, m number of features)
    k x m samples in test_t0 csv file (k number of samples, m number of features)
  
  * These data set files are ready by load_data() function.
  
  Output of Proposed Solution:
  ----------------------------
  * Predictions generated by learning model for testing set
  * They are stored in "submission.csv" file.
  
  Code Owner:
  -----------
  * Copyright © Team 16. All rights reserved.
  * Copyright © Istanbul Technical University, Learning From Data Fall 2021. All rights reserved.
  """
  
  import random
  import numpy as np
  import pandas as pd
  import matplotlib.pyplot as plt
  from sklearn.ensemble import AdaBoostRegressor
  from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
  from sklearn.multioutput import MultiOutputRegressor
  from sklearn.tree import DecisionTreeRegressor
  from sklearn.model_selection import KFold
  from scipy.stats import pearsonr
  
  np.random.seed(1)
  random.seed(1)
  
  def load_data(train_file, test_file):
  
      """
      The method reads train and test data from their dataset files.
      Then, it splits train data into features and labels.
      Parameters
      ----------
      train_file: directory of the file in which train data set is located
      test_file: directory of the file in which test data set is located
      """
  
      x_tra = pd.read_csv(train_file[0], index_col="ID")
      y_tra = pd.read_csv(train_file[1], index_col="ID")
      x_tst = pd.read_csv(test_file, index_col="ID")
      return x_tra, y_tra, x_tst
  
  
  def preprocessing(x_tra):
  
      """
      This method eliminates duplicated and zero columns from the
      training data.
      ----------
      x_tra: features of training data
      """
      
      df = x_tra.transpose().drop_duplicates().transpose()
      nunq = df.nunique()
      df = df.drop(nunq[nunq==1].index, axis=1)
      return df
  
  def train_model(x_tra, y_tra):
  
      """
      The method creates a learning model and trains it by using training data.
      Parameters
      ----------
      x_tra: features of training data
      y_tra: labels of training data
      """
  
      adb = MultiOutputRegressor(
          AdaBoostRegressor(
              base_estimator=DecisionTreeRegressor(max_depth=None, max_features="sqrt"), 
              random_state=0, 
              n_estimators=500, 
              learning_rate=0.8), 
          n_jobs=-1)
      adb.fit(x_tra, y_tra)
      return adb
  
  def predict(x_tst, model):
  
      """
      The method predicts labels for testing data samples by using trained learning model.
      Parameters
      ----------
      x_tst: features of testing data
      model: trained learning model
      """
      return model.predict(x_tst)
  
  def cross_validation(x_tra, y_tra):
  
      """
      The method performs 5-fold cross-validation on training data and returns the error rates.
      Parameters
      ----------
      x_tra: features of training data
      y_tra: labels of training data
      """
  
      def pearson_cc(y_truth, y_predict):
          pearson_r = []
          pearson_p = []
          for i in range(len(y_truth)):
              r, p = pearsonr(y_truth[i], y_predict[i])
              pearson_r.append(r)
              pearson_p.append(p)
          return pearson_r, pearson_p
  
      fold_statistics = []
      y_test_predict_list = []
      folds = []
      kf = KFold(n_splits=5, shuffle=True, random_state=1)
      for train, test in kf.split(x_tra):
          folds.append([train,test])
  
      for fold_idx, fold in enumerate(folds):
          x_train_fold = x_tra.iloc[fold[0]]
          y_train_fold = y_tra.iloc[fold[0]]
  
          x_test_fold = x_tra.iloc[fold[1]]
          y_test_fold = y_tra.iloc[fold[1]]
          
          print(f"On Fold: {fold_idx+1}")
          
          fold_statistics.append({'Fold_ID':fold_idx})
          model = train_model(x_train_fold, y_train_fold)
          y_test_predict = predict(x_test_fold, model)
  
          y_test_predict_list.append(y_test_predict)
          
          mse = mean_squared_error(y_test_fold, y_test_predict)
          mae = mean_absolute_error(y_test_fold, y_test_predict)
          r2  = r2_score(y_test_fold, y_test_predict)
          pearson_r, pearson_p = pearson_cc(y_test_fold.to_numpy(), y_test_predict)
          print(f"MSE : {mse}, MAE: {mae}, R2: {r2}, Pearson CCC Mean: {np.mean(pearson_r)}")
          fold_statistics[fold_idx]['fold_mse'] = mse
          fold_statistics[fold_idx]['fold_mae'] = mae
          fold_statistics[fold_idx]['fold_r2'] = r2
          fold_statistics[fold_idx]['pearson_r_mean'] = np.mean(pearson_r)
      return fold_statistics
  
  def write_output(filename, predictions):
      
      """
      Writes the outputted predictions to a file.
      Parameters
      ----------
      filename: file path for saving file
      predictions: pandas.dataframe object containing predictions
      """
  
      meltedDF = predictions.flatten()
      kaglexd = pd.DataFrame(meltedDF)
      kaglexd_melted = kaglexd.melt()
      kaglexd_melted.drop('variable', inplace=True, axis=1)
  
      kaglexd_melted = kaglexd_melted.rename(columns={'value': 'predicted'})
      kaglexd_melted.index.name = 'ID'
  
      kaglexd_melted.to_csv(filename)
  
  # ********** MAIN PROGRAM ********** #
  
  
  train_file, test_file = ["train_t0.csv", "train_t1.csv"], "test_t0.csv"
  x_tra, y_tra, x_tst = load_data(train_file, test_file)
  x_tra = preprocessing(x_tra)
  x_tst = x_tst[x_tra.columns]
  
  stats = cross_validation(x_tra, y_tra)
  print(stats)
  
  model = train_model(x_tra, y_tra)
  predictions = predict(x_tst, model)
  write_output("submission.csv", predictions)