Skip to content

Commit

Permalink
add White's test (heteroskedasticity)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulSoderlind committed May 26, 2020
1 parent d1ec83d commit 9b60be0
Show file tree
Hide file tree
Showing 4 changed files with 319 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/src/time_series.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ ADFTest
## Diebold-Mariano test
```@docs
DieboldMarianoTest
```

## White test
```@docs
WhiteTest
```
1 change: 1 addition & 0 deletions src/HypothesisTests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,6 @@ include("wald_wolfowitz.jl")
include("f.jl")
include("correlation.jl")
include("diebold_mariano.jl")
include("white.jl")

end
92 changes: 92 additions & 0 deletions src/white.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# white.jl
# White and Breusch-Pagan tests for heteroskedasticity
#
# Copyright (C) 2020 Paul Söderlind
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

export WhiteTest

struct WhiteTest <: HypothesisTest
dof::Int #degrees of freedom in test
LM::Float64 #test statistic, distributed as Chisq(dof)
end

"""
WhiteTest(X, e, TestType)
Compute White's (or Breusch-Pagan's) test for heteroskedasticity.
`X` is the matrix of regressors from the original model and `e` the vector of residuals.
`TestType` is either `:Linear` for the Breusch-Pagan test, `:LinearAndSquares` for
White's test with linear and squared terms only (no cross-products), or `:White` (the default)
for the full White's test (linear, squared and cross-product terms). `X` should include a
constant. The rest statistic is T*R2 where R2 is from the regression of `e^2` on the terms
mentioned above. Under the null hypothesis it is distributed as `Chisquare(dof)`
where `dof` is the number of independent terms (not counting the constant).
Implements: [`pvalue`](@ref)
# References
* H. White, (1980): A heteroskedasticity-consistent covariance matrix estimator and a direct test for heteroskedasticity, Econometrica, 48, 817-838.
* T.S. Breusch & A.R. Pagan (1979), A simple test for heteroscedasticity and random coefficient variation, Econometrica, 47, 1287-1294
# External links
* [White's test on Wikipedia](https://en.wikipedia.org/wiki/White_test)
"""
function WhiteTest(X::AbstractVecOrMat{<:Real}, e::AbstractVector{<:Real}, TestType=:White)
(n,K) = (size(X,1),size(X,2)) #nobs,nvars

n == length(e) || throw(DimensionMismatch("inputs must have the same length"))

if TestType == :Linear
z = X
elseif TestType == :LinearAndSquares
z = [X X.^2]
else #linear, squares and cross-products
z = fill(NaN,n,round(Int,K*(K+1)/2)) #loop is easier and quicker than index tricks
vv = 1
for i = 1:K, j = i:K
z[:,vv] = X[:,i].*X[:,j] #eg. x1*x1, x1*x2, x2*x2
vv = vv + 1
end
end

dof = rank(z) - 1 #number of independent regressors in z
e2 = e.^2
b = z\e2
res = e2 - z*b
R2 = 1 - var(res)/var(e2)
LM = n*R2 #n*R2 in original papers, could also use n*R2/(1-R2)
return WhiteTest(dof, LM)
end

testname(t::WhiteTest) = "White's test for heteroskedasticity"
population_param_of_interest(t::WhiteTest) = ("T*R2", 0, t.LM)
default_tail(test::WhiteTest) = :right

function show_params(io::IO, t::WhiteTest, ident)
println(io, ident, "T*R^2 statistic: ", t.LM)
println(io, ident, "degrees of freedom: ", dof(t))
end

StatsBase.dof(t::WhiteTest) = t.dof
pvalue(t::WhiteTest) = pvalue(Chisq(t.dof), t.LM, tail=:right)

221 changes: 221 additions & 0 deletions test/white.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
using HypothesisTests, Test

@testset "White tests" begin

X = [ 4.18 0.77 1.00;
-3.41 0.73 1.00;
5.75 0.81 1.00;
0.05 0.80 1.00;
-2.18 0.82 1.00;
3.88 0.81 1.00;
0.73 0.77 1.00;
5.70 0.77 1.00;
-0.69 0.83 1.00;
-8.14 0.87 1.00;
5.37 0.99 1.00;
1.87 0.95 1.00;
5.76 0.80 1.00;
-0.79 0.89 1.00;
-13.23 1.21 1.00;
3.97 1.26 1.00;
5.20 0.81 1.00;
3.16 0.61 1.00;
6.41 0.53 1.00;
1.72 0.64 1.00;
2.20 0.75 1.00;
1.06 0.95 1.00;
9.54 0.96 1.00;
-4.75 1.31 1.00;
-5.05 1.04 1.00;
0.48 1.07 1.00;
3.41 1.21 1.00;
-2.21 1.08 1.00;
0.21 1.15 1.00;
-2.37 1.35 1.00;
-1.55 1.24 1.00;
-6.91 1.28 1.00;
-7.62 1.24 1.00;
4.81 1.21 1.00;
3.51 1.07 1.00;
-3.68 0.87 1.00;
-3.42 0.80 1.00;
-6.03 0.92 1.00;
-1.99 0.98 1.00;
3.20 1.13 1.00;
-3.88 1.06 1.00;
-3.35 0.96 1.00;
-3.10 1.05 1.00;
11.14 0.76 1.00;
1.17 0.51 1.00;
11.27 0.59 1.00;
4.56 0.63 1.00;
0.78 0.67 1.00;
3.50 0.69 1.00;
2.40 0.62 1.00;
2.84 0.63 1.00;
6.71 0.71 1.00;
0.63 0.69 1.00;
3.11 0.67 1.00;
-3.90 0.74 1.00;
-0.41 0.76 1.00;
0.85 0.76 1.00;
-3.56 0.76 1.00;
2.26 0.70 1.00;
-1.78 0.73 1.00;
-2.06 0.76 1.00;
-4.62 0.71 1.00;
0.61 0.73 1.00;
-0.56 0.81 1.00;
-6.01 0.78 1.00;
1.59 0.75 1.00;
-2.88 0.82 1.00;
10.44 0.83 1.00;
-0.82 0.86 1.00;
-1.01 1.00 1.00;
-1.80 0.73 1.00;
1.73 0.64 1.00;
7.92 0.65 1.00;
1.11 0.58 1.00;
-0.79 0.62 1.00;
-0.94 0.72 1.00;
4.92 0.66 1.00;
1.16 0.55 1.00;
-0.65 0.62 1.00;
-1.03 0.55 1.00;
-4.58 0.60 1.00;
3.79 0.65 1.00;
6.31 0.61 1.00;
3.66 0.65 1.00;
0.42 0.56 1.00;
6.72 0.53 1.00;
4.79 0.60 1.00;
-1.31 0.52 1.00;
4.59 0.49 1.00;
0.90 0.52 1.00;
-6.49 0.52 1.00;
6.16 0.46 1.00;
-8.35 0.45 1.00;
4.47 0.46 1.00;
1.12 0.39 1.00;
-3.13 0.49 1.00;
12.43 0.42 1.00;
4.36 0.43 1.00;
1.90 0.47 1.00;
-2.14 0.44 1.00 ]

e = [ 5.19346;
2.22296;
3.82622;
2.93541;
0.70453;
1.98955;
0.56655;
1.54306;
0.57363;
-0.13346;
1.68565;
9.24558;
7.39317;
2.45484;
-4.83724;
-0.74742;
-0.22633;
0.51537;
2.82822;
9.35943;
5.38263;
6.59691;
1.79080;
0.54506;
4.06661;
-4.18808;
1.69414;
5.40963;
2.92762;
-2.67351;
-2.74613;
-3.52752;
-4.27775;
2.88245;
-8.12566;
0.08760;
2.20495;
-0.45509;
-0.06959;
1.51330;
1.37878;
-2.33046;
0.35730;
-11.41189;
-0.48083;
1.08917;
2.52333;
1.73218;
15.60426;
-0.15961;
-0.22174;
-1.19174;
13.92022;
1.16044;
0.08087;
-5.81547;
-5.14199;
-5.69918;
-0.36585;
-3.70294;
2.83687;
-1.37631;
-2.55403;
-4.10796;
1.32092;
-1.64056;
-4.09963;
-4.85728;
-1.45496;
-3.12612;
-4.36648;
-3.23379;
5.22893;
5.06730;
-0.63041;
-1.70377;
-5.71335;
-2.76831;
2.20443;
-0.10174;
-2.36727;
-5.49859;
-4.78093;
-3.36665;
5.12027;
-3.03180;
-2.52035;
3.10913;
-3.51388;
-0.70389;
-1.01963;
-8.78989;
2.95170;
-3.95464;
-4.01258;
-1.92315;
-4.94209;
5.29138;
1.28435;
0.28832 ]

atol = 1e-4
w_test = WhiteTest(X, e, :Linear)
@test pvalue(w_test) 0.1287 atol=atol

w_test = WhiteTest(X, e, :LinearAndSquares)
@test pvalue(w_test) 0.2774 atol=atol

w_test = WhiteTest(X, e)
@test pvalue(w_test) 0.3458 atol=atol

show(IOBuffer(), w_test)

@test_throws DimensionMismatch WhiteTest(rand(3), rand(4))

end

0 comments on commit 9b60be0

Please sign in to comment.