def l1_cross_distances(X): """ Computes the nonzero componentwise L1 cross-distances between the vectors in X. Parameters ---------- X: array_like An array with shape (n_samples, n_features) Returns ------- D: array with shape (n_samples * (n_samples - 1) / 2, n_features) The array of componentwise L1 cross-distances. ij: arrays with shape (n_samples * (n_samples - 1) / 2, 2) The indices i and j of the vectors in X associated to the cross- distances in D: D[k] = np.abs(X[ij[k, 0]] - Y[ij[k, 1]]). """ X = sk_utils.array2d(X) n_samples, n_features = X.shape n_nonzero_cross_dist = n_samples * (n_samples - 1) // 2 ij = np.zeros((n_nonzero_cross_dist, 2), dtype=np.int) D = np.zeros((n_nonzero_cross_dist, n_features)) ll_1 = 0 for k in range(n_samples - 1): ll_0 = ll_1 ll_1 = ll_0 + n_samples - k - 1 ij[ll_0:ll_1, 0] = k ij[ll_0:ll_1, 1] = np.arange(k + 1, n_samples) D[ll_0:ll_1] = np.abs(X[k] - X[(k + 1):n_samples]) return D, ij
def predict(self, X, eval_MSE=False, transformY=True, returnRV=False, integratedPrediction=False, eval_confidence_bounds=False, coef_bound=1.96, batch_size=None): """ This function evaluates the Gaussian Process model at x. Parameters ---------- `X` : array_like An array with shape (n_eval, n_features) giving the point(s) at which the prediction(s) should be made. `eval_MSE` : boolean, optional A boolean specifying whether the Mean Squared Error should be evaluated or not. Default assumes evalMSE = False and evaluates only the BLUP (mean prediction). `transformY` : boolean, optional A boolean specifying if the predicted values should correspond to the same space as the data given to the fit method, or to the warped space (in which the GP is fitted). Default is True. Setting to False can be useful to compute the Expected Improvement in an optimization process. `returnRV` : boolean, optional A boolean specifying if the method should return the predicted random variables at x instead of a float number. Default is False. `integratedPrediction` : boolean, optional A boolean specifying if the method should return the fully Bayesian prediction, ie compute the expectation given the posterior in the original space. If False, the returned value is the inverse value (by the mapping function) of the GP prediction. This is much more faster as the integratedPrediction needs to numerically compute the integral. Default is False. `eval_confidence_bounds` : boolean, optional A boolean specifying if the method should return the confidence bounds. Because of the non-linearity of the mapping function, this cannot be computed directly with the MSE, but needs to invert the mapping function. Default is False. If True, coef_bound specifies the boundary to compute. `coef_bound` : float, optional A float specifying the confidence bounds to compute. Upper and lower confidence bounds are computed as the inverse of m + coef_bound*sigma where m and sigma are the mean and the std of the posterior in the GP space. Default is 1.96 which corresponds to the 95% confidence bounds. `batch_size` : integer, optional An integer giving the maximum number of points that can be evaluated simultaneously (depending on the available memory). Default is None so that all given points are evaluated at the same time. Returns ------- `y` : array_like, shape (n_samples,) Prediction at x. `MSE` : array_like, optional (if eval_MSE == True) Mean Squared Error at x. `LCB` : array_like, optional (if eval_confidence_bounds == True) Lower confidence bound. `UCB` : array_like, optional (if eval_confidence_bounds == True) Upper confidence bound. """ # Check input shapes X = sk_utils.array2d(X) n_eval, _ = X.shape n_samples, n_features = self.X.shape n_samples_y, n_targets = self.y.shape if (n_targets > 1): raise ValueError('More than one target in the Y outputs. \ Currently only 1D outputs are handled') # Run input checks self._check_params(n_samples) if X.shape[1] != n_features: raise ValueError(("The number of features in X (X.shape[1] = %d) " "should match the number of features used " "for fit() " "which is %d.") % (X.shape[1], n_features)) # Normalize input if self.normalize: X = (X - self.X_mean) / self.X_std # Initialize output y = np.zeros(n_eval) if eval_MSE: MSE = np.zeros(n_eval) # Get pairwise componentwise L1-distances to the input training set dx = manhattan_distances(X, Y=self.X, sum_over_features=False) # Get regression function and correlation f = self.regr(X) r = self.corr(self.theta, dx).reshape(n_eval, n_samples) # Scaled predictor y_ = np.dot(f, self.beta) + np.dot(r, self.gamma) # Predictor y = (self.y_mean + self.y_std * y_).reshape(n_eval, n_targets) # transform the warped y, modeled as a Gaussian, to the real y size = y.shape[0] warped_y = np.copy(y) if (transformY): if (np.sum([y[i][0] > 8.2 for i in range(size)]) > 0): print('Warning : mapping_inversion failed') real_y = [self.mapping_inv(X[i], y[i][0]) for i in range(size)] real_y = self.raw_y_std * np.asarray(real_y) + self.raw_y_mean y = real_y.reshape(n_eval, n_targets) if self.y_ndim_ == 1: y = y.ravel() warped_y = warped_y.ravel() # Mean Squared Error if eval_MSE: C = self.C if C is None: # Light storage mode (need to recompute C, F, Ft and G) if self.verbose: print("This GaussianProcess used 'light' storage mode " "at instantiation. Need to recompute " "autocorrelation matrix...") reduced_likelihood_function_value, par = \ self.reduced_likelihood_function() self.C = par['C'] self.Ft = par['Ft'] self.G = par['G'] rt = linalg.solve_triangular(self.C, r.T, lower=True) if self.beta0 is None: # Universal Kriging u = linalg.solve_triangular(self.G.T, np.dot(self.Ft.T, rt) - f.T) else: # Ordinary Kriging u = np.zeros((n_targets, n_eval)) MSE = np.dot(self.sigma2.reshape(n_targets, 1), (1. - (rt**2.).sum(axis=0) + (u**2.).sum(axis=0))[np.newaxis, :]) MSE = np.sqrt((MSE**2.).sum(axis=0) / n_targets) # Mean Squared Error might be slightly negative depending on # machine precision: force to zero! MSE[MSE < 0.] = 0. if self.y_ndim_ == 1: MSE = MSE.ravel() sigma = np.sqrt(MSE) if (returnRV): return [ self.predicted_RV([warped_y[i]], sigma[i], X[i]) for i in range(size) ] else: if (eval_confidence_bounds): if not (transformY): print( 'Warning, transformY set to False but trying to evaluate conf bounds' ) warped_y_with_boundL = warped_y - coef_bound * sigma warped_y_with_boundU = warped_y + coef_bound * sigma pred_with_boundL = self.raw_y_std * np.asarray([ self.mapping_inv(X[i], warped_y_with_boundL[i])[0] for i in range(size) ]) + self.raw_y_mean pred_with_boundU = self.raw_y_std * np.asarray([ self.mapping_inv(X[i], warped_y_with_boundU[i])[0] for i in range(size) ]) + self.raw_y_mean if (integratedPrediction): lb = self.raw_y_min - 3. * (self.raw_y_max - self.raw_y_min) ub = self.raw_y_max + 3. * (self.raw_y_max - self.raw_y_min) print(lb, ub) integrated_real_y = [ self.integrate_prediction([warped_y[i]], sigma[i], X[i], lb, ub) for i in range(size) ] integrated_real_y = np.asarray(integrated_real_y) print('Integrated prediction') return integrated_real_y, MSE, pred_with_boundL, pred_with_boundU else: return y, MSE, pred_with_boundL, pred_with_boundU else: return y, MSE else: return y, MSE else: return y
def predict(self, X, eval_MSE=False, transformY=True, returnRV=False, integratedPrediction= False, eval_confidence_bounds=False,coef_bound=1.96, batch_size=None): """ This function evaluates the Gaussian Process model at x. Parameters ---------- X : array_like An array with shape (n_eval, n_features) giving the point(s) at which the prediction(s) should be made. eval_MSE : boolean, optional A boolean specifying whether the Mean Squared Error should be evaluated or not. Default assumes evalMSE = False and evaluates only the BLUP (mean prediction). transformY : boolean, optional A boolean specifying if the predicted values should correspond to the same space as the data given to the fit method, or to the warped space (in which the GP is fitted). Default is True. Setting to False can be useful to compute the Expected Improvement in an optimization process. returnRV : boolean, optional A boolean specifying if the method should return the predicted random variables at x instead of a float number. Default is False. integratedPrediction : boolean, optional A boolean specifying if the method should return the fully Bayesian prediction, ie compute the expectation given the posterior in the original space. If False, the returned value is the inverse value (by the mapping function) of the GP prediction. This is much more faster as the integratedPrediction needs to numerically compute the integral. Default is False. eval_confidence_bounds : boolean, optional A boolean specifying if the method should return the confidence bounds. Because of the non-linearity of the mapping function, this cannot be computed directly with the MSE, but needs to invert the mapping function. Default is False. If True, coef_bound specifies the boundary to compute. coef_bound : float, optional A float specifying the confidence bounds to compute. Upper and lower confidence bounds are computed as the inverse of m + coef_bound*sigma where m and sigma are the mean and the std of the posterior in the GP space. Default is 1.96 which corresponds to the 95% confidence bounds. batch_size : integer, optional An integer giving the maximum number of points that can be evaluated simultaneously (depending on the available memory). Default is None so that all given points are evaluated at the same time. Returns ------- y : array_like, shape (n_samples,) Prediction at x. MSE : array_like, optional (if eval_MSE == True) Mean Squared Error at x. LCB : array_like, optional (if eval_confidence_bounds == True) Lower confidence bound. UCB : array_like, optional (if eval_confidence_bounds == True) Upper confidence bound. """ # Check input shapes X = sk_utils.array2d(X) n_eval, _ = X.shape n_samples, n_features = self.X.shape n_samples_y, n_targets = self.y.shape if(n_targets > 1): raise ValueError('More than one target in the Y outputs. \ Currently only 1D outputs are handled') # Run input checks self._check_params(n_samples) if X.shape[1] != n_features: raise ValueError(("The number of features in X (X.shape[1] = %d) " "should match the number of features used " "for fit() " "which is %d.") % (X.shape[1], n_features)) # Normalize input if self.normalize: X = (X - self.X_mean) / self.X_std # Initialize output y = np.zeros(n_eval) if eval_MSE: MSE = np.zeros(n_eval) # Get pairwise componentwise L1-distances to the input training set dx = manhattan_distances(X, Y=self.X, sum_over_features=False) # Get regression function and correlation f = self.regr(X) r = self.corr(self.theta, dx).reshape(n_eval, n_samples) # Scaled predictor y_ = np.dot(f, self.beta) + np.dot(r, self.gamma) # Predictor y = (self.y_mean + self.y_std * y_).reshape(n_eval, n_targets) # transform the warped y, modeled as a Gaussian, to the real y size = y.shape[0] warped_y = np.copy(y) if(transformY): if( np.sum([ y[i][0] > 8.2 for i in range(size)]) >0): print('Warning : mapping_inversion failed') real_y = [ self.mapping_inv(X[i],y[i][0]) for i in range(size)] real_y = self.raw_y_std * np.asarray(real_y) +self.raw_y_mean y = real_y.reshape(n_eval, n_targets) if self.y_ndim_ == 1: y = y.ravel() warped_y = warped_y.ravel() # Mean Squared Error if eval_MSE: C = self.C if C is None: # Light storage mode (need to recompute C, F, Ft and G) if self.verbose: print("This GaussianProcess used 'light' storage mode " "at instantiation. Need to recompute " "autocorrelation matrix...") reduced_likelihood_function_value, par = \ self.reduced_likelihood_function() self.C = par['C'] self.Ft = par['Ft'] self.G = par['G'] rt = linalg.solve_triangular(self.C, r.T, lower=True) if self.beta0 is None: # Universal Kriging u = linalg.solve_triangular(self.G.T, np.dot(self.Ft.T, rt) - f.T) else: # Ordinary Kriging u = np.zeros((n_targets, n_eval)) MSE = np.dot(self.sigma2.reshape(n_targets, 1), (1. - (rt ** 2.).sum(axis=0) + (u ** 2.).sum(axis=0))[np.newaxis, :]) MSE = np.sqrt((MSE ** 2.).sum(axis=0) / n_targets) # Mean Squared Error might be slightly negative depending on # machine precision: force to zero! MSE[MSE < 0.] = 0. if self.y_ndim_ == 1: MSE = MSE.ravel() sigma = np.sqrt(MSE) if(returnRV): return [ self.predicted_RV([warped_y[i]],sigma[i],X[i]) for i in range(size)] else: if(eval_confidence_bounds): if not(transformY): print('Warning, transformY set to False but trying to evaluate conf bounds') warped_y_with_boundL = warped_y - coef_bound * sigma warped_y_with_boundU = warped_y + coef_bound * sigma pred_with_boundL = self.raw_y_std * np.asarray( [ self.mapping_inv(X[i],warped_y_with_boundL[i])[0] for i in range(size) ] ) +self.raw_y_mean pred_with_boundU = self.raw_y_std * np.asarray( [ self.mapping_inv(X[i],warped_y_with_boundU[i])[0] for i in range(size)] ) +self.raw_y_mean if(integratedPrediction): lb = self.raw_y_min - 3.*(self.raw_y_max-self.raw_y_min) ub = self.raw_y_max + 3.*(self.raw_y_max-self.raw_y_min) print(lb,ub) integrated_real_y = [ self.integrate_prediction([warped_y[i]],sigma[i],X[i],lb,ub) for i in range(size)] integrated_real_y = np.asarray(integrated_real_y) print('Integrated prediction') return integrated_real_y,MSE,pred_with_boundL,pred_with_boundU else: return y,MSE,pred_with_boundL,pred_with_boundU else: return y, MSE else: return y, MSE else: return y
def fit(self, X, y, detailed_y_obs=None, obs_noise=None): """ The Gaussian Copula Process model fitting method. Parameters ---------- `X` : double array_like An array with shape (n_samples, n_features) with the input at which observations were made. `y` : double array_like An array with shape (n_samples, ) or shape (n_samples, n_targets) with the observations of the output to be predicted. Currently only 1D targets are supported. `detailed_y_obs` : double list of list A list of length n_samples where entry at position i corresponds to the mutiple noisy observations (given as a list) of the input value X[i,:], and whose mean is y[i]. If not None, it can be used to learn the mapping function or fit the GP, see parameters mapWithNoise and useAllNoisyY of the GaussianCopulaProcess class. `obs_noise` : double array An array of shape (n_samples,) corresponding to the estimated noise in the observed y outputs. If not None, it can be used to model the noise with the Estimated Gaussian Noise method, see the model_noise parameter of the GaussianCopulaProcess class. Returns ------- `gcp` : self A fitted Gaussian Copula Process model object awaiting data to perform predictions. """ # Run input checks self._check_params() X = sk_utils.array2d(X) # Check if all CV obs are given # and if so, convert this list of list to array if (detailed_y_obs is not None): detailed_X, detailed_raw_y = listOfList_toArray(X, detailed_y_obs) y = np.asarray(y) self.y_ndim_ = y.ndim if y.ndim == 1: y = y[:, np.newaxis] if (detailed_y_obs is not None): detailed_raw_y = detailed_raw_y[:, np.newaxis] else: print( 'Warning: code is not ready for y outputs with dimension > 1') # Reshape theta if it is one dimensional and X is not x_dim = X.shape[1] #if not(self.theta.ndim == 1): # print('Warning : theta has not the right shape') self.theta = (np.ones((x_dim, self.theta.shape[0])) * self.theta).T self.thetaL = (np.ones((x_dim, self.thetaL.shape[0])) * self.thetaL).T self.thetaU = (np.ones((x_dim, self.thetaU.shape[0])) * self.thetaU).T #print('theta has new shape '+str(self.theta.shape)) self.random_state = sk_utils.check_random_state(self.random_state) X, y = sk_utils.check_arrays(X, y) # Check shapes of DOE & observations n_samples, n_features = X.shape _, n_targets = y.shape # Run input checks self._check_params(n_samples) # Normalize data or don't if self.normalize: X_mean = np.mean(X, axis=0) X_std = np.std(X, axis=0) X_std[X_std == 0.] = 1. X = (X - X_mean) / X_std raw_y_mean = np.mean(y, axis=0) raw_y_std = np.std(y, axis=0) raw_y_std[raw_y_std == 0.] = 1. y = (y - raw_y_mean) / raw_y_std if (obs_noise is not None): obs_noise = obs_noise / raw_y_std if (detailed_y_obs is not None): detailed_raw_y = (detailed_raw_y - raw_y_mean) / raw_y_std detailed_X = (detailed_X - X_mean) / X_std else: X_mean = np.zeros(1) X_std = np.ones(1) self.raw_y_min = np.min(y) self.raw_y_max = np.max(y) # Set attributes if (detailed_y_obs is not None): self.detailed_raw_y = detailed_raw_y self.detailed_X = detailed_X else: self.detailed_raw_y = None self.detailed_X = None if (self.detailed_raw_y is not None and self.mapWithNoise and self.useAllNoisyY): self.X = self.detailed_X self.raw_y = self.detailed_raw_y self.raw_y_mean = raw_y_mean self.raw_y_std = raw_y_std self.low_bound = np.min([-500., 5. * np.min(y)]) self.X_mean, self.X_std = X_mean, X_std # initialize mapping only if needed, i.e. it hasn't be done # yet of if we want to optimize the GCP hyperparameters if (self.try_optimize or (self.density_functions is None)): self.init_mappings() elif (self.detailed_raw_y is not None and self.useAllNoisyY): self.X = X self.raw_y = y self.raw_y_mean = raw_y_mean self.raw_y_std = raw_y_std self.low_bound = np.min([-500., 5. * np.min(y)]) self.X_mean, self.X_std = X_mean, X_std # initialize mapping only if needed, i.e. it hasn't be done # yet of if we want to optimize the GCP hyperparameters if (self.try_optimize or (self.density_functions is None)): self.init_mappings() self.X = self.detailed_X self.raw_y = self.detailed_raw_y else: self.X = X self.raw_y = y self.raw_y_mean = raw_y_mean self.raw_y_std = raw_y_std self.low_bound = np.min([-500., 5. * np.min(y)]) self.X_mean, self.X_std = X_mean, X_std # initialize mapping only if needed, i.e. it hasn't be done # yet of if we want to optimize the GCP hyperparameters if (self.try_optimize or (self.density_functions is None)): self.init_mappings() self.obs_noise = obs_noise self.update_copula_params() if self.try_optimize: # Maximum Likelihood Estimation of the parameters if self.verbose: print("Performing Maximum Likelihood Estimation of the " "autocorrelation parameters...") self.theta, self.reduced_likelihood_function_value_, par = \ self._arg_max_reduced_likelihood_function() if np.isinf(self.reduced_likelihood_function_value_): raise Exception("Bad parameter region. " "Try increasing upper bound") else: # Given parameters if self.verbose: print("Given autocorrelation parameters. " "Computing Gaussian Process model parameters...") self.reduced_likelihood_function_value_, par = \ self.reduced_likelihood_function() if np.isinf(self.reduced_likelihood_function_value_): raise Exception("Bad point. Try increasing theta0.") self.beta = par['beta'] self.gamma = par['gamma'] self.sigma2 = par['sigma2'] self.C = par['C'] self.Ft = par['Ft'] self.G = par['G'] return self
def fit(self, X, y,detailed_y_obs=None,obs_noise=None): """ The Gaussian Copula Process model fitting method. Parameters ---------- X : double array_like An array with shape (n_samples, n_features) with the input at which observations were made. y : double array_like An array with shape (n_samples, ) or shape (n_samples, n_targets) with the observations of the output to be predicted. Currently only 1D targets are supported. detailed_y_obs : double list of list A list of length n_samples where entry at position i corresponds to the mutiple noisy observations (given as a list) of the input value X[i,:], and whose mean is y[i]. If not None, it can be used to learn the mapping function or fit the GP, see parameters mapWithNoise and useAllNoisyY of the GaussianCopulaProcess class. obs_noise : double array An array of shape (n_samples,) corresponding to the estimated noise in the observed y outputs. If not None, it can be used to model the noise with the Estimated Gaussian Noise method, see the model_noise parameter of the GaussianCopulaProcess class. Returns ------- gcp : self A fitted Gaussian Copula Process model object awaiting data to perform predictions. """ # Run input checks self._check_params() X = sk_utils.array2d(X) # Check if all CV obs are given # and if so, convert this list of list to array if(detailed_y_obs is not None): detailed_X,detailed_raw_y = listOfList_toArray(X,detailed_y_obs) y = np.asarray(y) self.y_ndim_ = y.ndim if y.ndim == 1: y = y[:, np.newaxis] if(detailed_y_obs is not None): detailed_raw_y = detailed_raw_y[:, np.newaxis] else: print('Warning: code is not ready for y outputs with dimension > 1') # Reshape theta if it is one dimensional and X is not x_dim = X.shape[1] #if not(self.theta.ndim == 1): # print('Warning : theta has not the right shape') self.theta = (np.ones((x_dim,self.theta.shape[0])) * self.theta ).T self.thetaL = (np.ones((x_dim,self.thetaL.shape[0])) * self.thetaL ).T self.thetaU = (np.ones((x_dim,self.thetaU.shape[0])) * self.thetaU ).T #print('theta has new shape '+str(self.theta.shape)) self.random_state = check_random_state(self.random_state) X, y = sk_utils.check_arrays(X, y) # Check shapes of DOE & observations n_samples, n_features = X.shape _, n_targets = y.shape # Run input checks self._check_params(n_samples) # Normalize data or don't if self.normalize: X_mean = np.mean(X, axis=0) X_std = np.std(X, axis=0) X_std[X_std == 0.] = 1. X = (X - X_mean) / X_std raw_y_mean = np.mean(y, axis=0) raw_y_std = np.std(y, axis=0) raw_y_std[raw_y_std == 0.] = 1. y = (y - raw_y_mean) / raw_y_std if(obs_noise is not None): obs_noise = obs_noise / raw_y_std if(detailed_y_obs is not None): detailed_raw_y = (detailed_raw_y - raw_y_mean) / raw_y_std detailed_X = (detailed_X - X_mean) / X_std else: X_mean = np.zeros(1) X_std = np.ones(1) self.raw_y_min = np.min(y) self.raw_y_max = np.max(y) # Set attributes if(detailed_y_obs is not None): self.detailed_raw_y = detailed_raw_y self.detailed_X = detailed_X else: self.detailed_raw_y = None self.detailed_X = None if(self.detailed_raw_y is not None and self.mapWithNoise and self.useAllNoisyY ): self.X = self.detailed_X self.raw_y = self.detailed_raw_y self.raw_y_mean = raw_y_mean self.raw_y_std = raw_y_std self.low_bound = np.min([-500., 5. * np.min(y)]) self.X_mean, self.X_std = X_mean, X_std # initialize mapping only if needed, i.e. it hasn't be done # yet of if we want to optimize the GCP hyperparameters if (self.try_optimize or (self.density_functions is None)): self.init_mappings() elif(self.detailed_raw_y is not None and self.useAllNoisyY ): self.X = X self.raw_y = y self.raw_y_mean = raw_y_mean self.raw_y_std = raw_y_std self.low_bound = np.min([-500., 5. * np.min(y)]) self.X_mean, self.X_std = X_mean, X_std # initialize mapping only if needed, i.e. it hasn't be done # yet of if we want to optimize the GCP hyperparameters if (self.try_optimize or (self.density_functions is None)): self.init_mappings() self.X = self.detailed_X self.raw_y = self.detailed_raw_y else: self.X = X self.raw_y = y self.raw_y_mean = raw_y_mean self.raw_y_std = raw_y_std self.low_bound = np.min([-500., 5. * np.min(y)]) self.X_mean, self.X_std = X_mean, X_std # initialize mapping only if needed, i.e. it hasn't be done # yet of if we want to optimize the GCP hyperparameters if (self.try_optimize or (self.density_functions is None)): self.init_mappings() self.obs_noise = obs_noise self.update_copula_params() if self.try_optimize: # Maximum Likelihood Estimation of the parameters if self.verbose: print("Performing Maximum Likelihood Estimation of the " "autocorrelation parameters...") self.theta, self.reduced_likelihood_function_value_, par = \ self._arg_max_reduced_likelihood_function() if np.isinf(self.reduced_likelihood_function_value_): raise Exception("Bad parameter region. " "Try increasing upper bound") else: # Given parameters if self.verbose: print("Given autocorrelation parameters. " "Computing Gaussian Process model parameters...") self.reduced_likelihood_function_value_, par = \ self.reduced_likelihood_function() if np.isinf(self.reduced_likelihood_function_value_): raise Exception("Bad point. Try increasing theta0.") self.beta = par['beta'] self.gamma = par['gamma'] self.sigma2 = par['sigma2'] self.C = par['C'] self.Ft = par['Ft'] self.G = par['G'] return self