# -*- coding: utf-8 -*-
"""
Created on Sat Jun 20 13:14:36 2020

@author: emmav
"""

import pandas as pd
from pandas import read_table
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import xlrd

frame = pd.read_excel(r"NationalTreeSales.xlsx") 
pred27 = None
scaler = None
minmax = None

def get_features_and_labels(frame):
    global pred27
    global scaler
    global minmax
    '''
    Transforms and scales the input data and returns numpy arrays for
    training and testing inputs and targets.
    '''

    # Convert values to floats
    arr = np.array(frame, dtype=np.float)

    # Normalize the entire data set
    from sklearn.preprocessing import StandardScaler, MinMaxScaler
    minmax = MinMaxScaler()
    minmax.fit(arr[:-1])
    arr = minmax.transform(arr)

    # Use the last column as the target value
    X, y = arr[:-1, :-1], arr[:-1, -1]
    pred27 = arr[-1, :-1]
    
    # Use 50% of the data for training, but we will test against the
    # entire set
    from sklearn.model_selection import train_test_split
    X_train, _, y_train, _ = train_test_split(X, y, test_size=0.2)
    X_test, y_test = X, y

    
    # Normalize the attribute values to mean=0 and variance=1
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()

    
    # Fit the scaler based on the training data, then apply the same
    # scaling to both training and test sets.
    scaler.fit(X_train)
    X_train = scaler.transform(X_train)
    X_test = scaler.transform(X_test)
    # Return the training and test sets
    return X_train, X_test, y_train, y_test

def evaluate_learner(X_train, X_test, y_train, y_test):
    global scaler
    global pred27
    global minmax 
    # Use a support vector machine for regression
    from sklearn.svm import SVR

    # Train using a radial basis function
    svr = SVR(kernel='rbf', gamma='scale', tol=1e-5)
    svr.fit(X_train, y_train)
    y_pred = svr.predict(X_test)
    r_2 = svr.score(X_test, y_test)
    yield 'RBF Model ($R^2={:.3f}$)'.format(r_2), y_test, y_pred
    f_scale = scaler.transform([pred27])
    f_input = svr.predict(f_scale)
    f_pred = minmax.inverse_transform([[0] * 9 + [f_input]])[0][-1]
    print("RBF Prediction for 2027: " + str(f_pred))

    # Train using a linear kernel
    svr = SVR(kernel='linear')
    svr.fit(X_train, y_train)
    y_pred = svr.predict(X_test)
    r_2 = svr.score(X_test, y_test)
    yield 'Linear Model ($R^2={:.3f}$)'.format(r_2), y_test, y_pred
    f_scale = scaler.transform([pred27])
    f_input = svr.predict(f_scale)
    f_pred = minmax.inverse_transform([[0] * 9 + [f_input]])[0][-1]
    print("Linear Prediction for 2027: " + str(f_pred))

    # Train using a polynomial kernel
    svr = SVR(kernel='poly', degree=2)
    svr.fit(X_train, y_train)
    y_pred = svr.predict(X_test)
    r_2 = svr.score(X_test, y_test)
    yield 'Polynomial Model ($R^2={:.3f}$)'.format(r_2), y_test, y_pred
    f_scale = scaler.transform([pred27])
    f_input = svr.predict(f_scale)
    f_pred = minmax.inverse_transform([[0] * 9 + [f_input]])[0][-1]
    print("Poly Prediction for 2027: " + str(f_pred))
    

def plot(results):
    '''
    Create a plot comparing multiple learners.
    `results` is a list of tuples containing:
        (title, expected values, actual values)
    
    All the elements in results will be plotted.
    '''
    global minmax

    # Using subplots to display the results on the same X axis
    fig, plts = plt.subplots(nrows=len(results), figsize=(8, 8))
    fig.canvas.set_window_title('Predicting data')

    # Show each element in the plots returned from plt.subplots()
    for subplot, (title, y, y_pred) in zip(plts, results):
        # Configure each subplot to have no tick marks
        # (these are meaningless for the sample dataset)
        subplot.xaxis.set_major_formatter(ticker.IndexFormatter(frame["Year"]))

        # Label the vertical axis
        subplot.set_ylabel('Trees Sold')

        # Set the title for the subplot
        subplot.set_title(title)

        # Plot the actual data and the prediction
        subplot.plot(y, 'g', label='actual')
        subplot.plot(y_pred, 'r--', label='predicted')
        
        # Shade the area between the predicted and the actual values
        subplot.fill_between(
            # Generate X values [0, 1, 2, ..., len(y)-2, len(y)-1]
            np.arange(0, len(y), 1),
            y,
            y_pred,
            color='r',
            alpha=0.2
        )

        # Mark the extent of the training data
        subplot.axvline(np.floor(len(y) * 0.8), linestyle='--', color='0', alpha=0.2)

        # Include a legend in each subplot
        subplot.legend()

    # Let matplotlib handle the subplot layout
    fig.tight_layout()

    # ==================================
    # Display the plot in interactive UI
    plt.show()


    # Closing the figure allows matplotlib to release the memory used.
    plt.close()


if __name__ == '__main__':
# Set data set to .csv file


# Process data into feature and label arrays
    print("Processing {} samples with {} attributes".format(len(frame.index), len(frame.columns)))
    X_train, X_test, y_train, y_test = get_features_and_labels(frame)

# Evaluate multiple regression learners on the data
    print("Evaluating regression learners")
    results = list(evaluate_learner(X_train, X_test, y_train, y_test))
# Display the results
    print("Plotting the results")
    plot(results)

        