Examples / PANELCAUSE.RPF |
PANELCAUSE.RPF is an example of a test for (Granger) causality in a panel data set allowing for heterogeneity in the coefficients and variances. It does both a joint test and tests at the individual level. This type of test is appropriate when the T dimension is relatively large (and the N dimension isn't), which would typically be the case with (for instance) macroeconomic data for multiple countries.
In a two variable situation, the null is that x fails to Granger cause y for all individuals, that is, that lags of x are zero in a regression of y on lags of y and lags of x. The alternative is that at least some of those lags are non-zero for some individuals. Note that it is quite possible to accept non-causality (that is, fail to reject) for every single individual and yet reject non-causality in the joint test—one of the reasons for doing panel data is to give better inference by combining information across individuals.
This is covered in greater detail as part of the Panel/Grouped Data e-course.
The program (which uses the data set from Mark and Sul(2003)) does tests for growth in real money (the DM series) causing growth in real income (the DY series). To adapt to different data, change the following to create labels (for output) for the individuals in your data set:
dec vect[strings] countries(%panelsize())
input countries
Austria
Belgium
...
Reset the number of lags:
*
* Number of lags
*
compute p=3
This uses INQUIRE with REGLIST to get a SMPL series (called FULLSMPL) to use for the common range of the restricted and unrestricted regressions (based upon the variables and lags from the unrestricted regression). It doesn't matter with this data set (as both series are defined over the same set of entries), but will if the variable being excluded is missing some extra observations. Change the DY and DM to match the ones you're using.
inquire(valid=fullsmpl,reglist)
# dy{0 to p} dm{0 to p}
Change the DY and DM in these to match your two series (this is for DM causing DY). This uses SWEEP to do unrestricted (first) and restricted (second) regressions with observations grouped on the individual, with heterogeneous variances. The two log likelihoods are used to make a likelihood ratio test for the restriction.
sweep(group=%indiv(t),smpl=fullsmpl,var=hetero)
# dy
# constant dy{1 to p} dm{1 to p}
sweep(group=%indiv(t),var=hetero)
# dy
# constant dy{1 to p}
Inside a loop, this does the individual causality tests using EXCLUDE, then transforms the usual F statistic to the equivalent likelihood ratio statistic. The individual log likelihood ratios sum to the joint test. (We don't have to worry about the sample here because we only run the unrestricted regression and use a Wald test, rather than doing separate restricted and unrestricted regressions). Again, change the DY and DM's to match the series that you are using.
linreg(noprint,smpl=%indiv(t)==i) dy
# constant dy{1 to p} dm{1 to p}
exclude(noprint)
# dm{1 to p}
compute lr=log((1+p*%cdstat/%ndf))*%nobs
Full Program
cal(panelobs=40)
open data panelmoney.xls
data(org=obs,format=xls) 1//1 19//40 realm realy
dec vect[strings] countries(%panelsize())
input countries
Austria
Belgium
Denmark
Finland
France
Germany
Iceland
Ireland
Netherlands
Norway
Portugal
Spain
Switzerland
UK
Japan
Australia
New Zealand
Canada
USA
*
* Number of lags
*
compute p=3
*
set dy = realy-realy{1}
set dm = realm-realm{1}
*
* Joint test.
*
* This gets a SMPL to use for the common range of the restricted
* and unrestricted regressions (based upon the variables and lags
* from the unrestricted regression). It doesn't matter in this case
* (as both series are defined over the same set of entries), but
* will if the variable being excluded is missing some extra
* observations.
*
inquire(valid=fullsmpl,reglist)
# dy{0 to p} dm{0 to p}
*
sweep(group=%indiv(t),smpl=fullsmpl,var=hetero)
# dy
# constant dy{1 to p} dm{1 to p}
compute loglunr=%logl,nregunr=%nregsystem
sweep(group=%indiv(t),smpl=fullsmpl,var=hetero)
# dy
# constant dy{1 to p}
compute loglres=%logl,nregres=%nregsystem
cdf(title="Heterogeneous Panel Causality Test") chisqr $
2.0*(loglunr-loglres) nregunr-nregres
compute jointtest=%cdstat,jointsignif=%signif
*
* Individual causality tests. The individual log likelihood ratios
* sum to the joint test. (We don't have to worry about the sample
* here because we *only* run the unrestricted regression and use a
* Wald test, rather than doing separate restricted and unrestricted
* regressions).
*
report(action=define,title="Panel Causality Test")
do i=1,%panelsize()
linreg(noprint,smpl=%indiv(t)==i) dy
# constant dy{1 to p} dm{1 to p}
exclude(noprint)
# dm{1 to p}
compute lr=log((1+p*%cdstat/%ndf))*%nobs
report(row=new,atcol=1) countries(i) lr %chisqr(lr,p)
end do i
report(row=new,atcol=1) "OVERALL" jointtest jointsignif
report(atcol=2,tocol=2,action=format,picture="*.###")
report(atcol=3,tocol=3,action=format,picture="*.#####")
report(action=show)
Output
Heterogeneous Panel Causality Test
Chi-Squared(57)= 202.357431 with Significance Level 0.00000000
Austria 6.142 0.10488
Belgium 16.859 0.00076
Denmark 8.136 0.04327
Finland 13.771 0.00323
France 9.121 0.02772
Germany 1.806 0.61368
Iceland 35.762 0.00000
Ireland 12.283 0.00647
Netherlands 3.896 0.27290
Norway 23.017 0.00004
Portugal 6.063 0.10858
Spain 7.043 0.07055
Switzerland 7.288 0.06325
UK 7.980 0.04642
Japan 7.263 0.06396
Australia 11.205 0.01067
New Zealand 14.521 0.00227
Canada 8.234 0.04142
USA 1.965 0.57966
OVERALL 202.357 0.00000
Copyright © 2025 Thomas A. Doan