<reponame>Rasoul-Jahanshahi/Hardware_Performance_Counters_Can_Detect_Malware_Myth_or_Fact

import learn_all_boyou, learn_1k_cv, \
        logging, sys, random, os, time, json, itertools
import numpy as np
from sklearn.model_selection import StratifiedKFold

class learn_1k_cv_optimization(learn_1k_cv.learn_1k_cv):
    def setup_classifiers(self):
        """
        setup_classifiers only generate the classifier class objects. nothing more.
        Note that KNeighborsClassifier is inherited from learn_all_boyou instead of
        sklearn (learn_all_boyou inherits the implements from sklearn).
        """
        # self.names       = [\
        #                     "Nearest Neighbors", \
        #                     "Decision Tree", \
        #                     "Random Forest", \
        #                     "AdaBoost", \
        #                     "Naive Bayes",\
        #                     "Neural Net" \

        #                     #### "Logistic Regression",\
        #                     #### "Linear SVM", "Rbf SVM", "Poly SVM", "Sigmoid SVM"\
        #                     ####, "Gaussian Process"
        #                     ]
        max_iterations  = 1000
        # self.classifiers = [ \
        #                 learn_all_boyou.KNeighborsClassifier(\
        #                     n_neighbors=7, weights='uniform', algorithm='auto', n_jobs=-1),\
        #                 learn_all_boyou.DecisionTreeClassifier(\
        #                     max_depth=17, min_samples_split=12, min_samples_leaf=12,\
        #                                 presort=True, max_features=None,\
        #                                 random_state=int(round(time.time()))),\
        #                 learn_all_boyou.RandomForestClassifier(max_depth=100, min_samples_split=12,\
        #                                 min_samples_leaf=12, \
        #                                 n_estimators=100, max_features=None,\
        #                                 random_state=int(round(time.time()))), \
        #                 learn_all_boyou.AdaBoostClassifier(algorithm='SAMME.R', n_estimators=200, \
        #                                 random_state=int(round(time.time()))),\
        #                 learn_all_boyou.GaussianNB(priors=[0.5, 0.5]),\
        #                 learn_all_boyou.MLPClassifier(hidden_layer_sizes=(100,100,100,100), \
        #                                 alpha=100, solver='lbfgs',\
        #                                 max_iter=max_iterations,\
        #                                 activation='tanh', tol=1e-5,\
        #                                 warm_start='True') \

        #                 #### LogisticRegression(penalty='l2', tol=1e-4, C=1e2,\
        #                 ####               fit_intercept=True, solver='lbfgs', \
        #                 ####               class_weight='balanced', max_iter=max_iterations), \
        #                 #### SVC(kernel="linear", C=1e2, tol=1e-4, max_iter=max_iterations,\
        #                 ####               probability= True),\
        #                 #### SVC(kernel="rbf", C=1e2, tol=1e-4, max_iter=max_iterations,\
        #                 ####               probability=True, shrinking=True),
        #                 #### SVC(kernel="poly", C=1e2, degree=4, tol=1e-4,\
        #                 ####               max_iter=max_iterations, probability=True),\
        #                 #### SVC(kernel="sigmoid", C=1e2, gamma=1e-1, tol=1e-3, \
        #                 ####               max_iter=max_iterations, probability=True, \
        #                 ####               shrinking=True)#,\
        #                 #### GaussianProcessClassifier(1.0 * RBF(1.0), n_jobs=-1, \
        #                 ####               copy_X_train=False, \
        #                 ####               max_iter_predict=100, warm_start=False )\
        #                 ]

        self.classifiers =  list(\
                                itertools.chain(\
                                    [learn_all_boyou.KNeighborsClassifier(\
                                        n_neighbors=parameter_i, \
                                        weights='uniform', \
                                        algorithm='auto', \
                                        n_jobs=-1) \
                                        for parameter_i in list(xrange(38, 68, 3))],\
                                    [learn_all_boyou.DecisionTreeClassifier(\
                                        max_depth=parameter_i, \
                                        min_samples_split=12, \
                                        min_samples_leaf=12,\
                                        presort=True, max_features=None,\
                                        random_state=int(round(time.time()))) \
                                        for parameter_i in list(xrange(35, 45, 1))],\
                                    [learn_all_boyou.RandomForestClassifier(\
                                        max_depth=parameter_i, \
                                        min_samples_split=12,\
                                        min_samples_leaf=12, \
                                        n_estimators=100, max_features=None,\
                                        random_state=int(round(time.time()))) \
                                        for parameter_i in list(xrange(30, 40, 1))],\
                                    [learn_all_boyou.AdaBoostClassifier(\
                                        algorithm='SAMME.R', \
                                        n_estimators=parameter_i, \
                                        random_state=int(round(time.time())))
                                        for parameter_i in list(xrange(300, 1300, 100))],\
                                    [learn_all_boyou.GaussianNB(\
                                        priors=[0.5, 0.5])],\
                                    [learn_all_boyou.MLPClassifier(\
                                        hidden_layer_sizes=(parameter_i,parameter_i,parameter_i), \
                                        alpha = 5, \
                                        solver='lbfgs',\
                                        max_iter=max_iterations,\
                                        activation='tanh', 
                                        tol=1e-5,\
                                        warm_start='True') \
                                        for parameter_i in list(xrange(3, 53, 5))]\
                                )\
                            )
        self.names      =  list (\
                                itertools.chain(\
                                    ["Nearest Neighbors: " + \
                                    json.dumps(self.classifiers[parameter_i].get_params()) \
                                    for parameter_i in list(xrange(0, 10))],\
                                    ["Decision Tree: " + \
                                    json.dumps(self.classifiers[parameter_i].get_params()) \
                                    for parameter_i in list(xrange(10, 20))],\
                                    ["Random Forest: " + \
                                    json.dumps(self.classifiers[parameter_i].get_params()) \
                                    for parameter_i in list(xrange(20, 30))],\
                                    ["AdaBoost: " + \
                                    json.dumps(self.classifiers[parameter_i].get_params()) \
                                    for parameter_i in list(xrange(30, 40))],\
                                    ["Naive Bayes: " + \
                                    json.dumps(self.classifiers[40].get_params())], \
                                    ["Neural Net: " + \
                                    json.dumps(self.classifiers[parameter_i].get_params()) \
                                    for parameter_i in list(xrange(41, 51))]\
                                    )\
                                )

    def classic_cross_validation(self):
        """
        This function does 10 fold split for self.data and its label :class:`learn_all_boyou`. 
        Data and label will be shuffled. The data and label is splited with granularity of 
        single feature vector.

        :param dict self.report: simulation report dictionary
        :param array self.X_train: Training array 
        :param array self.X_test: Testing array
        :param array self.y_train: Training label
        :param array self.y_test: Testing label
        :param list prediction: prediction results
        :param list predict_proba: prediction confidence
        
        """
        self.logger.info('Start to cross validate ...')
        self.load_data()
        self.setup_classifiers()
        self.report     = {}
        # random shuffling
        zipped_list             = zip(self.data, self.label)
        random.shuffle(zipped_list)
        self.data, self.label   = zip(*zipped_list)
        self.data               = np.array(list(self.data))
        self.label              = np.array(list(self.label))
        # 10 fold split
        cv                      = StratifiedKFold(n_splits = 10)
        
        experiment_path         = self.result_path

        zipped_clfs             = zip(self.names, self.classifiers)

        #for names, clf in zip(self.names, self.classifiers):
        names, clf              = zipped_clfs[int(sys.argv[1].split('/')[-1])]
        self.logger.info(names + " in process ....")

        count                   = 0

        for train_idx, test_idx in cv.split(self.data, self.label):
            self.X_train, self.X_test = self.data[train_idx], self.data[test_idx]
            self.y_train, self.y_test = self.label[train_idx], self.label[test_idx]
            clf.fit(self.X_train, self.y_train)
           
            self.result_path    = experiment_path + str(count) + '/'
            count               += 1

            if not os.path.isdir(self.result_path):
                self.logger.info(self.result_path + " new folder created ....")
                os.mkdir(self.result_path)
            else:
                self.logger.info(self.result_path + " old directory exists ....")
                if os.path.isfile(self.result_path + 'classification_report.txt'):
                    self.logger.info(self.result_path + " old report exists ....")
                    with open(self.result_path + 'classification_report.txt', 'r') as outfile:
                        self.report = json.load(outfile)
                    outfile.close()


            self.prediction     = clf.predict(self.X_test)
            self.text_class_report(names)

            self.predict_proba  = clf.predict_proba(self.X_test)
            self.roc_curve_report(names)

        self.logger.info(names + " testing completed!")

if __name__ == "__main__":
    
    logger  = logging.getLogger()
    logger.setLevel(logging.DEBUG)

    logger_handler = logging.StreamHandler()
    logger_handler.setFormatter(\
        logging.Formatter('%(asctime)s [%(levelname)s]\
            %(filename)s [%(lineno)d]: %(funcName)s(): %(message)s'))
    logger.addHandler(logger_handler)

    learn1 = learn_1k_cv_optimization(logger, \
            data_path_prefix='../amd_data/')
            #data_path_prefix='/home/bobzhou/2017_summer/data_analysis/amd_data_analysis/')

    learn1.result_path = sys.argv[1] + '/'
    logger.info("files will be saved in the following path: " + learn1.result_path)

    #learn1.run()
    learn1.classic_cross_validation()
    #learn1.test_rasoul()


