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
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