def objective_function(self, fps, *args): model, weights, inputs, meas = args _fitter_to_model_params(model, fps) if weights is None: return np.ravel(np.subtract(model(*inputs), meas)) else: return np.ravel(weights * np.subtract(model(*inputs), meas))
def __call__(self, model, x, measured_raw_cts, measured_bkg_cts, t_raw, t_bkg, x_err=None, **kwargs): if x_err is not None: model = IntModel(model.__class__)(x_err, *model.parameters) model_copy = _validate_model(model, self.supported_constraints) farg = _convert_input(x, measured_raw_cts) farg = (model_copy, measured_bkg_cts, t_raw, t_bkg) + farg p0, _ = _model_to_fit_params(model_copy) # TODO: Honor estimate_jacobian in kwargs, and/or determine if # model supports jacobian, and/or if fitter supports the jac argument. fitparams, self.fit_info = self._opt_method( self.objective_function, p0, farg, jac=self.objective_derivative, **kwargs) _fitter_to_model_params(model_copy, fitparams) return model_copy
def __call__(self, model, in_coords, ref_coords, sigma=5.0, maxsig=4.0, **kwargs): model_copy = _validate_model(model, ['bounds']) x, y = in_coords xref, yref = ref_coords xmax = max(np.max(x), np.max(xref)) ymax = max(np.max(y), np.max(yref)) landscape = self.mklandscape(ref_coords, sigma, maxsig, (int(ymax),int(xmax))) farg = (model_copy,) + _convert_input(x, y, landscape) p0, _ = _model_to_fit_params(model_copy) # TODO: Use the name of the parameter to infer the step size ranges = [] for p in model_copy.param_names: bounds = model_copy.bounds[p] try: diff = np.diff(bounds)[0] except TypeError: pass else: if diff > 0: ranges.append(slice(*(bounds+(min(0.5*sigma, 0.1*diff),)))) continue ranges.append((getattr(model_copy, p).value,) * 2) # Ns=1 limits the fitting along an axis where the range is not a slice # object: this is those were the bounds are equal (i.e. fixed param) fitted_params = self._opt_method(self.objective_function, ranges, farg, Ns=1, finish=None, **kwargs) _fitter_to_model_params(model_copy, fitted_params) return model_copy
def __call__(self, model, in_coords, ref_coords, sigma=5.0, maxsig=4.0, **kwargs): model_copy = _validate_model(model, ['bounds', 'fixed']) # Starting simplex step size is set to be 5% of parameter values # Need to ensure this is larger than the convergence tolerance # so move the initial values away from zero if necessary try: xtol = kwargs['options']['xtol'] except KeyError: pass else: for p in model_copy.param_names: pval = getattr(model_copy, p).value if abs(pval) < 20*xtol and 'offset' in p: getattr(model_copy, p).value = 20*xtol if pval == 0 \ else (np.sign(pval) * 20*xtol) tree = spatial.cKDTree(list(zip(*ref_coords))) # avoid _convert_input since tree can't be coerced to a float x, y = in_coords farg = (model_copy, x, y, sigma, maxsig, tree) p0, _ = _model_to_fit_params(model_copy) result = self._opt_method(self.objective_function, p0, farg, **kwargs) fitted_params = result['x'] _fitter_to_model_params(model_copy, fitted_params) return model_copy
def evaluate(self, pars, neg=False): if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) if self.m == 1: loglike = -np.sum(np.log(mean_model)) - \ np.sum(self.y/mean_model) else: loglike = -2.0*self.m*(np.sum(np.log(mean_model)) + np.sum(self.y/mean_model) + np.sum((2.0 / (2. * self.m) - 1.0) * np.log(self.y))) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def __call__(self, model, x, y, weights=None, maxiter=DEFAULT_MAXITER, epsilon=DEFAULT_EPS): if model.linear: raise ModelLinearityError( 'Model is linear in parameters; ' 'non-linear fitting methods should not be used.') model_copy = model.copy() init_values, fit_param_indicies = _model_to_fit_params(model_copy) bounds = np.array(list(model.bounds.values()))[fit_param_indicies] minimizer_kwargs = {"method": "BFGS"} opt_res = optimize.basinhopping( lambda fps: self.objective_function(fps, model_copy, x, y, weights ), init_values, minimizer_kwargs=minimizer_kwargs, accept_test=lambda *args, **kwargs: self._bounds_check( *args, bounds=bounds, **kwargs), take_step=lambda *args, **kwargs: self._take_step( *args, bounds=bounds, **kwargs), callback=lambda x, f, acc: self._dynamic_step(x, f, acc)) _fitter_to_model_params(model_copy, opt_res.x) return model_copy
def _compute_mean_model(self, pars): # if no polynomial is used, initialize the mean # model as a row of zeros if self.model is not None: _fitter_to_model_params(self.model, pars[-self.npar:]) mean_model = self.model(self.x) else: mean_model = np.ones_like(self.x) if self.n_gauss > 0: # else get the weights vector out of the # parameter vector and compute the polynomial # get the weights out of the parameter vector w = pars[:self.n_gauss] # compute polynomial mean model mean_model *= np.dot(self.pft, w) # if responses are given, apply them before # calculating the likelihood if self.apply_response: model_counts = self._apply_response(mean_model) else: model_counts = mean_model return model_counts
def __call__(self, model, in_coords, ref_coords, sigma=5.0, maxsig=4.0, **kwargs): model_copy = _validate_model(model, ['bounds', 'fixed']) # Starting simplex step size is set to be 5% of parameter values # Need to ensure this is larger than the convergence tolerance # so move the initial values away from zero if necessary try: xtol = kwargs['options']['xtol'] except KeyError: pass else: for p in model_copy.param_names: pval = getattr(model_copy, p).value if abs(pval) < 20 * xtol and 'offset' in p: getattr(model_copy, p).value = 20*xtol if pval == 0 \ else (np.sign(pval) * 20*xtol) tree = spatial.cKDTree(list(zip(*ref_coords))) # avoid _convert_input since tree can't be coerced to a float x, y = in_coords farg = (model_copy, x, y, sigma, maxsig, tree) p0, _ = _model_to_fit_params(model_copy) result = self._opt_method(self.objective_function, p0, farg, **kwargs) fitted_params = result['x'] _fitter_to_model_params(model_copy, fitted_params) return model_copy
def __call__(self, model, in_coords, ref_coords, sigma=5.0, maxsig=4.0, landscape=None, **kwargs): model_copy = _validate_model(model, ['bounds', 'fixed']) # Turn 1D arrays into tuples to allow iteration over axes try: iter(in_coords[0]) except TypeError: in_coords = (in_coords, ) try: iter(ref_coords[0]) except TypeError: ref_coords = (ref_coords, ) # Remember, coords are x-first (reversed python order) if landscape is None: landshape = tuple( int(max(np.max(inco), np.max(refco)) + 10) for inco, refco in zip(in_coords, ref_coords))[::-1] landscape = self.mklandscape(ref_coords, sigma, maxsig, landshape) farg = (model_copy, np.asanyarray(in_coords, dtype=float), landscape) p0, _ = _model_to_fit_params(model_copy) # TODO: Use the name of the parameter to infer the step size ranges = [] for p in model_copy.param_names: bounds = model_copy.bounds[p] try: diff = np.diff(bounds)[0] except TypeError: pass else: # We don't check that the value of a fixed param is within bounds if diff > 0 and not model_copy.fixed[p]: ranges.append( slice(*(bounds + (min(0.5 * sigma, 0.1 * diff), )))) continue ranges.append((getattr(model_copy, p).value, ) * 2) # Ns=1 limits the fitting along an axis where the range is not a slice # object: this is those were the bounds are equal (i.e. fixed param) fitted_params = self._opt_method(self.objective_function, ranges, farg, Ns=1, finish=None, **kwargs) _fitter_to_model_params(model_copy, fitted_params) return model_copy
def test_generate_model_data(self): pe = PSDParEst(self.ps) m = self.model _fitter_to_model_params(m, self.t0) model = m(self.ps.freq) pe_model = pe._generate_model(self.lpost, [2.0, 0.1, 100, 2.0]) assert np.allclose(model, pe_model)
def lnprob(mc_params, model, bounds, measured_raw_cts, measured_bkg_cts, t_raw, t_bkg, x): min_bounds, max_bounds = bounds for value, min_bound, max_bound in zip(mc_params, min_bounds, max_bounds): if not np.isnan(min_bound) and value < min_bound: return -np.inf if not np.isnan(max_bound) and value > max_bound: return -np.inf _fitter_to_model_params(model, mc_params) lnp = 0. # TODO: evaluate prior based on bounds lnc = cstat(measured_raw_cts, model, measured_bkg_cts, t_raw, t_bkg, x) return lnp - lnc
def evaluate(self, pars): # Fix values of fixed parameters print 'Antes...', pars pars = PrepareParameters(GlobalModel, pars) print 'Despues...', pars _fitter_to_model_params(GlobalModel, pars) mean_model = GlobalModel(self.x) loglike = np.sum(-0.5 * np.log(2. * np.pi) - np.log(self.yerr) - (self.y - mean_model)**2 / (2. * self.yerr**2)) return loglike
def evaluate(self, pars, neg=False): """ Evaluate the log-likelihood for a given set of parameters. Parameters ---------- pars : numpy.ndarray An array of parameters at which to evaluate the model and subsequently the log-likelihood. Note that the length of this array must match the free parameters in ``model``, i.e. ``npar`` neg : bool, optional, default ``False`` If ``True``, return the *negative* log-likelihood, i.e. ``-loglike``, rather than ``loglike``. This is useful e.g. for optimization routines, which generally minimize functions. Returns ------- loglike : float The log(likelihood) value for the data and model. """ if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) with warnings.catch_warnings(record=True) as out: if self.m == 1: loglike = -np.sum(np.log(mean_model)) - \ np.sum(self.y/mean_model) else: loglike = -2.0*self.m*(np.sum(np.log(mean_model)) + np.sum(self.y/mean_model) + np.sum((2.0 / (2. * self.m) - 1.0) * np.log(self.y))) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def test_compute_model(self): self.optres._compute_model(self.lpost) assert hasattr(self.optres, "mfit"), "OptimizationResult object should have mfit " \ "attribute at this point!" _fitter_to_model_params(self.model, self.opt.x) mfit_test = self.model(self.lpost.x) assert np.allclose(self.optres.mfit, mfit_test)
def evaluate(self, params): # Daniela: set the input parameters in the astropy model using the # list of parameters in params _fitter_to_model_params(self.model, params) # Daniela: make the mean model mean_model = self.model(x) # Daniela: not sure what your 'x' in this log-likelihood is, but it should be # the mean model loglike = np.sum(-mean_model + self.y*np.log(mean_model) - gammaln(self.y + 1)) return loglike
def test_generate_model_data(self): pe = PSDParEst(self.ps) m = self.model _fitter_to_model_params(m, self.t0) model = m(self.ps.freq) pe_model = pe._generate_model(self.lpost, [self.x_0_0, self.fwhm_0, self.amplitude_0, self.amplitude_1]) assert np.allclose(model, pe_model)
def evaluate(self, pars, neg=False): """ Evaluate the log-likelihood for a given set of parameters. Parameters ---------- pars : numpy.ndarray An array of parameters at which to evaluate the model and subsequently the log-likelihood. Note that the length of this array must match the free parameters in ``model``, i.e. ``npar`` neg : bool, optional, default ``False`` If ``True``, return the *negative* log-likelihood, i.e. ``-loglike``, rather than ``loglike``. This is useful e.g. for optimization routines, which generally minimize functions. Returns ------- loglike : float The log(likelihood) value for the data and model. """ if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) with warnings.catch_warnings(record=True) as out: if self.m == 1: loglike = -np.sum(np.log(mean_model)) - \ np.sum(self.y/mean_model) else: loglike = -2.0 * self.m * (np.sum(np.log(mean_model)) + np.sum( self.y / mean_model) + np.sum( (2.0 / (2. * self.m) - 1.0) * np.log(self.y))) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def test_compute_model(self): optres = OptimizationResultsSubclassDummy(self.lpost, self.opt, neg=True) optres._compute_model(self.lpost) assert hasattr(optres, "mfit"), "OptimizationResult object should have mfit " \ "attribute at this point!" _fitter_to_model_params(self.model, self.opt.x) mfit_test = self.model(self.lpost.x) assert np.all(optres.mfit == mfit_test)
def lnlike(theta, x, y, yerr, model): # Convert the array of parameter values back into model parameters _fitter_to_model_params(model, theta) mod_y = model(x) # inv_sigma2 = 1.0 / (yerr ** 2 + mod_y ** 2 * np.exp(2 * lnf)) # res = -0.5 * (np.sum((y - mod_y) ** 2 * inv_sigma2 - np.log(inv_sigma2))) if np.sum(yerr) > 0: res = -0.5 * np.sum(((y - mod_y) / yerr)**2) else: res = -0.5 * np.sum((y - mod_y)**2) return res
def __call__(self, model, *args, weights=None, maxiter=100, acc=1e-7, epsilon=1.4901161193847656e-08, estimate_jacobian=False): from scipy import optimize model_copy = _validate_model(model, self.supported_constraints) farg = ( model_copy, weights, ) + args if model_copy.fit_deriv is None or estimate_jacobian: dfunc = None else: dfunc = self._wrap_deriv init_values, _ = _model_to_fit_params(model_copy) fitparams, cov_x, dinfo, mess, ierr = optimize.leastsq( self.objective_function, init_values, args=farg, Dfun=dfunc, col_deriv=model_copy.col_fit_deriv, maxfev=maxiter, epsfcn=epsilon, xtol=acc, full_output=True) _fitter_to_model_params(model_copy, fitparams) self.fit_info.update(dinfo) self.fit_info['cov_x'] = cov_x self.fit_info['message'] = mess self.fit_info['ierr'] = ierr if ierr not in [1, 2, 3, 4]: warnings.warn( "The fit may be unsuccessful; check " "fit_info['message'] for more information.", AstropyUserWarning) # now try to compute the true covariance matrix if (len(args[-1]) > len(init_values)) and cov_x is not None: sum_sqrs = np.sum(self.objective_function(fitparams, *farg)**2) dof = len(args[-1]) - len(init_values) self.fit_info['param_cov'] = cov_x * sum_sqrs / dof else: self.fit_info['param_cov'] = None return model_copy
def create_simulated_power_spectra(nx, ny, observation_model, model_parameters, frequencies): d = np.zeros([nx, ny, len(frequencies)]) for i in range(0, nx): this_alpha = model_parameters[1][i] for j in range(0, ny): # This section will be replaced with a section that reads observed power spectra # Set the model parameters _fitter_to_model_params(observation_model, [model_parameters[0], this_alpha, model_parameters[2]]) # Create the true data psd_shape = observation_model(frequencies) # Now randomize the true data and store it in an iterable d[i, j, :] = psd_shape * np.random.chisquare(2, size=psd_shape.shape[0]) / 2.0 return d
def __call__(self, model, x, y, weights=None, **kwargs): """ Fit data to this model. Parameters ---------- model : `~astropy.modeling.FittableModel` model to fit to x, y x : array input coordinates y : array input coordinates weights : array, optional Weights for fitting. For data with Gaussian uncertainties, the weights should be 1/sigma. kwargs : dict optional keyword arguments to be passed to the optimizer or the statistic Returns ------- model_copy : `~astropy.modeling.FittableModel` a copy of the input model with parameters set by the fitter """ model_copy = _validate_model(model, self._opt_method.supported_constraints) farg = _convert_input(x, y) farg = (model_copy, weights) + farg p0, _ = _model_to_fit_params(model_copy) fitparams, self.fit_info = self._opt_method( self.log_probability, p0, farg, self.nsteps, save_samples=self.save_samples, **kwargs) # set the output model parameters to the "best fit" parameters _fitter_to_model_params(model_copy, fitparams) # get and set the symmetric and asymmetric uncertainties on each parameter model_copy = self._set_uncs_and_posterior(model_copy) return model_copy
def _compute_mean_model(self, pars): # if no polynomial is used, initialize the mean # model as a row of zeros if self.bkg_model is not None: # background model parameters are the second-to-last few in the list: if self.src_model is not None: bkg_pars = pars[-self.bkg_npar - self.src_npar:-self.src_npar] else: bkg_pars = pars[-self.bkg_npar - self.src_npar:] _fitter_to_model_params(self.bkg_model, bkg_pars) mean_model = self.bkg_model(self.x) else: mean_model = np.ones_like(self.x) if self.n_gauss > 0: # else get the weights vector out of the # parameter vector and compute the polynomial # get the weights out of the parameter vector w = pars[:self.n_gauss] # compute polynomial mean model mean_model *= np.dot(self.pft, w) if self.src_model is not None: # background model parameters are the second-to-last few in the list: src_pars = pars[-self.src_npar:] _fitter_to_model_params(self.src_model, src_pars) source_model = self.src_model(self.x) + mean_model else: source_model = None # if responses are given, apply them before # calculating the likelihood if self.apply_response: bkg_counts, source_counts = self._apply_response( mean_model, source_model) else: bkg_counts = mean_model source_counts = source_model return bkg_counts, source_counts
def evaluate(self, pars, neg=False): if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) loglike = np.sum(-0.5*np.log(2.*np.pi) - np.log(self.yerr) - (self.y-mean_model)**2/(2.*self.yerr**2)) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def __call__(self, model, in_coords, ref_coords, sigma=5.0, maxsig=4.0, **kwargs): model_copy = _validate_model(model, ['bounds']) x, y = in_coords xref, yref = ref_coords xmax = max(np.max(x), np.max(xref)) ymax = max(np.max(y), np.max(yref)) landscape = self.mklandscape(ref_coords, sigma, maxsig, (int(ymax), int(xmax))) farg = (model_copy, ) + _convert_input(x, y, landscape) p0, _ = _model_to_fit_params(model_copy) # TODO: Use the name of the parameter to infer the step size ranges = [] for p in model_copy.param_names: bounds = model_copy.bounds[p] try: diff = np.diff(bounds)[0] except TypeError: pass else: if diff > 0: ranges.append( slice(*(bounds + (min(0.5 * sigma, 0.1 * diff), )))) continue ranges.append((getattr(model_copy, p).value, ) * 2) # Ns=1 limits the fitting along an axis where the range is not a slice # object: this is those were the bounds are equal (i.e. fixed param) fitted_params = self._opt_method(self.objective_function, ranges, farg, Ns=1, finish=None, **kwargs) _fitter_to_model_params(model_copy, fitted_params) return model_copy
def evaluate(self, pars, neg=False): """ Evaluate the Gaussian log-likelihood for a given set of parameters. Parameters ---------- pars : numpy.ndarray An array of parameters at which to evaluate the model and subsequently the log-likelihood. Note that the length of this array must match the free parameters in ``model``, i.e. ``npar`` neg : bool, optional, default ``False`` If ``True``, return the *negative* log-likelihood, i.e. ``-loglike``, rather than ``loglike``. This is useful e.g. for optimization routines, which generally minimize functions. Returns ------- loglike : float The log(likelihood) value for the data and model. """ if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) loglike = np.sum(-0.5*np.log(2.*np.pi) - np.log(self.yerr) - (self.y-mean_model)**2/(2.*self.yerr**2)) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def evaluate(self, pars, neg=False): """ Evaluate the Gaussian log-likelihood for a given set of parameters. Parameters ---------- pars : numpy.ndarray An array of parameters at which to evaluate the model and subsequently the log-likelihood. Note that the length of this array must match the free parameters in ``model``, i.e. ``npar`` neg : bool, optional, default ``False`` If ``True``, return the *negative* log-likelihood, i.e. ``-loglike``, rather than ``loglike``. This is useful e.g. for optimization routines, which generally minimize functions. Returns ------- loglike : float The log(likelihood) value for the data and model. """ if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) loglike = np.sum(-0.5 * np.log(2. * np.pi) - np.log(self.yerr) - (self.y - mean_model)**2 / (2. * self.yerr**2)) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def evaluate(self, pars, neg=False): if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) loglike = np.sum(-mean_model + self.y*np.log(mean_model) \ - scipy_gammaln(self.y + 1.)) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def Minimize_OutputAnalysis(self, output): popt, pcov = output nparam = len(GlobalModel.parameters) _fitter_to_model_params(GlobalModel, popt) mean_model = GlobalModel(self.r) errors = np.sqrt(np.diag(pcov)) chi2 = Chi2Reduced(mean_model, self.shear, self.shear_err, df=nparam) more = { 'model_name': GlobalModel.name, 'param_names': [n.encode('utf-8') for n in GlobalModel.param_names], 'param_values': popt, 'param_errors': errors, 'param_covar': pcov, 'chi2': chi2 } output = scipy.optimize.optimize.OptimizeResult(more) return output
def objective_function(self, fps, *args): """ Function to minimize. Parameters ---------- fps : list parameters returned by the fitter args : list [model, [weights], [input coordinates]] """ model = args[0] weights = args[1] fitting._fitter_to_model_params(model, fps) meas = args[-1] if weights is None: return np.ravel(np.log(model(*args[2 : -1])) - np.log(meas)) else: return np.ravel(np.log(weights * model(*args[2 : -1])) - np.log(weights * meas))
def evaluate(self, pars, neg=False): if np.size(pars) != self.npar: raise IncorrectParameterError("Input parameters must" + " match model parameters!") _fitter_to_model_params(self.model, pars) mean_model = self.model(self.x) with warnings.catch_warnings(record=True) as out: loglike = np.sum(-np.log(2.*self.yerr) - \ (np.abs(self.y - mean_model)/self.yerr)) if not np.isfinite(loglike): loglike = logmin if neg: return -loglike else: return loglike
def _generate_model(self, lpost, pars): """ Helper function that generates a fake PSD similar to the one in the data, but with different parameters. Parameters ---------- lpost : instance of a Posterior or LogLikelihood subclass The object containing the relevant information about the data and the model pars : iterable A list of parameters to be passed to lpost.model in oder to generate a model data set. Returns: -------- model_data : numpy.ndarray An array of model values for each bin in lpost.x """ assert isinstance(lpost, LogLikelihood) or isinstance(lpost, Posterior), \ "lpost must be of type LogLikelihood or Posterior or one of its " \ "subclasses!" # assert pars is of correct length assert len(pars) == lpost.npar, "pars must be a list " \ "of %i parameters"%lpost.npar # get the model m = lpost.model # reset the parameters _fitter_to_model_params(m, pars) # make a model spectrum model_data = lpost.model(lpost.x) return model_data
# Daniela: for maximum likelihood fitting, we need to define the *negative* # log-likelihood: neg_loglike_sing = lambda x: -loglike_sing(x) # Daniela: here's the optimization: opt_sing = minimize(neg_loglike_sing, init_params_s, method="L-BFGS-B", tol=1.e-10) # Daniela: print the negative log-likelihood: #print("The value of the negative log-likelihood: " + str(opt_sing.fun)) # Daniela: the parameters at the maximum of the likelihood is in opt.x: fit_pars = opt_sing.x # Daniela : now we can put the parameters back into the Gaussian model _fitter_to_model_params(gaus_sing, fit_pars) # Bayesian information criterion # see also: https://en.wikipedia.org/wiki/Bayesian_information_criterion # bic = -2*loglike + n_params * log(n_datapoints) # note to myself: opt.fun is -loglike, so we'll just use that here bic_sing = 2.*opt_sing.fun + fit_pars.shape[0]*np.log(x.shape[0]) # Daniela: from here on, you can do the same for the model with two Gaussians # Then you can compare the two BICs for a slightly hacky way of model # comparison # DOUBLE GAUSSIAN FITTING ydg = y[:]
def _compute_model(self, lpost): _fitter_to_model_params(lpost.model, self.p_opt) self.mfit = lpost.model(lpost.x)
# fix x_0 of power law component pl.x_0.fixed = True # define constant c = models.Const1D() # make compound model plc = pl + c # parameters for fake data. alpha = 2.0 amplitude = 5.0 white_noise = 2.0 freq = np.linspace(0.01, 10.0, int(10.0 / 0.01)) from astropy.modeling.fitting import _fitter_to_model_params _fitter_to_model_params(plc, [amplitude, alpha, white_noise]) psd_shape = plc(freq) powers = psd_shape * np.random.chisquare(2, size=psd_shape.shape[0]) / 2.0 ps = Powerspectrum() ps.freq = freq ps.power = powers ps.df = ps.freq[1] - ps.freq[0] ps.m = 1 loglike = PSDLogLikelihood(ps.freq, ps.power, plc, m=ps.m) test_pars = [1, 5, 100] parest = PSDParEst(ps, fitmethod="L-BFGS-B", max_post=True) # flat prior for the power law index p_alpha = lambda alpha: ((-1. <= alpha) & (alpha <= 5.))
def __call__(self, model, in_coords, ref_coords, in_weights=None, ref_weights=None, matches=None, **kwargs): """ Perform a minimization using the KDTreeFitter Parameters ---------- model: FittableModel initial guess at model defining transformation in_coords: array-like (n x N) array of input coordinates ref_coords: array-like (n x M) array of reference coordinates in_weights: array-like (N,) weights for input coordinates ref_weights: array-like (M,) weights for reference coordinates kwargs: dict additional arguments to control fit Returns ------- Model: best-fitting model also assigns attributes: x: array-like best-fitting parameters fun: float final value of fitting function nit: int number of iterations performed """ model_copy = _validate_model(model, ['bounds', 'fixed']) # Turn 1D arrays into tuples to allow iteration over axes try: iter(in_coords[0]) except TypeError: in_coords = (in_coords, ) try: iter(ref_coords[0]) except TypeError: ref_coords = (ref_coords, ) # Starting simplex step size is set to be 5% of parameter values # Need to ensure this is larger than the convergence tolerance # so move the initial values away from zero if necessary try: xatol = kwargs['options']['xatol'] except KeyError: pass else: for p in model_copy.param_names: pval = getattr(model_copy, p).value ### EDITED THIS LINE SO TAKE A LOOK IF 2D MATCHING GOES WRONG!! if abs(pval) < 20 * xatol and not model_copy.fixed[ p]: # and 'offset' in p getattr(model_copy, p).value = 20 * xatol if pval == 0 \ else (np.sign(pval) * 20 * xatol) if in_weights is None: in_weights = np.ones((len(in_coords[0]), )) if ref_weights is None: ref_weights = np.ones((len(ref_coords[0]), )) # cKDTree.query() returns a value of n for no neighbour so make coding # easier by allowing this to match a zero-weighted reference ref_weights = np.append(ref_weights, (0, )) ref_coords = np.array(list(zip(*ref_coords))) tree = spatial.cKDTree(ref_coords) # avoid _convert_input since tree can't be coerced to a float farg = (model_copy, in_coords, ref_coords, in_weights, ref_weights, matches, tree) p0, _ = _model_to_fit_params(model_copy) arg_names = inspect.getfullargspec(self._opt_method).args args = [self.objective_function] if arg_names[1] == 'x0': args.append(p0) elif arg_names[1] == 'bounds': args.append( tuple(model_copy.bounds[p] for p in model_copy.param_names)) else: raise ValueError("Don't understand argument {}".format( arg_names[1])) if 'args' in arg_names: kwargs['args'] = farg if 'method' in arg_names: kwargs['method'] = self._method if 'minimizer_kwargs' in arg_names: kwargs['minimizer_kwargs'] = { 'args': farg, 'method': 'Nelder-Mead' } result = self._opt_method(*args, **kwargs) fitted_params = result['x'] _fitter_to_model_params(model_copy, fitted_params) self.statistic = result['fun'] self.niter = result['nit'] return model_copy
def objective_derivative(self, params, model, measured_bkg_cts, t_raw, t_bkg, x, measured_raw_cts): _fitter_to_model_params(model, params) return cstat_deriv(measured_raw_cts, model, measured_bkg_cts, t_raw, t_bkg, x)
# subplot ax2 = plt.axes([0.60, 0.35, 0.35, 0.35]) # plot the bands and all spectra for this star extdata.plot(ax, color="k", alpha=0.5) extdata.plot(ax2, color="k", alpha=0.5) # plot samples from the mcmc chaing flat_samples = fit2.fit_info["sampler"].get_chain(discard=int(0.1 * nsteps), flat=True) inds = np.random.randint(len(flat_samples), size=100) model_copy = p92_fit2.copy() for ind in inds: sample = flat_samples[ind] _fitter_to_model_params(model_copy, sample) ax.plot(1.0 / x, model_copy(x), "C1", alpha=0.05) ax2.plot(1.0 / x, model_copy(x), "C1", alpha=0.05) # for the figure legend ax.plot(1.0 / x, model_copy(x), "C1", alpha=0.05, label="EMCEE Fits") ax2.plot(1.0 / x, model_copy(x), "C1", alpha=0.05, label="EMCEE Fits") # ax.plot(1.0 / x, p92_init(x), "r--", label="P92 Init") ax.plot(1.0 / x, p92_fit(x), "r-", label="P92 Best Fit") ax2.plot(1.0 / x, p92_fit(x), "r-") # show components of best fitter p92_comps = p92_fit.copy() p92_comps.FUV_amp_0 = 0.0 p92_comps.NUV_amp_0 = 0.0 p92_comps.SIL1_amp_0 = 0.0