ols: further simplifications

time-shift
Houtan Bastani 2019-01-11 11:26:13 +01:00
parent a35fd291c5
commit a477075825
No known key found for this signature in database
GPG Key ID: 000094FB955BE169
4 changed files with 147 additions and 58 deletions

View File

@ -1,15 +1,19 @@
function [X, Y, startdates, enddates, startidxs, residnames, pbeta, vars, surpidxs, surconstrainedparams] = pooled_sur_common(ds, jsonmodel)
%function [X, Y, startdates, enddates, startidxs, residnames, pbeta, vars, surpidxs, surconstrainedparams] = pooled_sur_common(ds, jsonmodel)
function [Y, lhssub, X, startdates, enddates, startidxs, residnames, pbeta, vars, surpidxs, surconestrainedparams] = common_parsing(ds, ast, jsonmodel, overlapping_dates)
%function [Y, lhssub, X, startdates, enddates, startidxs, residnames, pbeta, vars, surpidxs, surconstrainedparams] = common_parsing(ds, ast, jsonmodel, overlapping_dates)
%
% Code common to sur.m and pooled_ols.m
%
% INPUTS
% ds [dseries] dataset
% ast [cell array] JSON representation of abstract syntax tree
% jsonmodel [cell array] JSON representation of model block
% overlapping_dates [boolean] if true, dates are same across
% equations
%
% OUTPUTS
% X [matrix] regressors
% Y [vector] dependent variables
% Y [cell array] dependent variables
% lhssub [cell array] RHS to subtract from Y
% X [cell array] regressors
% startdates [cell array] first observed period for each
% equation
% enddates [cell array] last observed period for each
@ -29,7 +33,7 @@ function [X, Y, startdates, enddates, startidxs, residnames, pbeta, vars, surpid
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2017-2018 Dynare Team
% Copyright (C) 2019 Dynare Team
%
% This file is part of Dynare.
%
@ -46,7 +50,43 @@ function [X, Y, startdates, enddates, startidxs, residnames, pbeta, vars, surpid
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
global M_
%% Initialize variables
Y = cell(length(ast), 1);
lhssub = cell(length(ast), 1);
X = cell(length(ast), 1);
startdates = cell(length(ast), 1);
enddates = cell(length(ast), 1);
%% Loop over equations
neqs = length(ast);
for i = 1:neqs
%% Parse equation i
[Y{i}, lhssub{i}, X{i}] = parse_ols_style_equation(ds, ast{i}, jsonmodel{i}.line);
%% Set start and end dates
if overlapping_dates
[startdates{i}, enddates{i}] = get_ols_start_end_dates(Y{i}, lhssub{i}, X{i}, jsonmodel{i});
end
end
if overlapping_dates
maxfp = max([startdates{:}]);
minlp = min([enddates{:}]);
for i = 1:neqs
Y{i} = Y{i}(maxfp:minlp);
X{i} = X{i}(maxfp:minlp);
if ~isempty(lhssub{i})
lhssub{i} = lhssub{i}(maxfp:minlp);
end
end
end
return
%%
M_endo_exo_names_trim = [M_.endo_names; M_.exo_names];
[junk, idxs] = sort(cellfun(@length, M_endo_exo_names_trim), 'descend');

View File

@ -41,7 +41,7 @@ function varargout = dyn_ols(ds, fitted_names_dict, eqtags)
global M_ oo_ options_
assert(nargin >= 1 && nargin <= 3, 'dyn_ols: takes between 1 and 3 arguments');
assert(nargin >= 1 && nargin <= 3, 'dyn_ols() takes between 1 and 3 arguments');
assert(~isempty(ds) && isdseries(ds), 'dyn_ols: the first argument must be a dseries');
jsonfile = [M_.fname filesep() 'model' filesep() 'json' filesep() 'modfile-original.json'];
@ -77,54 +77,21 @@ if strcmp(st(1).name, 'olsgibbs')
assert(length(ast) == 1);
end
%% Parse equations
[Y, lhssub, X, fp, lp ] = common_parsing(ds, ast, jsonmodel, true);
%% Loop over equations
for i = 1:length(ast)
%% Parse equation i
[Y, lhssub, X] = parse_ols_style_equation(ds, ast{i}, jsonmodel{i}.line);
%% Set dates
fp = max(Y.firstobservedperiod, X.firstobservedperiod);
lp = min(Y.lastobservedperiod, X.lastobservedperiod);
if ~isempty(lhssub)
fp = max(fp, lhssub.firstobservedperiod);
lp = min(lp, lhssub.lastobservedperiod);
end
if isfield(jsonmodel{i}, 'tags') ...
&& isfield(jsonmodel{i}.tags, 'sample') ...
&& ~isempty(jsonmodel{i}.tags.sample)
colon_idx = strfind(jsonmodel{i}.tags.sample, ':');
fsd = dates(jsonmodel{i}.tags.sample(1:colon_idx-1));
lsd = dates(jsonmodel{i}.tags.sample(colon_idx+1:end));
if fp > fsd
warning(['The sample over which you want to estimate contains NaNs. '...
'Adjusting estimation range to begin on: ' fp.char])
else
fp = fsd;
end
if lp < lsd
warning(['The sample over which you want to estimate contains NaNs. '...
'Adjusting estimation range to end on: ' lp.char])
else
lp = lsd;
end
end
Y = Y(fp:lp);
if ~isempty(lhssub)
lhssub = lhssub(fp:lp);
end
pnames = X.name;
X = X(fp:lp).data;
[nobs, nvars] = size(X);
for i = 1:length(Y)
pnames = X{i}.name;
[nobs, nvars] = size(X{i}.data);
if called_from_olsgibbs
varargout{1} = nobs;
varargout{2} = pnames;
varargout{3} = X;
varargout{4} = Y.data;
varargout{3} = X{i}.data;
varargout{4} = Y{i}.data;
varargout{5} = jsonmodel;
varargout{6} = fp;
varargout{7} = lp;
varargout{6} = fp{i};
varargout{7} = lp{i};
return
end
@ -140,9 +107,9 @@ for i = 1:length(ast)
oo_.ols.(tag).dof = nobs - nvars;
% Estimated Parameters
[q, r] = qr(X, 0);
[q, r] = qr(X{i}.data, 0);
xpxi = (r'*r)\eye(nvars);
oo_.ols.(tag).beta = r\(q'*Y.data);
oo_.ols.(tag).beta = r\(q'*Y{i}.data);
oo_.ols.(tag).param_idxs = zeros(length(pnames), 1);
for j = 1:length(pnames)
if ~strcmp(pnames{j}, 'intercept')
@ -160,14 +127,14 @@ for i = 1:length(ast)
yhatname = fitted_names_dict{idx, 2};
end
end
oo_.ols.(tag).Yhat = dseries(X*oo_.ols.(tag).beta, fp, yhatname);
oo_.ols.(tag).Yhat = dseries(X{i}.data*oo_.ols.(tag).beta, fp{i}, yhatname);
% Residuals
oo_.ols.(tag).resid = Y - oo_.ols.(tag).Yhat;
oo_.ols.(tag).resid = Y{i} - oo_.ols.(tag).Yhat;
% Correct Yhat reported back to user
Y = Y + lhssub;
oo_.ols.(tag).Yhat = oo_.ols.(tag).Yhat + lhssub;
Y{i} = Y{i} + lhssub{i};
oo_.ols.(tag).Yhat = oo_.ols.(tag).Yhat + lhssub{i};
% Apply correcting function for Yhat if it was passed
if any(idx) ...
@ -184,7 +151,7 @@ for i = 1:length(ast)
oo_.ols.(tag).s2 = SS_res/oo_.ols.(tag).dof;
% R^2
ym = Y.data - mean(Y);
ym = Y{i}.data - mean(Y{i});
SS_tot = ym'*ym;
oo_.ols.(tag).R2 = 1 - SS_res/SS_tot;
@ -211,7 +178,7 @@ for i = 1:length(ast)
preamble = {sprintf('Dependent Variable: %s', jsonmodel{i}.lhs), ...
sprintf('No. Independent Variables: %d', nvars), ...
sprintf('Observations: %d from %s to %s\n', nobs, fp.char, lp.char)};
sprintf('Observations: %d from %s to %s\n', nobs, fp{i}.char, lp{i}.char)};
afterward = {sprintf('R^2: %f', oo_.ols.(tag).R2), ...
sprintf('R^2 Adjusted: %f', oo_.ols.(tag).adjR2), ...

View File

@ -0,0 +1,52 @@
function [ast, jsonmodel] = get_ast_jsonmodel(eqtags)
% function [ast, jsonmodel] = get_ast_jsonmodel(eqtags)
% return AST and jsonmodel from json output of preprocessor for the given
% equation tags.
%
% INPUTS
% eqtags [cellstr] names of equation tags for which to get info.
% If empty, get all
%
% OUTPUTS
% ast [cell array] JSON representation of the abstract syntax tree
% jsonmodel [cell array] JSON representation of the model block
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2019 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
global M_
if ~isempty(eqtags) && ~(ischar(eqtags) || iscell(eqtags))
error('get_ast_jsonmodel: eqtags not passed correctly')
end
jsonfile = [M_.fname filesep() 'model' filesep() 'json' filesep() 'modfile-original.json'];
if exist(jsonfile, 'file') ~= 2
error('Could not find %s! Please use the json=compute option (See the Dynare invocation section in the reference manual).', jsonfile);
end
jsonmodel = loadjson(jsonfile);
ast = jsonmodel.abstract_syntax_tree;
jsonmodel = jsonmodel.model;
if ~isempty(eqtags)
ast = getEquationsByTags(ast, 'name', eqtags);
jsonmodel = getEquationsByTags(jsonmodel, 'name', eqtags);
end
end

View File

@ -0,0 +1,30 @@
function [fp, lp] = get_ols_start_end_dates(Y, lhssub, X, jsonmodel)
% function [fp, lp] = get_ols_start_end_dates(Y, lhssub, X, jsonmodel)
fp = max(Y.firstobservedperiod, X.firstobservedperiod);
lp = min(Y.lastobservedperiod, X.lastobservedperiod);
if ~isempty(lhssub)
fp = max(fp, lhssub.firstobservedperiod);
lp = min(lp, lhssub.lastobservedperiod);
end
if isfield(jsonmodel, 'tags') ...
&& isfield(jsonmodel.tags, 'sample') ...
&& ~isempty(jsonmodel.tags.sample)
colon_idx = strfind(jsonmodel.tags.sample, ':');
fsd = dates(jsonmodel.tags.sample(1:colon_idx-1));
lsd = dates(jsonmodel.tags.sample(colon_idx+1:end));
if fp > fsd
warning(['The sample over which you want to estimate contains NaNs. '...
'Adjusting estimation range to begin on: ' fp.char])
else
fp = fsd;
end
if lp < lsd
warning(['The sample over which you want to estimate contains NaNs. '...
'Adjusting estimation range to end on: ' lp.char])
else
lp = lsd;
end
end
end