def NeuralNetwork(xData, yData, crossVal, perfMetric, pool):
    """

    """
    input_layer_size = xData.shape[1]
    nn = MLPRegressor(hidden_layer_sizes=(int(np.ceil(input_layer_size / 2)),
                                          int(np.ceil(input_layer_size / 2))),
                      activation="tanh",
                      solver="lbfgs",
                      warm_start=True)
    xScaled = (xData - np.mean(xData, axis=0)) / np.std(xData, axis=0)
    yScaled = (yData - np.mean(yData, axis=0)) / np.std(yData, axis=0)
    yScaled = yScaled.ravel()
    cv_ypred = model_selection.cross_val_predict(nn,
                                                 xScaled,
                                                 yScaled,
                                                 cv=crossVal,
                                                 n_jobs=1)
    cv_ypred = cv_ypred * np.std(yData, axis=0) + np.mean(yData, axis=0)
    nn.fit(xScaled, yScaled)
    ypred = nn.predict(xScaled)
    ypred = ypred * np.std(yData, axis=0) + np.mean(yData, axis=0)

    return Metrics.computeMetrics(
        cv_ypred, ypred, yData, input_layer_size), ypred, np.random.random(
            input_layer_size), np.random.random(1), cv_ypred
def MultipleRegression(xData, yData, crossVal, perfMetric, pool):
    """
    Simple multiple regression model. Takes an array of training predictor data
    and creates a least-squares fit with training predictand data. Geenerates 
    and returns predictions from a testing predictor data array.
    """
    def regression(training_predictors,
                   training_predictand,
                   testing_predictors,
                   returnCoefs=False):
        """
        Performs a simple linear OLS regression between the training predictor data and the training predictand data.
        Then it makes predictions against the testing predictor set. Optionally, it will return the trained model coefficients and intercept.
        """
        """ Append a column of ones so that we can compute an intercept """
        x = np.vstack(
            [training_predictors.T,
             np.ones(len(training_predictand))])
        """ Fit the model and get the coefficients """
        model = np.linalg.lstsq(x.T, training_predictand, rcond=None)
        coefs = model[0][:-1]
        intercept = model[0][-1]
        """ Return the testing predictions """
        if returnCoefs:
            return coefs, intercept

        return np.dot(testing_predictors, coefs) + intercept

    predictors = xData
    predictand = yData

    all_significant = True

    p = predictors.shape[1]

    cv_splits = [[train, test] for train, test in crossVal.split(predictand)]
    cv_predictors_train = [
        predictors[cv_splits[i][0]] for i in range(len(cv_splits))
    ]
    cv_predictand_train = [
        predictand[cv_splits[i][0]] for i in range(len(cv_splits))
    ]
    cv_predictors_test = [
        predictors[cv_splits[i][1]] for i in range(len(cv_splits))
    ]

    cv_predictand_star = pool.starmap(regression, [
        tuple([
            cv_predictors_train[i], cv_predictand_train[i],
            cv_predictors_test[i]
        ]) for i in range(len(cv_splits))
    ])

    cv_predictand_star = np.array(cv_predictand_star)
    cv_predictand_star = np.concatenate(cv_predictand_star).ravel()

    coef, intercept = regression(predictors,
                                 predictand,
                                 predictors,
                                 returnCoefs=True)
    predictandStar = np.dot(predictors, coef) + intercept

    metric_dict = Metrics.computeMetrics(cv_predictand_star, predictandStar,
                                         predictand, p)

    cov = (metric_dict['Root Mean Squared Error']**2) * np.linalg.inv(
        np.dot(np.transpose(xData), xData))
    se = [np.sqrt(cov[i][i]) for i in range(len(coef))]
    t_ = [coef[i] / se[i] for i in range(len(se))]
    tVal = t.ppf(1 - 0.05, len(predictandStar) - (p + 1))
    if True in [tt > -1 * tVal and tt < tVal for tt in t_]:
        all_significant = False

    return metric_dict, predictandStar, coef.flatten(), intercept.flatten(
    ), cv_predictand_star, all_significant