Skip to content

Commit b66adcf

Browse files
authored
Merge pull request #53 from marcom/willmott-index
Add Willmott index of agreement
2 parents 663477d + d50f3c6 commit b66adcf

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

src/continuous.jl

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,3 +545,55 @@ RSquared
545545
const rsq = RSquared()
546546
"$RSquaredDoc"
547547
const rsquared = rsq
548+
549+
# -------------------------------------------------------------------------
550+
# Willmott index of agreement (d)
551+
552+
# type for measure without argument checks:
553+
struct _WillmottD end
554+
555+
function (::_WillmottD)(yhat, y)
556+
μ = aggregate(y) # mean
557+
# numerator: Σ_i (ŷ_i - y_i)^2
558+
num = LPSumLoss(p=2)(yhat, y)
559+
# denominator: Σ_i (|ŷ_i - μ| + |y_i - μ|)^2
560+
den = multimeasure((yhat, y) -> (abs(yhat - μ) + abs(y - μ))^2; mode=Sum())(yhat, y)
561+
return den == 0 ? (num == 0 ? 1.0 : 0.0) : 1 - num/den
562+
end
563+
564+
WillmottD() = _WillmottD() |> API.robust_measure |> API.fussy_measure
565+
const WillmottDType = API.FussyMeasure{<:API.RobustMeasure{<:_WillmottD}}
566+
567+
@trait(
568+
_WillmottD,
569+
consumes_multiple_observations = true,
570+
kind_of_proxy = LearnAPI.Point(),
571+
observation_scitype = Union{Missing,Infinite},
572+
orientation = Score(),
573+
human_name = "Willmott index of agreement (d)",
574+
)
575+
576+
@fix_show WillmottD::WillmottDType
577+
578+
register(WillmottD, "willmott_d")
579+
580+
const WillmottDDoc = docstring(
581+
"WillmottD()",
582+
scitype=DOC_INFINITE,
583+
body=
584+
"""
585+
Returns Willmott index of agreement (d)
586+
587+
``d = 1 - \\dfrac{\\sum (ŷ_i - y_i)^2}{\\sum (|ŷ_i - \\bar y| + |y_i - \\bar y|)^2}``,
588+
589+
where ``\\bar y`` is the mean of the targets. The value lies in ``[0,1]`` with higher
590+
being better.
591+
592+
References: Willmott [(1981)](https://doi.org/10.1080/02723646.1981.10642213)
593+
""",
594+
)
595+
596+
"$WillmottDDoc"
597+
WillmottD
598+
"$WillmottDDoc"
599+
const willmott_d = WillmottD()

test/continuous.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ rng = srng(666899)
3131
yhat = rand(rng, 4)
3232
@test isapprox(log_cosh(yhat, y), mean(log.(cosh.(yhat - y))))
3333
@test rsq(yhat, y) == 1 - sum((yhat - y).^2)/sum((y .- mean(y)).^2)
34+
let
35+
num = sum((yhat - y).^2)
36+
den = sum((abs.(yhat .- mean(y)) .+ abs.(y .- mean(y))).^2)
37+
@test isapprox(willmott_d(yhat, y), den == 0 ? (num == 0 ? 1.0 : 0.0) : 1 - num/den)
38+
# additional tests for willmott_d
39+
@test willmott_d(yhat, yhat) == 1
40+
@test willmott_d(y, y) == 1
41+
@test willmott_d(yhat .+ 1, zeros(length(yhat))) == 0 # yhat .+ 1 ensures it's not all zeros
42+
@test willmott_d(zeros(4), zeros(4)) == 1
43+
end
3444

3545
# a multi-target test where there is a parameter:
3646
y = rand(rng, 2, 10)

0 commit comments

Comments
 (0)