function optimal_bandwidth = mh_optimal_bandwidth(data,number_of_draws,bandwidth,kernel_function) % This function gives the optimal bandwidth parameter of a kernel estimator % used to estimate a posterior univariate density from realisations of a % Metropolis-Hastings algorithm. % % INPUTS: % data [double] Vector (number_of_draws*1) of draws. % number_of_draws [integer] Scalar, number of draws. % bandwidth [integer] Scalar equal to 0,-1 or -2. % bandwidth = 0 => Silverman [1986] rule of thumb. % bandwidth = -1 => Sheather and Jones [1991]. % bandwidth = -2 => Local bandwith parameters. % kernel_function [string] Name of the kernel function: 'gaussian', 'triweight', % 'uniform', 'triangle', 'epanechnikov', 'quartic', % 'triweight' and 'cosinus' % % OUTPUTS: % optimal_bandwidth: [double] Scalar or vector, optimal window width. % % SPECIAL REQUIREMENTS: % none. % % REFERENCES: % [1] M. Skoeld and G.O. Roberts [2003], "Density estimation for the Metropolis-Hastings algorithm". % [2] Silverman [1986], "Density estimation for statistics and data analysis". % Copyright © 2004-2017 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 . % Kernel specifications. if strcmpi(kernel_function,'gaussian') % Kernel definition k = @(x)inv(sqrt(2*pi))*exp(-0.5*x.^2); % Second derivate of the kernel function k2 = @(x)inv(sqrt(2*pi))*(-exp(-0.5*x.^2)+(x.^2).*exp(-0.5*x.^2)); % Fourth derivate of the kernel function k4 = @(x)inv(sqrt(2*pi))*(3*exp(-0.5*x.^2)-6*(x.^2).*exp(-0.5*x.^2)+(x.^4).*exp(-0.5*x.^2)); % Sixth derivate of the kernel function k6 = @(x)inv(sqrt(2*pi))*(-15*exp(-0.5*x.^2)+45*(x.^2).*exp(-0.5*x.^2)-15*(x.^4).*exp(-0.5*x.^2)+(x.^6).*exp(-0.5*x.^2)); mu02 = inv(2*sqrt(pi)); mu21 = 1; elseif strcmpi(kernel_function,'uniform') k = @(x)0.5*(abs(x) <= 1); mu02 = 0.5; mu21 = 1/3; elseif strcmpi(kernel_function,'triangle') k = @(x)(1-abs(x)).*(abs(x) <= 1); mu02 = 2/3; mu21 = 1/6; elseif strcmpi(kernel_function,'epanechnikov') k = @(x)0.75*(1-x.^2).*(abs(x) <= 1); mu02 = 3/5; mu21 = 1/5; elseif strcmpi(kernel_function,'quartic') k = @(x)0.9375*((1-x.^2).^2).*(abs(x) <= 1); mu02 = 15/21; mu21 = 1/7; elseif strcmpi(kernel_function,'triweight') k = @(x)1.09375*((1-x.^2).^3).*(abs(x) <= 1); k2 = @(x)(105/4*(1-x.^2).*x.^2-105/16*(1-x.^2).^2).*(abs(x) <= 1); k4 = @(x)(-1575/4*x.^2+315/4).*(abs(x) <= 1); k6 = @(x)(-1575/2).*(abs(x) <= 1); mu02 = 350/429; mu21 = 1/9; elseif strcmpi(kernel_function,'cosinus') k = @(x)(pi/4)*cos((pi/2)*x).*(abs(x) <= 1); k2 = @(x)(-1/16*cos(pi*x/2)*pi^3).*(abs(x) <= 1); k4 = @(x)(1/64*cos(pi*x/2)*pi^5).*(abs(x) <= 1); k6 = @(x)(-1/256*cos(pi*x/2)*pi^7).*(abs(x) <= 1); mu02 = (pi^2)/16; mu21 = (pi^2-8)/pi^2; else disp('mh_optimal_bandwidth:: '); error('This kernel function is not yet implemented in Dynare!'); end % Get the Skold and Roberts' correction. if bandwidth==0 || bandwidth==-1 correction = correction_for_repeated_draws(data,number_of_draws); else correction = 0; end % Compute the standard deviation of the draws. sigma = std(data); % Optimal bandwidth parameter. if bandwidth == 0 % Rule of thumb bandwidth parameter (Silverman [1986]. h = 2*sigma*(sqrt(pi)*mu02/(12*(mu21^2)*number_of_draws))^(1/5); h = h*correction^(1/5); elseif bandwidth == -1 % Sheather and Jones [1991] plug-in estimation of the optimal bandwidth parameter. if strcmp(kernel_function,'uniform') || ... strcmp(kernel_function,'triangle') || ... strcmp(kernel_function,'epanechnikov') || ... strcmp(kernel_function,'quartic') error(['I can''t compute the optimal bandwidth with this kernel...' ... 'Try the gaussian, triweight or cosinus kernels.']); end Itilda4 = 8*7*6*5/(((2*sigma)^9)*sqrt(pi)); g3 = abs(2*correction*k6(0)/(mu21*Itilda4*number_of_draws))^(1/9); Ihat3 = 0; for i=1:number_of_draws Ihat3 = Ihat3 + sum(k6((data(i,1)-data)/g3)); end Ihat3 = - Ihat3/((number_of_draws^2)*g3^7); g2 = abs(2*correction*k4(0)/(mu21*Ihat3*number_of_draws))^(1/7); Ihat2 = 0; for i=1:number_of_draws Ihat2 = Ihat2 + sum(k4((data(i)-data)/g2)); end Ihat2 = Ihat2/((number_of_draws^2)*g2^5); h = (correction*mu02/(number_of_draws*Ihat2*mu21^2))^(1/5); % equation (22) in Skold and Roberts [2003]. elseif bandwidth == -2 % Bump killing... I compute local bandwith parameters in order to remove % spurious bumps introduced by long rejecting periods. if strcmp(kernel_function,'uniform') || ... strcmp(kernel_function,'triangle') || ... strcmp(kernel_function,'epanechnikov') || ... strcmp(kernel_function,'quartic') error(['I can''t compute the optimal bandwidth with this kernel...' ... 'Try the gaussian, triweight or cosinus kernels.']); end T = zeros(number_of_draws, 1); for i=1:number_of_draws j = i; while j<=number_of_draws && (data(j,1)-data(i,1))<2*eps j = j+1; end T(i) = (j-i); correction = correction + 2*T(i) - 1; end correction = correction/number_of_draws; Itilda4 = 8*7*6*5/(((2*sigma)^9)*sqrt(pi)); g3 = abs(2*correction*k6(0)/(mu21*Itilda4*number_of_draws))^(1/9); Ihat3 = 0; for i=1:number_of_draws Ihat3 = Ihat3 + sum(k6((data(i,1)-data)/g3)); end Ihat3 = -Ihat3/((n^2)*g3^7); g2 = abs(2*correction*k4(0)/(mu21*Ihat3*number_of_draws))^(1/7); Ihat2 = 0; for i=1:number_of_draws Ihat2 = Ihat2 + sum(k4((data(i)-data)/g2)); end Ihat2 = Ihat2/((number_of_draws^2)*g2^5); h = ((2*T-1)*mu02/(number_of_draws*Ihat2*mu21^2)).^(1/5); % h is a column vector (local banwidth parameters). else disp('mh_optimal_bandwidth:: '); error('Parameter bandwidth must be equal to 0, -1 or -2.'); end optimal_bandwidth = h; return function correction = correction_for_repeated_draws(draws,n) correction = 0; for i=1:n j = i; while j<=n && ( draws(j,1) - draws(i,1) )<2*eps j = j+1; end correction = correction + 2*(j-i) - 1; end correction = correction/n;