#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Oct 28 18:37:20 2018

@author: gykovacs

This script contains all the functions and codes we used to produce the
tables in the paper. Before using the script, update the "results_path" variable
below to the path containing the cache file generated by the CacheAndValidate
object.
"""

# import SMOTE variants
import smote_variants as sv

# some packages to transform the data
import numpy as np

foldings='https://drive.google.com/open?id=1PKw1vETVUzaToomio1-RGzJ9_-buYjOW'
raw_results='https://drive.google.com/open?id=12CfB3184nchLIwStaHhrjcQK7Ari18Mo'
agg_results='https://drive.google.com/open?id=19JGikRYXQ6-eOxaFVrqkF64zOCiSdT-j'

def ballpark_sample(sampler_nf,
                    img_file_base= None,
                    img_file_sampled= None,
                    use_built_in= 1,
                    data_maj_user= None,
                    data_min_user= None,
                    center_min= np.array([[4.0, 0.0], [3.0, 0.5], [3.0, -1.0]]),
                    var_min= np.array([np.diag([1.0, 1.0]), np.diag([0.5, 0.5]), np.diag([1.0, 0.5])]),
                    num_min= np.array([4, 8, 8]),
                    center_maj= np.array([[0.0, 0.0]]),
                    var_maj= np.array([np.diag([1.0, 1.0])]),
                    num_maj= np.array([60])):
        """
        Execute ballpark example sampling or noise removal with plotting

        Args:
            sampler_nf (SamplerBase/NoiseFilter): sampling or noise filtering object
            img_file_base (str): filename to save the plot of the base data
            img_file_sampled (str): filename to save the plot of the sampled data
            use_built_in (int): id of the built in data to be used - 0/1, data
                                will be generated if no user proveded data is specified
            data_maj_user (np.array): user provided majority data
            data_min_user (np.array): user provided minority data
            center_min (np.array): centers of minority concepts with Gaussian distribution
            var_min (np.array): variances of minority concepts
            num_min (np.array): number of samples to generate from minority concepts
            center_maj (np.array): center of majority concept
            var_maj (np.array): variance of majority concept
            num_maj (int): number of samples to generate from the majority concept

        Example:

            ballpark_sample(SMOTE_ENN(), img_file_base= 'base.png', img_file_sampled= 'SMOTE_ENN.png')
            ballpark_sample(EditedNearestNeighbors(), img_file_base= 'base.png', img_file_sampled= 'ENN.png')

        """
        import matplotlib.pyplot as plt

        if use_built_in == 0:
            data_min= np.array([[ 5.7996138 , -0.25574582], [ 3.0637093 ,  2.11750874],
                   [ 4.91444087, -0.72380123], [ 1.06414164,  0.08694243],
                   [ 2.59071708,  0.75283568], [ 3.44834937,  1.46118085],
                   [ 2.8036378 ,  0.69553702], [ 3.57901791,  0.71870743],
                   [ 3.81529064,  0.62580927], [ 3.05005506,  0.33290343],
                   [ 1.83674689,  1.06998465], [ 2.08574889, -0.32686821],
                   [ 3.49417022, -0.92155623], [ 2.33920982, -1.59057568],
                   [ 1.95332431, -0.84533309], [ 3.35453368, -1.10178101],
                   [ 4.20791149, -1.41874985], [ 2.25371221, -1.45181929],
                   [ 2.87401694, -0.74746037], [ 1.84435381,  0.15715329]])

            data_maj= np.array([[-1.40972752,  0.07111486], [-1.1873495 , -0.20838002],
                   [ 0.51978825,  2.1631319 ], [-0.61995016, -0.45111475],
                   [ 2.6093289 , -0.40993063], [-0.06624482, -0.45882838],
                   [-0.28836659, -0.59493865], [ 0.345051  ,  0.05188811],
                   [ 1.75694985,  0.16685025], [ 0.52901288, -0.62341735],
                   [ 0.09694047, -0.15811278], [-0.37490451, -0.46290818],
                   [-0.32855088, -0.20893795], [-0.98508364, -0.32003935],
                   [ 0.07579831,  1.36455355], [-1.44496689, -0.44792395],
                   [ 1.17083343, -0.15804265], [ 1.73361443, -0.06018163],
                   [-0.05139342,  0.44876765], [ 0.33731075, -0.06547923],
                   [-0.02803696,  0.5802353 ], [ 0.20885408,  0.39232885],
                   [ 0.22819482,  2.47835768], [ 1.48216063,  0.81341279],
                   [-0.6240829 , -0.90154291], [ 0.54349668,  1.4313319 ],
                   [-0.65925018,  0.78058634], [-1.65006105, -0.88327625],
                   [-1.49996313, -0.99378106], [ 0.31628974, -0.41951526],
                   [ 0.64402186,  1.10456105], [-0.17725369, -0.67939216],
                   [ 0.12000555, -1.18672234], [ 2.09793313,  1.82636262],
                   [-0.11711376,  0.49655609], [ 1.40513236,  0.74970305],
                   [ 2.40025472, -0.5971392 ], [-1.04860983,  2.05691699],
                   [ 0.74057019, -1.48622202], [ 1.32230881, -2.36226588],
                   [-1.00093975, -0.44426212], [-2.25927766, -0.55860504],
                   [-1.12592836, -0.13399132], [ 0.14500925, -0.89070934],
                   [ 0.90572513,  1.23923502], [-1.25416346, -1.49100593],
                   [ 0.51229813,  1.54563048], [-1.36854287,  0.0151081 ],
                   [ 0.08169257, -0.69722099], [-0.73737846,  0.42595479],
                   [ 0.02465411, -0.36742946], [-1.14532211, -1.23217124],
                   [ 0.98038343,  0.59259824], [-0.20721222,  0.68062552],
                   [-2.21596433, -1.96045872], [-1.20519292, -1.8900018 ],
                   [ 0.47189299, -0.4737293 ], [ 1.18196143,  0.85320018],
                   [ 0.03255894, -0.77687178], [ 0.32485141, -0.34609381]])
        elif use_built_in == 1:
            data_min= np.array([[ 2.24821415,  1.18676469], [ 2.57432259, -0.52937757],
                               [ 4.03012851, -0.27223403], [ 4.92529272,  0.14430249],
                               [ 0.3640416 ,  1.26641668], [ 3.59539637,  0.15179343],
                               [ 1.85245002,  0.44108807], [ 1.92319986,  1.07438521],
                               [ 1.31302177, -0.66937676], [ 1.29782254, -1.29062634],
                               [ 1.90836629, -1.73220654], [ 3.41166059, -1.90655422]])
            data_maj= np.array([[ 1.5978218 ,  0.47715381], [-0.14397666,  0.63448536],
                               [-0.15443592, -1.38198419], [ 0.2864424 , -1.44299448],
                               [-1.94354042,  1.071522  ], [ 1.68681563, -0.30805447],
                               [ 0.18245927,  1.85561426], [-0.20484136,  1.13614876],
                               [-0.07955036,  0.13771555], [ 1.04595671, -0.42968178],
                               [-0.09473432, -2.4042022 ], [-1.0116999 , -0.84900863],
                               [ 1.14975514,  0.25432179], [-0.27432522,  0.06097208],
                               [ 0.55895491, -0.63200645], [ 1.04855879,  1.31012162],
                               [ 0.90370109,  0.46469345], [ 1.67266613,  2.27583048],
                               [-0.93092223, -0.87225695], [-0.9954787 , -0.13147926],
                               [ 1.52725929,  0.79565553], [ 2.05886293, -1.2115962 ],
                               [ 0.4724037 , -0.50301013], [ 1.19511606, -2.43229807],
                               [-0.04131479,  0.28242579], [ 0.64148259, -1.69502588],
                               [ 0.86751856,  1.41218637], [-0.67012062, -0.82124794],
                               [-0.47190644, -0.74410928], [-1.88441455, -0.03092223],
                               [-1.50730107, -0.46354274], [-1.25401701,  1.96476907],
                               [ 1.58863019, -1.26417484], [-0.77823086,  0.8528338 ],
                               [ 0.84733373, -0.34732072], [-0.17083489, -1.21026323],
                               [-1.11201547,  0.77977009], [-0.59840722,  0.50721945],
                               [ 1.81465074,  0.15076694], [-0.15056923, -0.76463412]])
        elif not data_maj_user is None and not data_min_user is None:
            data_maj= data_maj_user
            data_min= data_min_user
        else:
            # generating new data
            data_maj= np.vstack([np.random.multivariate_normal(center_maj[i], var_maj[i], num_maj[i]) for i in range(len(center_maj))])
            data_min= np.vstack([np.random.multivariate_normal(center_min[i], var_min[i], num_min[i]) for i in range(len(center_min))])

        # plotting the base data
        plt.figure(figsize=(4, 3))
        plt.scatter(data_maj[:,0], data_maj[:,1], c= 'black', marker='P', s=100, label='majority')
        plt.scatter(data_min[:,0], data_min[:,1], c= 'r', marker='o', s=70, label='minority')
        plt.title('Original data sample')
        plt.xlabel('feature 0')
        plt.ylabel('feature 1')
        plt.legend()
        plt.tight_layout()
        if not img_file_base is None:
            plt.savefig(img_file_base)
        plt.plot()

        # doing the sampling
        majority_label= 0
        minority_label= 1

        X= np.vstack([data_maj, data_min])
        y= np.hstack([np.repeat(majority_label, len(data_maj)), np.repeat(minority_label, len(data_min))])

        if isinstance(sampler_nf, sv.OverSampling):
            X_samp, y_samp= sampler_nf.sample(X, y)
            if np.sum(y_samp == minority_label) == 0:
                raise ValueError(sampler_nf.__class__.__name__ + ' removed all minority samples, please rerun the code, the randomized behaviour might result a better output')
        else:
            X_samp, y_samp= sampler_nf.remove_noise(X, y)

        X_samp_maj= X_samp[y_samp == majority_label]
        X_samp_min= X_samp[y_samp == minority_label]

        # plotting the new data
        plt.figure(figsize=(4, 3))
        plt.scatter(X_samp_maj[:,0], X_samp_maj[:,1], c='black', marker='P', s= 100, label='majority')
        X_samp_min_unique, counts= np.unique(X_samp_min, axis= 0, return_counts= True)
        samples_by_counts= [X_samp_min_unique[counts == i] for i in range(0, np.max(counts)+1)]
        if np.max(counts) == 1:
            plt.scatter(X_samp_min[:,0], X_samp_min[:,1], c='r', marker='o', s= 70, label='minority')
        else:
            for i in range(len(samples_by_counts)):
                if len(samples_by_counts[i]) > 0:
                    plt.scatter(samples_by_counts[i][:,0], samples_by_counts[i][:,1], c='r', marker='o', s= 70 + 30*(i-1), label=('minority %d' % i))

        if isinstance(sampler_nf, sv.OverSampling):
            plt.title('%s: %s' % (sampler_nf.__class__.__name__, ", ".join([c for c in sampler_nf.categories])))
        else:
            plt.title('%s' % (sampler_nf.__class__.__name__))
        plt.xlabel('feature 0')
        plt.ylabel('feature 1')
        plt.legend()
        plt.tight_layout()
        if not img_file_sampled is None:
            plt.savefig(img_file_sampled)
        plt.plot()

def generate_figures():
    oversamplers= sv.get_all_oversamplers()

    for o in oversamplers:
        ballpark_sample(o(), img_file_base= 'figures/base.png', img_file_sampled= ('figures/%s.png' % o.__name__))

    noisefilters= sv.get_all_noisefilters()

    for n in noisefilters:
        ballpark_sample(n(), img_file_base= 'figures/base.png', img_file_sampled= ('figures/%s.png' % n.__name__))

def generate_multiclass_figures():
    oversamplers= sv.get_all_oversamplers()
    oversamplers= [o for o in oversamplers if not sv.OverSampling.cat_changes_majority in o.categories and 'proportion' in o().get_params()]

    import sklearn.datasets as datasets

    dataset= datasets.load_wine()

    X= dataset['data']
    y= dataset['target']

    import matplotlib.pyplot as plt

    import sklearn.preprocessing as preprocessing

    ss= preprocessing.StandardScaler()

    X_ss= ss.fit_transform(X)

    def plot_and_save(X, y, filename, oversampler_name):
        plt.figure(figsize=(4, 3))
        plt.scatter(X[y == 0][:,0], X[y == 0][:,1], c='r', marker='o', label='class 0')
        plt.scatter(X[y == 1][:,0], X[y == 1][:,1], c='b', marker='P', label='class 1')
        plt.scatter(X[y == 2][:,0], X[y == 2][:,1], c='green', marker='x', label='class 2')
        plt.xlabel('feature 0')
        plt.ylabel('feature 1')
        plt.title(", ".join(["wine dataset", oversampler_name]))
        plt.savefig(filename)
        plt.show()

    plot_and_save(X, y, 'figures/multiclass-base.png', "No Oversampling")

    for o in oversamplers:
        print(o.__name__)
        mcos= sv.MulticlassOversampling(o())
        X_samp, y_samp= mcos.sample(X_ss, y)
        plot_and_save(ss.inverse_transform(X_samp), y_samp, "figures/multiclass-%s" % o.__name__, o.__name__)

def generate_all_figures():
    generate_figures()
    generate_multiclass_figures()

generate_all_figures()
