Skip to content

Commit b33e5d8

Browse files
authored
Merge pull request #153 from nannau/feature/exact-values-option
Feature: exact values option
2 parents a067eb1 + f1dda1e commit b33e5d8

File tree

7 files changed

+343
-50
lines changed

7 files changed

+343
-50
lines changed

examples/exact_values_example_1D.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Exact Values
4+
=================
5+
6+
PyKrige demonstration and usage
7+
as a non-exact interpolator in 1D.
8+
"""
9+
10+
from pykrige.ok import OrdinaryKriging
11+
import matplotlib.pyplot as plt
12+
import numpy as np
13+
14+
plt.style.use("ggplot")
15+
16+
np.random.seed(42)
17+
18+
x = np.linspace(0, 12.5, 50)
19+
xpred = np.linspace(0, 12.5, 393)
20+
y = np.sin(x) * np.exp(-0.25 * x) + np.random.normal(-0.25, 0.25, 50)
21+
22+
# compare OrdinaryKriging as an exact and non exact interpolator
23+
uk = OrdinaryKriging(
24+
x, np.zeros(x.shape), y, variogram_model="linear", exact_values=False
25+
)
26+
uk_exact = OrdinaryKriging(x, np.zeros(x.shape), y, variogram_model="linear")
27+
28+
y_pred, y_std = uk.execute("grid", xpred, np.array([0.0]), backend="loop")
29+
y_pred_exact, y_std_exact = uk_exact.execute(
30+
"grid", xpred, np.array([0.0]), backend="loop"
31+
)
32+
33+
34+
y_pred = np.squeeze(y_pred)
35+
y_std = np.squeeze(y_std)
36+
37+
y_pred_exact = np.squeeze(y_pred_exact)
38+
y_std_exact = np.squeeze(y_std_exact)
39+
40+
41+
fig, ax = plt.subplots(1, 1, figsize=(10, 4))
42+
43+
ax.scatter(x, y, label="Input Data")
44+
ax.plot(xpred, y_pred_exact, label="Exact Prediction")
45+
ax.plot(xpred, y_pred, label="Non Exact Prediction")
46+
47+
ax.fill_between(
48+
xpred,
49+
y_pred - 3 * y_std,
50+
y_pred + 3 * y_std,
51+
alpha=0.3,
52+
label="Confidence interval",
53+
)
54+
ax.legend(loc=9)
55+
ax.set_ylim(-1.8, 1.3)
56+
ax.legend(loc=9)
57+
plt.xlabel("X")
58+
plt.ylabel("Field")
59+
plt.show()

pykrige/lib/cok.pyx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ cpdef _c_exec_loop(double [:, ::1] a_all,
4848
b[k] *= -1
4949
b[n] = 1.0
5050

51-
check_b_vect(n, bd, b, eps)
51+
if not pars['exact_values']:
52+
check_b_vect(n, bd, b, eps)
5253

5354

5455
# Do the BLAS matrix-vector multiplication call

pykrige/ok.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
----------
1616
.. [1] P.K. Kitanidis, Introduction to Geostatistcs: Applications in
1717
Hydrogeology, (Cambridge University Press, 1997) 272 p.
18+
.. [2] N. Cressie, Statistics for spatial data,
19+
(Wiley Series in Probability and Statistics, 1993) 137 p.
1820
1921
Copyright (c) 2015-2020, PyKrige Developers
2022
"""
@@ -140,11 +142,21 @@ class OrdinaryKriging:
140142
coordinates, x is interpreted as longitude and y as latitude
141143
coordinates, both given in degree. Longitudes are expected in
142144
[0, 360] and latitudes in [-90, 90]. Default is 'euclidean'.
145+
exact_values : bool, optional
146+
If True, interpolation provides input values at input locations.
147+
If False, interpolation accounts for variance/nugget within input
148+
values at input locations and does not behave as an
149+
exact-interpolator [2]. Note that this only has an effect if
150+
there is variance/nugget present within the input data since it is
151+
interpreted as measurement error. If the nugget is zero, the kriged
152+
field will behave as an exact interpolator.
143153
144154
References
145155
----------
146156
.. [1] P.K. Kitanidis, Introduction to Geostatistcs: Applications in
147157
Hydrogeology, (Cambridge University Press, 1997) 272 p.
158+
.. [2] N. Cressie, Statistics for spatial data,
159+
(Wiley Series in Probability and Statistics, 1993) 137 p.
148160
"""
149161

150162
eps = 1.0e-10 # Cutoff for comparison to zero
@@ -173,11 +185,17 @@ def __init__(
173185
enable_plotting=False,
174186
enable_statistics=False,
175187
coordinates_type="euclidean",
188+
exact_values=True,
176189
):
177190

178191
# set up variogram model and parameters...
179192
self.variogram_model = variogram_model
180193
self.model = None
194+
195+
if not isinstance(exact_values, bool):
196+
raise ValueError("exact_values has to be boolean True or False")
197+
self.exact_values = exact_values
198+
181199
# check if a GSTools covariance model is given
182200
if hasattr(self.variogram_model, "pykrige_kwargs"):
183201
# save the model in the class
@@ -585,11 +603,11 @@ def _get_kriging_matrix(self, n):
585603
)
586604
a = np.zeros((n + 1, n + 1))
587605
a[:n, :n] = -self.variogram_function(self.variogram_model_parameters, d)
606+
588607
np.fill_diagonal(a, 0.0)
589608
a[n, :] = 1.0
590609
a[:, n] = 1.0
591610
a[n, n] = 0.0
592-
593611
return a
594612

595613
def _exec_vector(self, a, bd, mask):
@@ -609,7 +627,7 @@ def _exec_vector(self, a, bd, mask):
609627

610628
b = np.zeros((npt, n + 1, 1))
611629
b[:, :n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
612-
if zero_value:
630+
if zero_value and self.exact_values:
613631
b[zero_index[0], zero_index[1], 0] = 0.0
614632
b[:, n, 0] = 1.0
615633

@@ -647,7 +665,7 @@ def _exec_loop(self, a, bd_all, mask):
647665

648666
b = np.zeros((n + 1, 1))
649667
b[:n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
650-
if zero_value:
668+
if zero_value and self.exact_values:
651669
b[zero_index[0], 0] = 0.0
652670
b[n, 0] = 1.0
653671
x = np.dot(a_inv, b)
@@ -683,7 +701,7 @@ def _exec_loop_moving_window(self, a_all, bd_all, mask, bd_idx):
683701
zero_value = False
684702
b = np.zeros((n + 1, 1))
685703
b[:n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
686-
if zero_value:
704+
if zero_value and self.exact_values:
687705
b[zero_index[0], 0] = 0.0
688706
b[n, 0] = 1.0
689707

@@ -705,25 +723,6 @@ def execute(
705723
):
706724
"""Calculates a kriged grid and the associated variance.
707725
708-
This is now the method that performs the main kriging calculation.
709-
Note that currently measurements (i.e., z values) are considered
710-
'exact'. This means that, when a specified coordinate for interpolation
711-
is exactly the same as one of the data points, the variogram evaluated
712-
at the point is forced to be zero. Also, the diagonal of the kriging
713-
matrix is also always forced to be zero. In forcing the variogram
714-
evaluated at data points to be zero, we are effectively saying that
715-
there is no variance at that point (no uncertainty,
716-
so the value is 'exact').
717-
718-
In the future, the code may include an extra 'exact_values' boolean
719-
flag that can be adjusted to specify whether to treat the measurements
720-
as 'exact'. Setting the flag to false would indicate that the
721-
variogram should not be forced to be zero at zero distance
722-
(i.e., when evaluated at data points). Instead, the uncertainty in
723-
the point will be equal to the nugget. This would mean that the
724-
diagonal of the kriging matrix would be set to
725-
the nugget instead of to zero.
726-
727726
Parameters
728727
----------
729728
style : str
@@ -876,6 +875,7 @@ def execute(
876875
"eps",
877876
"variogram_model_parameters",
878877
"variogram_function",
878+
"exact_values",
879879
]
880880
}
881881

pykrige/ok3d.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
----------
1515
.. [1] P.K. Kitanidis, Introduction to Geostatistcs: Applications in
1616
Hydrogeology, (Cambridge University Press, 1997) 272 p.
17+
.. [2] N. Cressie, Statistics for spatial data,
18+
(Wiley Series in Probability and Statistics, 1993) 137 p.
1719
1820
Copyright (c) 2015-2020, PyKrige Developers
1921
"""
@@ -151,11 +153,21 @@ class OrdinaryKriging3D:
151153
Default is False (off).
152154
enable_plotting : bool, optional
153155
Enables plotting to display variogram. Default is False (off).
156+
exact_values : bool, optional
157+
If True, interpolation provides input values at input locations.
158+
If False, interpolation accounts for variance/nugget within input
159+
values at input locations and does not behave as an
160+
exact-interpolator [2]. Note that this only has an effect if
161+
there is variance/nugget present within the input data since it is
162+
interpreted as measurement error. If the nugget is zero, the kriged
163+
field will behave as an exact interpolator.
154164
155165
References
156166
----------
157167
.. [1] P.K. Kitanidis, Introduction to Geostatistcs: Applications in
158168
Hydrogeology, (Cambridge University Press, 1997) 272 p.
169+
.. [2] N. Cressie, Statistics for spatial data,
170+
(Wiley Series in Probability and Statistics, 1993) 137 p.
159171
"""
160172

161173
eps = 1.0e-10 # Cutoff for comparison to zero
@@ -186,11 +198,17 @@ def __init__(
186198
anisotropy_angle_z=0.0,
187199
verbose=False,
188200
enable_plotting=False,
201+
exact_values=True,
189202
):
190203

191204
# set up variogram model and parameters...
192205
self.variogram_model = variogram_model
193206
self.model = None
207+
208+
if not isinstance(exact_values, bool):
209+
raise ValueError("exact_values has to be boolean True or False")
210+
self.exact_values = exact_values
211+
194212
# check if a GSTools covariance model is given
195213
if hasattr(self.variogram_model, "pykrige_kwargs"):
196214
# save the model in the class
@@ -594,7 +612,7 @@ def _exec_vector(self, a, bd, mask):
594612

595613
b = np.zeros((npt, n + 1, 1))
596614
b[:, :n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
597-
if zero_value:
615+
if zero_value and self.exact_values:
598616
b[zero_index[0], zero_index[1], 0] = 0.0
599617
b[:, n, 0] = 1.0
600618

@@ -632,7 +650,7 @@ def _exec_loop(self, a, bd_all, mask):
632650

633651
b = np.zeros((n + 1, 1))
634652
b[:n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
635-
if zero_value:
653+
if zero_value and self.exact_values:
636654
b[zero_index[0], 0] = 0.0
637655
b[n, 0] = 1.0
638656

@@ -669,7 +687,7 @@ def _exec_loop_moving_window(self, a_all, bd_all, mask, bd_idx):
669687
zero_index = None
670688
b = np.zeros((n + 1, 1))
671689
b[:n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
672-
if zero_value:
690+
if zero_value and self.exact_values:
673691
b[zero_index[0], 0] = 0.0
674692
b[n, 0] = 1.0
675693

pykrige/uk.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
----------
1616
.. [1] P.K. Kitanidis, Introduction to Geostatistcs: Applications in
1717
Hydrogeology, (Cambridge University Press, 1997) 272 p.
18-
18+
.. [2] N. Cressie, Statistics for spatial data,
19+
(Wiley Series in Probability and Statistics, 1993) 137 p.
1920
Copyright (c) 2015-2020, PyKrige Developers
2021
"""
2122
import numpy as np
@@ -172,11 +173,21 @@ class UniversalKriging:
172173
Default is False (off).
173174
enable_plotting : boolean, optional
174175
Enables plotting to display variogram. Default is False (off).
176+
exact_values : bool, optional
177+
If True, interpolation provides input values at input locations.
178+
If False, interpolation accounts for variance/nugget within input
179+
values at input locations and does not behave as an
180+
exact-interpolator [2]. Note that this only has an effect if
181+
there is variance/nugget present within the input data since it is
182+
interpreted as measurement error. If the nugget is zero, the kriged
183+
field will behave as an exact interpolator.
175184
176185
References
177186
----------
178187
.. [1] P.K. Kitanidis, Introduction to Geostatistcs: Applications in
179188
Hydrogeology, (Cambridge University Press, 1997) 272 p.
189+
.. [2] N. Cressie, Statistics for spatial data,
190+
(Wiley Series in Probability and Statistics, 1993) 137 p.
180191
"""
181192

182193
UNBIAS = True # This can be changed to remove the unbiasedness condition
@@ -212,6 +223,7 @@ def __init__(
212223
functional_drift=None,
213224
verbose=False,
214225
enable_plotting=False,
226+
exact_values=True,
215227
):
216228

217229
# Deal with mutable default argument
@@ -225,6 +237,11 @@ def __init__(
225237
# set up variogram model and parameters...
226238
self.variogram_model = variogram_model
227239
self.model = None
240+
241+
if not isinstance(exact_values, bool):
242+
raise ValueError("exact_values has to be boolean True or False")
243+
self.exact_values = exact_values
244+
228245
# check if a GSTools covariance model is given
229246
if hasattr(self.variogram_model, "pykrige_kwargs"):
230247
# save the model in the class
@@ -820,6 +837,7 @@ def _get_kriging_matrix(self, n, n_withdrifts):
820837
else:
821838
a = np.zeros((n_withdrifts, n_withdrifts))
822839
a[:n, :n] = -self.variogram_function(self.variogram_model_parameters, d)
840+
823841
np.fill_diagonal(a, 0.0)
824842

825843
i = n
@@ -888,7 +906,7 @@ def _exec_vector(self, a, bd, xy, xy_orig, mask, n_withdrifts, spec_drift_grids)
888906
else:
889907
b = np.zeros((npt, n_withdrifts, 1))
890908
b[:, :n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
891-
if zero_value:
909+
if zero_value and self.exact_values:
892910
b[zero_index[0], zero_index[1], 0] = 0.0
893911

894912
i = n
@@ -979,7 +997,7 @@ def _exec_loop(self, a, bd_all, xy, xy_orig, mask, n_withdrifts, spec_drift_grid
979997
else:
980998
b = np.zeros((n_withdrifts, 1))
981999
b[:n, 0] = -self.variogram_function(self.variogram_model_parameters, bd)
982-
if zero_value:
1000+
if zero_value and self.exact_values:
9831001
b[zero_index[0], 0] = 0.0
9841002

9851003
i = n
@@ -1039,24 +1057,6 @@ def execute(
10391057
"""Calculates a kriged grid and the associated variance.
10401058
Includes drift terms.
10411059
1042-
This is now the method that performs the main kriging calculation.
1043-
Note that currently measurements (i.e., z values) are considered
1044-
'exact'. This means that, when a specified coordinate for interpolation
1045-
is exactly the same as one of the data points, the variogram evaluated
1046-
at the point is forced to be zero. Also, the diagonal of the kriging
1047-
matrix is also always forced to be zero. In forcing the variogram
1048-
evaluated at data points to be zero, we are effectively saying that
1049-
there is no variance at that point (no uncertainty,
1050-
so the value is 'exact').
1051-
1052-
In the future, the code may include an extra 'exact_values' boolean
1053-
flag that can be adjusted to specify whether to treat the measurements
1054-
as 'exact'. Setting the flag to false would indicate that the variogram
1055-
should not be forced to be zero at zero distance (i.e., when evaluated
1056-
at data points). Instead, the uncertainty in the point will be equal to
1057-
the nugget. This would mean that the diagonal of the kriging matrix
1058-
would be set to the nugget instead of to zero.
1059-
10601060
Parameters
10611061
----------
10621062
style : str

0 commit comments

Comments
 (0)