def test_from_theta_shomo(self): """Test init from theta for spatial specification.""" nstocks = 4 groups = [[(0, 1), (2, 3)]] ncat = len(groups) alpha, beta, gamma = .01, .16, .09 # A, B, C - n x n matrices avecs = np.ones((ncat+1, nstocks)) * alpha**.5 bvecs = np.ones((ncat+1, nstocks)) * beta**.5 dvecs = np.vstack([np.ones((1, nstocks)), np.ones((ncat, nstocks)) * gamma**.5]) param = ParamSpatial.from_abdv(avecs=avecs, bvecs=bvecs, dvecs=dvecs, groups=groups) restriction = 'shomo' target = None theta = [avecs[:, 0], bvecs[:, 0], dvecs[0], dvecs[1:, 0]] theta = np.concatenate(theta) param_new = ParamSpatial.from_theta(theta=theta, groups=groups, restriction=restriction, target=target) npt.assert_array_equal(param.amat, param_new.amat) npt.assert_array_equal(param.bmat, param_new.bmat) npt.assert_array_equal(param.cmat, param_new.cmat) npt.assert_array_equal(param.avecs, param_new.avecs) npt.assert_array_equal(param.bvecs, param_new.bvecs) npt.assert_array_equal(param.dvecs, param_new.dvecs) target = param.get_uvar() theta = [avecs[:, 0], bvecs[:, 0]] theta = np.concatenate(theta) cmat = param.find_cmat(amat=param.amat, bmat=param.bmat, target=target) param_new = ParamSpatial.from_theta(theta=theta, groups=groups, restriction=restriction, target=target) npt.assert_array_equal(param.amat, param_new.amat) npt.assert_array_equal(param.bmat, param_new.bmat) npt.assert_array_equal(cmat, param_new.cmat) npt.assert_array_equal(param.avecs, param_new.avecs) npt.assert_array_equal(param.bvecs, param_new.bvecs) # npt.assert_array_equal(None, param_new.dvecs) cfree = True theta = [avecs[:, 0], bvecs[:, 0], param.cmat[np.tril_indices(nstocks)]] theta = np.concatenate(theta) param_new = ParamSpatial.from_theta(theta=theta, groups=groups, restriction=restriction, cfree=cfree) npt.assert_array_equal(param.amat, param_new.amat) npt.assert_array_equal(param.bmat, param_new.bmat) npt.assert_array_equal(np.tril(param.cmat), param_new.cmat) npt.assert_array_equal(param.avecs, param_new.avecs) npt.assert_array_equal(param.bvecs, param_new.bvecs) npt.assert_array_equal(None, param_new.dvecs)
def test_from_theta_ghomo_special(self): """Test group init from theta for spatial specification.""" nstocks = 4 groups = [[(0, 1, 2, 3)]] ncat = len(groups) alpha = [.01, .02, .03, .04, .05] beta = [.07, .08, .09, .1, .11] delta = [.13, .14, .15, .16, .17] # A, B, C - n x n matrices avecs = np.ones((ncat+1, nstocks)) bvecs = np.ones((ncat+1, nstocks)) dvecs = np.ones((ncat+1, nstocks)) avecs[0] = alpha[:4] avecs[1] *= alpha[-1] bvecs[0] = beta[:4] bvecs[1] *= beta[-1] dvecs[0] = delta[:4] dvecs[1] *= delta[-1] param = ParamSpatial.from_abdv(avecs=avecs, bvecs=bvecs, dvecs=dvecs, groups=groups) target = param.get_uvar() theta = np.concatenate([alpha, beta]) cmat = param.find_cmat(amat=param.amat, bmat=param.bmat, target=target) uvar = param.find_stationary_var(amat=param.amat, bmat=param.bmat, cmat=cmat) npt.assert_array_almost_equal(target, uvar) restriction = 'h**o' param_homo = ParamSpatial.from_theta(theta=theta, groups=groups, restriction=restriction, target=target) theta_homo = param_homo.get_theta(restriction=restriction, use_target=False) restriction = 'ghomo' param_ghomo = ParamSpatial.from_theta(theta=theta, groups=groups, restriction=restriction, target=target) theta_ghomo = param_ghomo.get_theta(restriction=restriction, use_target=False) npt.assert_array_almost_equal(cmat, param.cmat) npt.assert_array_almost_equal(theta_ghomo, theta_homo, decimal=3) for param_check in [param_homo, param_ghomo]: npt.assert_array_equal(param.avecs, param_check.avecs) npt.assert_array_equal(param.bvecs, param_check.bvecs) npt.assert_array_equal(param.amat, param_check.amat) npt.assert_array_equal(param.bmat, param_check.bmat) npt.assert_array_equal(cmat, param_check.cmat)
def test_from_theta_ghomo(self): """Test group init from theta for spatial specification.""" nstocks = 4 groups = [[(0, 1), (2, 3)]] ncat = len(groups) alpha = [.01, .02, .03, .04, .05, .06] beta = [.07, .08, .09, .1, .11, .12] delta = [.13, .14, .15, .16, .17, .18] # A, B, C - n x n matrices avecs = np.ones((ncat+1, nstocks)) bvecs = np.ones((ncat+1, nstocks)) dvecs = np.ones((ncat+1, nstocks)) avecs[0] = alpha[:4] avecs[1, :2] *= alpha[-2] avecs[1, 2:] *= alpha[-1] bvecs[0] = beta[:4] bvecs[1, :2] *= beta[-2] bvecs[1, 2:] *= beta[-1] dvecs[0] = delta[:4] dvecs[1, :2] *= delta[-2] dvecs[1, 2:] *= delta[-1] param = ParamSpatial.from_abdv(avecs=avecs, bvecs=bvecs, dvecs=dvecs, groups=groups) restriction = 'ghomo' target = param.get_uvar() theta = np.concatenate([alpha, beta]) cmat = param.find_cmat(amat=param.amat, bmat=param.bmat, target=target) uvar = param.find_stationary_var(amat=param.amat, bmat=param.bmat, cmat=cmat) npt.assert_array_almost_equal(target, uvar) param_new = ParamSpatial.from_theta(theta=theta, groups=groups, restriction=restriction, target=target) npt.assert_array_equal(param.avecs, param_new.avecs) npt.assert_array_equal(param.bvecs, param_new.bvecs) # npt.assert_array_equal(None, param_new.dvecs) npt.assert_array_equal(param.amat, param_new.amat) npt.assert_array_equal(param.bmat, param_new.bmat) npt.assert_array_equal(cmat, param_new.cmat) npt.assert_array_almost_equal(cmat, param.cmat)
def likelihood(self, theta, model='standard', restriction='full', target=None, cfree=False, groups=None, cython=True, use_penalty=False): """Compute the conditional log-likelihood function. Parameters ---------- theta : 1dim array Dimension depends on the model restriction model : str Specific model to estimate. Must be - 'standard' - 'spatial' restriction : str Restriction on parameters. Must be - 'full' - 'diagonal' - 'scalar' target : (nstocks, nstocks) array Estimate of unconditional variance matrix cfree : bool Whether to leave C matrix free (True) or not (False) groups : list of lists of tuples Encoded groups of items cython : bool Whether to use Cython optimizations (True) or not (False) use_penalty : bool Whether to include penalty term in the likelihood Returns ------- float The value of the minus log-likelihood function. If some regularity conditions are violated, then it returns some obscene number. """ try: if model == 'standard': param = ParamStandard.from_theta(theta=theta, target=target, nstocks=self.innov.shape[1], restriction=restriction) elif model == 'spatial': param = ParamSpatial.from_theta(theta=theta, target=target, cfree=cfree, restriction=restriction, groups=groups) else: raise NotImplementedError('The model is not implemented!') # TODO: Temporary hack to exclude errors in optimization if isinstance(param, np.ndarray): return 1e10 if param.constraint() >= 1: return 1e10 # if param.uvar_bad(): # return 1e10 args = [self.hvar, self.innov, param.amat, param.bmat, param.cmat] penalty = param.penalty() if use_penalty else 0 if cython: filter_var(*args) nstocks = self.innov.shape[1] idxl = np.tril_indices(nstocks) idxu = np.triu_indices(nstocks) self.hvar[:, idxu[0], idxu[1]] = self.hvar[:, idxl[0], idxl[1]] return likelihood_gauss(self.hvar, self.innov) + penalty else: filter_var_python(*args) return likelihood_python(self.hvar, self.innov) + penalty except: return 1e10
def estimate(self, param_start=None, restriction='scalar', cfree=False, use_target=False, model='standard', groups=None, method='SLSQP', cython=True, use_penalty=False): """Estimate parameters of the BEKK model. Parameters ---------- param_start : ParamStandard or ParamSpatial instance Starting parameters. See Notes for more details. model : str Specific model to estimate. Must be - 'standard' - 'spatial' restriction : str Restriction on parameters. Must be - 'full' - 'diagonal' - 'group' (only applicable with 'spatial' model) - 'scalar' use_target : bool Whether to use variance targeting (True) or not (False) cfree : bool Whether to leave C matrix free (True) or not (False) groups : list of lists of tuples Encoded groups of items method : str Optimization method. See scipy.optimize.minimize cython : bool Whether to use Cython optimizations (True) or not (False) use_penalty : bool Whether to include penalty term in the likelihood Returns ------- BEKKResults instance Estimation results object Notes ----- If no param_start is given, the program will estimate parameters in the order 'from simple to more complicated' (from scalar to diagonal to full) while always using variance targeting. """ # Start timer for the whole optimization time_start = time.time() # Check for incompatible inputs if use_target and cfree: raise ValueError('use_target and cfree are incompatible!') # if (groups is not None) and (model != 'spatial'): # raise ValueError('The model is incompatible with weights!') # Update default settings nobs, nstocks = self.innov.shape var_target = estimate_uvar(self.innov) self.hvar = np.zeros((nobs, nstocks, nstocks), dtype=float) self.hvar[0] = var_target.copy() # Check for existence of initial guess among arguments. # Otherwise, initialize. if param_start is None: common = { 'restriction': restriction, 'method': method, 'use_penalty': use_penalty, 'use_target': use_target } if model == 'standard': param_start = self.init_param_standard(**common) elif model == 'spatial': param_start = self.init_param_spatial(groups=groups, cfree=cfree, **common) else: raise NotImplementedError('The model is not implemented!') # Get vector of parameters to start optimization theta_start = param_start.get_theta(restriction=restriction, use_target=use_target, cfree=cfree) if use_target: target = var_target else: target = None # Optimization options options = {'disp': False, 'maxiter': int(1e6)} if method == 'Nelder-Mead': options['maxfev'] = 3000 # Likelihood arguments kwargs = { 'model': model, 'target': target, 'cfree': cfree, 'restriction': restriction, 'groups': groups, 'cython': cython, 'use_penalty': use_penalty } # Likelihood function likelihood = partial(self.likelihood, **kwargs) # Run optimization if method == 'basin': opt_out = basinhopping(likelihood, theta_start, niter=100, disp=options['disp'], minimizer_kwargs={'method': 'Nelder-Mead'}) else: opt_out = minimize(likelihood, theta_start, method=method, options=options) # How much time did it take in minutes? time_delta = time.time() - time_start # Store optimal parameters in the corresponding class if model == 'standard': param_final = ParamStandard.from_theta(theta=opt_out.x, restriction=restriction, target=target, nstocks=nstocks) elif model == 'spatial': param_final = ParamSpatial.from_theta(theta=opt_out.x, restriction=restriction, target=target, cfree=cfree, groups=groups) else: raise NotImplementedError('The model is not implemented!') return BEKKResults(innov=self.innov, hvar=self.hvar, cython=cython, var_target=var_target, model=model, method=method, use_target=use_target, cfree=cfree, restriction=restriction, param_start=param_start, param_final=param_final, time_delta=time_delta, opt_out=opt_out)
def estimate(self, param_start=None, restriction='scalar', cfree=False, use_target=False, model='standard', groups=None, method='SLSQP', cython=True, use_penalty=False): """Estimate parameters of the BEKK model. Parameters ---------- param_start : ParamStandard or ParamSpatial instance Starting parameters. See Notes for more details. model : str Specific model to estimate. Must be - 'standard' - 'spatial' restriction : str Restriction on parameters. Must be - 'full' - 'diagonal' - 'group' (only applicable with 'spatial' model) - 'scalar' use_target : bool Whether to use variance targeting (True) or not (False) cfree : bool Whether to leave C matrix free (True) or not (False) groups : list of lists of tuples Encoded groups of items method : str Optimization method. See scipy.optimize.minimize cython : bool Whether to use Cython optimizations (True) or not (False) use_penalty : bool Whether to include penalty term in the likelihood Returns ------- BEKKResults instance Estimation results object Notes ----- If no param_start is given, the program will estimate parameters in the order 'from simple to more complicated' (from scalar to diagonal to full) while always using variance targeting. """ # Start timer for the whole optimization time_start = time.time() # Check for incompatible inputs if use_target and cfree: raise ValueError('use_target and cfree are incompatible!') # if (groups is not None) and (model != 'spatial'): # raise ValueError('The model is incompatible with weights!') # Update default settings nobs, nstocks = self.innov.shape var_target = estimate_uvar(self.innov) self.hvar = np.zeros((nobs, nstocks, nstocks), dtype=float) self.hvar[0] = var_target.copy() # Check for existence of initial guess among arguments. # Otherwise, initialize. if param_start is None: common = {'restriction': restriction, 'method': method, 'use_penalty': use_penalty, 'use_target': use_target} if model == 'standard': param_start = self.init_param_standard(**common) elif model == 'spatial': param_start = self.init_param_spatial(groups=groups, cfree=cfree, **common) else: raise NotImplementedError('The model is not implemented!') # Get vector of parameters to start optimization theta_start = param_start.get_theta(restriction=restriction, use_target=use_target, cfree=cfree) if use_target: target = var_target else: target = None # Optimization options options = {'disp': False, 'maxiter': int(1e6)} if method == 'Nelder-Mead': options['maxfev'] = 3000 # Likelihood arguments kwargs = {'model': model, 'target': target, 'cfree': cfree, 'restriction': restriction, 'groups': groups, 'cython': cython, 'use_penalty': use_penalty} # Likelihood function likelihood = partial(self.likelihood, **kwargs) # Run optimization if method == 'basin': opt_out = basinhopping(likelihood, theta_start, niter=100, disp=options['disp'], minimizer_kwargs={'method': 'Nelder-Mead'}) else: opt_out = minimize(likelihood, theta_start, method=method, options=options) # How much time did it take in minutes? time_delta = time.time() - time_start # Store optimal parameters in the corresponding class if model == 'standard': param_final = ParamStandard.from_theta(theta=opt_out.x, restriction=restriction, target=target, nstocks=nstocks) elif model == 'spatial': param_final = ParamSpatial.from_theta(theta=opt_out.x, restriction=restriction, target=target, cfree=cfree, groups=groups) else: raise NotImplementedError('The model is not implemented!') return BEKKResults(innov=self.innov, hvar=self.hvar, cython=cython, var_target=var_target, model=model, method=method, use_target=use_target, cfree=cfree, restriction=restriction, param_start=param_start, param_final=param_final, time_delta=time_delta, opt_out=opt_out)