<filename>rectool/helper.py
#=========================================================#
# Helper Functions                                        #
#---------------------------------------------------------#
import math
import numpy as np
from scipy.stats import norm,chi2,t
import os

#Helper Functions
def is_number(s):
    """Return true if the input is a number."""
    try:
        float(s)
        return True
    except ValueError:
        return False


def calculate_weights(x,alpha=10):
    """Apply softmax function to a list of numbers and return a list of probabilities."""
    y = -alpha*(x/max(x)*100)
    e_x = np.exp(y)
    return e_x / e_x.sum()

    
def dist(X,Y):
    '''Calculate Euclidean Distance between two points in R**n'''
    return math.sqrt(sum([(x-y)**2 for x,y in zip(X,Y)]))


def create_bounds(features,padding_factor=1,negativeAllowed=False):
    """Create the search bounds for the feature space.
    
    Feature bounds are created to limit the search space 
    of optimizers to points near the data set.
    
    Args:
        features(array_like): Input features to the machine learning model with dimensions 
            of (number_of_samples,cardinality_of_feature_vector).
        
        padding_factor(float,optional): The factor to extrapolate outside the data set. 
            For example, if a particular element in the feature vector has a maximum value of 10
            and the padding_factor is set to 2, the upper bound for that element of the feature
            vector will be 20. Default 1.
    
        negativeAllowed(bool): Are negative bound values allowed? Default False.
    
    Returns:
        list: A list of tuples where each element of the list contains a tuple of length 2 
            that contains the minimum and maximum bound for the corresponding element of the
            feature vector.

    """
    
    features_transpose = list(map(list, zip(*features)))
    bounds = []
    for dim in range(len(features[0])):
        maxVal = max(features_transpose[dim])
        minVal = min(features_transpose[dim])
        mu = (maxVal + minVal)/2
        shift = (maxVal - minVal) * padding_factor / 2
        
        if negativeAllowed or mu - shift > 0:
            bounds.append((mu-shift,mu+shift))
        else:
            bounds.append((0.1*(mu+shift),mu+shift))
    return bounds


def ball_target_moments(x,engineering_accuracy,model,sample_points=10,confidence_level=0.95,seed=None):
    """Sample a machine learning model in a ball about a chosen input feature. 
       Return the mean and standard deviation of the outputs.
    
    Args:
        x(array_like): The input feature used as the center point of the ball.
    
        engineering_accuracy(float): A Percent used to determine the radius of the ball.  
    
        model(sklearn.base.BaseEstimator): The scikit-learn style machine learning model to sample.
    
        sample_points(int,optional): Number of points to choose in the ball. 

        confidence_level(float,optional): Default 0.95.
    
        seed(int,optional): Setting the seed makes calling this function 
            deterministic so the same points are chosen for a given input. Default None.
    
    Returns:
        float: The mean of the outputs generated by the model from inputs sampled 
            inside the ball.
        
        float: The standard deviation of outputs generated by the model from inputs 
            sampled inside the ball
    
    """
    
    #Set Seed So this is a deterministic algorithm for each point!
    np.random.seed(seed)
    
    #print('point:',point)
    #print('engineering accuracy',engineering_accuracy)
    #print('model',model)
    #Generate Interval for Random Samples
    low_bound = [value - value*engineering_accuracy for value in x]
    high_bound = [value + value*engineering_accuracy for value in x]
    #print(low_bound,high_bound)
    #Generate uniform random sample points inside of those boundaries 
    samples = [[np.random.uniform(low=low_bound[i],high=high_bound[i]) for i in range(len(low_bound))] for j in range(sample_points)]
    
    #Predict sample points
    predictions = []
    predictions.append(model.predict(samples).tolist())
    
    #Calculate sample mean & confidence intervals
    k = sample_points - 1 #Degrees of freedom
    s = np.std(predictions)
    m = np.mean(predictions)
    s_m = s / math.sqrt(k + 1)
    #print(s,m)
    mean_interval = [m - t.ppf(0.975,k)*s_m,m + t.ppf(0.975,k)*s_m]

    #print(k,t.ppf(0.025,k))

    #Calculate sample standard deviation & confidence intervals
    interval = [math.sqrt(k*s**2/chi2.ppf(1-confidence_level/2,k)),math.sqrt(k*s**2/chi2.ppf(confidence_level/2,k))]

    #Print Relevant Stats
    percent_error = lambda x: (np.mean(x) - x[0])/np.mean(x)
    #print('Mean:',m,mean_interval,percent_error(mean_interval))
    #print('Stdev:',s,interval,percent_error(interval))
    
    mu = m
    sigma = max(interval)
    
    return mu,sigma


#Functions which generate markdown
def create_figure_markdown(fig,caption,fname):
    """Create Markdown and the correct files for a Figure.
    
    Generate an HTML string to describe and display a figure. 
    Save the image of the figure to the spot the HTML is refferencing.
    
    Args:
        fig(matplotlib.): A matplotlib figure handle. 
    
        caption(str): The figure caption.
    
        fname(str): The file name to save the figure.
    
    Returns:
        str: The html string for display.
    
    """
    
    base_url = os.path.dirname(os.path.realpath('../tmp'))
    
    #Save Figure to File in Temp Folder (Should be Unique Name)
    fig.savefig('../tmp/' + fname)
    plt.close(fig)
    url = base_url + '/tmp/' + fname
    
    #Create HTML for Displaying that Figure
    html = '<div class=\'figure\'> <img src=\'' + url + '\' >\n' 
    html += '<p>' + caption + '</p></div>\n'
    
    return html


def summarize_success_probability(self):
    """Generate an HTML string that summarizes the model success probability."""
    
    success_prob = 0
    threshold = 0.9
    for i,probability in enumerate(self.probabilities):
        success_prob += (1-success_prob)*(probability/100)
        if success_prob > threshold:
            break
    
    html = '<p><b>(Left)</b> Success Probability Analysis: In order to have a ' + str(round(threshold*100)) + '% chance of successfully meeting the stated objective above ' + str(i+1) + ' strains must be constructed.'
    html += ' <b>(Right)</b> Strains Selected: Here the black pluses show the points analyzed in the data set.  Larger Plus means more production.  Blue plusses show predicted strains.</p>'
    return html

<filename>rectool/helper.py
#=========================================================#
# Helper Functions                                        #
#---------------------------------------------------------#
import math
import numpy as np
from scipy.stats import norm,chi2,t
import os

#Helper Functions
def is_number(s):
    """Return true if the input is a number."""
    try:
        float(s)
        return True
    except ValueError:
        return False


def calculate_weights(x,alpha=10):
    """Apply softmax function to a list of numbers and return a list of probabilities."""
    y = -alpha*(x/max(x)*100)
    e_x = np.exp(y)
    return e_x / e_x.sum()

    
def dist(X,Y):
    '''Calculate Euclidean Distance between two points in R**n'''
    return math.sqrt(sum([(x-y)**2 for x,y in zip(X,Y)]))


def create_bounds(features,padding_factor=1,negativeAllowed=False):
    """Create the search bounds for the feature space.
    
    Feature bounds are created to limit the search space 
    of optimizers to points near the data set.
    
    Args:
        features(array_like): Input features to the machine learning model with dimensions 
            of (number_of_samples,cardinality_of_feature_vector).
        
        padding_factor(float,optional): The factor to extrapolate outside the data set. 
            For example, if a particular element in the feature vector has a maximum value of 10
            and the padding_factor is set to 2, the upper bound for that element of the feature
            vector will be 20. Default 1.
    
        negativeAllowed(bool): Are negative bound values allowed? Default False.
    
    Returns:
        list: A list of tuples where each element of the list contains a tuple of length 2 
            that contains the minimum and maximum bound for the corresponding element of the
            feature vector.

    """
    
    features_transpose = list(map(list, zip(*features)))
    bounds = []
    for dim in range(len(features[0])):
        maxVal = max(features_transpose[dim])
        minVal = min(features_transpose[dim])
        mu = (maxVal + minVal)/2
        shift = (maxVal - minVal) * padding_factor / 2
        
        if negativeAllowed or mu - shift > 0:
            bounds.append((mu-shift,mu+shift))
        else:
            bounds.append((0.1*(mu+shift),mu+shift))
    return bounds


def ball_target_moments(x,engineering_accuracy,model,sample_points=10,confidence_level=0.95,seed=None):
    """Sample a machine learning model in a ball about a chosen input feature. 
       Return the mean and standard deviation of the outputs.
    
    Args:
        x(array_like): The input feature used as the center point of the ball.
    
        engineering_accuracy(float): A Percent used to determine the radius of the ball.  
    
        model(sklearn.base.BaseEstimator): The scikit-learn style machine learning model to sample.
    
        sample_points(int,optional): Number of points to choose in the ball. 

        confidence_level(float,optional): Default 0.95.
    
        seed(int,optional): Setting the seed makes calling this function 
            deterministic so the same points are chosen for a given input. Default None.
    
    Returns:
        float: The mean of the outputs generated by the model from inputs sampled 
            inside the ball.
        
        float: The standard deviation of outputs generated by the model from inputs 
            sampled inside the ball
    
    """
    
    #Set Seed So this is a deterministic algorithm for each point!
    np.random.seed(seed)
    
    #print('point:',point)
    #print('engineering accuracy',engineering_accuracy)
    #print('model',model)
    #Generate Interval for Random Samples
    low_bound = [value - value*engineering_accuracy for value in x]
    high_bound = [value + value*engineering_accuracy for value in x]
    #print(low_bound,high_bound)
    #Generate uniform random sample points inside of those boundaries 
    samples = [[np.random.uniform(low=low_bound[i],high=high_bound[i]) for i in range(len(low_bound))] for j in range(sample_points)]
    
    #Predict sample points
    predictions = []
    predictions.append(model.predict(samples).tolist())
    
    #Calculate sample mean & confidence intervals
    k = sample_points - 1 #Degrees of freedom
    s = np.std(predictions)
    m = np.mean(predictions)
    s_m = s / math.sqrt(k + 1)
    #print(s,m)
    mean_interval = [m - t.ppf(0.975,k)*s_m,m + t.ppf(0.975,k)*s_m]

    #print(k,t.ppf(0.025,k))

    #Calculate sample standard deviation & confidence intervals
    interval = [math.sqrt(k*s**2/chi2.ppf(1-confidence_level/2,k)),math.sqrt(k*s**2/chi2.ppf(confidence_level/2,k))]

    #Print Relevant Stats
    percent_error = lambda x: (np.mean(x) - x[0])/np.mean(x)
    #print('Mean:',m,mean_interval,percent_error(mean_interval))
    #print('Stdev:',s,interval,percent_error(interval))
    
    mu = m
    sigma = max(interval)
    
    return mu,sigma


#Functions which generate markdown
def create_figure_markdown(fig,caption,fname):
    """Create Markdown and the correct files for a Figure.
    
    Generate an HTML string to describe and display a figure. 
    Save the image of the figure to the spot the HTML is refferencing.
    
    Args:
        fig(matplotlib.): A matplotlib figure handle. 
    
        caption(str): The figure caption.
    
        fname(str): The file name to save the figure.
    
    Returns:
        str: The html string for display.
    
    """
    
    base_url = os.path.dirname(os.path.realpath('../tmp'))
    
    #Save Figure to File in Temp Folder (Should be Unique Name)
    fig.savefig('../tmp/' + fname)
    plt.close(fig)
    url = base_url + '/tmp/' + fname
    
    #Create HTML for Displaying that Figure
    html = '<div class=\'figure\'> <img src=\'' + url + '\' >\n' 
    html += '<p>' + caption + '</p></div>\n'
    
    return html


def summarize_success_probability(self):
    """Generate an HTML string that summarizes the model success probability."""
    
    success_prob = 0
    threshold = 0.9
    for i,probability in enumerate(self.probabilities):
        success_prob += (1-success_prob)*(probability/100)
        if success_prob > threshold:
            break
    
    html = '<p><b>(Left)</b> Success Probability Analysis: In order to have a ' + str(round(threshold*100)) + '% chance of successfully meeting the stated objective above ' + str(i+1) + ' strains must be constructed.'
    html += ' <b>(Right)</b> Strains Selected: Here the black pluses show the points analyzed in the data set.  Larger Plus means more production.  Blue plusses show predicted strains.</p>'
    return html

#=========================================================# # Helper Functions                                        # #---------------------------------------------------------# #Helper Functions Return true if the input is a number. Apply softmax function to a list of numbers and return a list of probabilities. Calculate Euclidean Distance between two points in R**n Create the search bounds for the feature space.          Feature bounds are created to limit the search space      of optimizers to points near the data set.          Args:         features(array_like): Input features to the machine learning model with dimensions              of (number_of_samples,cardinality_of_feature_vector).                  padding_factor(float,optional): The factor to extrapolate outside the data set.              For example, if a particular element in the feature vector has a maximum value of 10             and the padding_factor is set to 2, the upper bound for that element of the feature             vector will be 20. Default 1.              negativeAllowed(bool): Are negative bound values allowed? Default False.          Returns:         list: A list of tuples where each element of the list contains a tuple of length 2              that contains the minimum and maximum bound for the corresponding element of the             feature vector. Sample a machine learning model in a ball about a chosen input feature.         Return the mean and standard deviation of the outputs.          Args:         x(array_like): The input feature used as the center point of the ball.              engineering_accuracy(float): A Percent used to determine the radius of the ball.                model(sklearn.base.BaseEstimator): The scikit-learn style machine learning model to sample.              sample_points(int,optional): Number of points to choose in the ball.           confidence_level(float,optional): Default 0.95.              seed(int,optional): Setting the seed makes calling this function              deterministic so the same points are chosen for a given input. Default None.          Returns:         float: The mean of the outputs generated by the model from inputs sampled              inside the ball.                  float: The standard deviation of outputs generated by the model from inputs              sampled inside the ball #Set Seed So this is a deterministic algorithm for each point! #print('point:',point) #print('engineering accuracy',engineering_accuracy) #print('model',model) #Generate Interval for Random Samples #print(low_bound,high_bound) #Generate uniform random sample points inside of those boundaries #Predict sample points #Calculate sample mean & confidence intervals #Degrees of freedom #print(s,m) #print(k,t.ppf(0.025,k)) #Calculate sample standard deviation & confidence intervals #Print Relevant Stats #print('Mean:',m,mean_interval,percent_error(mean_interval)) #print('Stdev:',s,interval,percent_error(interval)) #Functions which generate markdown Create Markdown and the correct files for a Figure.          Generate an HTML string to describe and display a figure.      Save the image of the figure to the spot the HTML is refferencing.          Args:         fig(matplotlib.): A matplotlib figure handle.               caption(str): The figure caption.              fname(str): The file name to save the figure.          Returns:         str: The html string for display. #Save Figure to File in Temp Folder (Should be Unique Name) #Create HTML for Displaying that Figure Generate an HTML string that summarizes the model success probability.