Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
Changes - from version >= 1.x
=============================

2026-02-21
2026-02-2
----------

**version 1.2.2**

* [experimental] LSA-method Ordinary Kriging tests and experiments
* [enhancement] Users can set negative predictions to zero in Area-to-Area, Area-to-Point, and Centroid-based Poisson Kriging


2025-12-26
----------
Expand Down
42 changes: 34 additions & 8 deletions src/pyinterpolate/core/pipelines/block_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def filter_blocks(semivariogram_model: TheoreticalVariogram,
data_crs=None,
raise_when_negative_prediction=True,
raise_when_negative_error=False,
negative_prediction_to_zero=False,
verbose=True) -> gpd.GeoDataFrame:
"""
Function filters block data using Poisson Kriging. By filtering we
Expand Down Expand Up @@ -66,6 +67,9 @@ def filter_blocks(semivariogram_model: TheoreticalVariogram,
raise_when_negative_error : bool, default=True
Raise error when prediction error is negative.

negative_prediction_to_zero : bool, default=False
When predicted value is below zero then set it to zero.

verbose : bool, default=True
Show progress bar

Expand Down Expand Up @@ -154,7 +158,8 @@ def filter_blocks(semivariogram_model: TheoreticalVariogram,
number_of_neighbors=number_of_neighbors,
data_crs=data_crs,
raise_when_negative_prediction=raise_when_negative_prediction,
raise_when_negative_error=raise_when_negative_error
raise_when_negative_error=raise_when_negative_error,
negative_prediction_to_zero=negative_prediction_to_zero
)
return parsed

Expand All @@ -165,6 +170,7 @@ def smooth_blocks(semivariogram_model: TheoreticalVariogram,
data_crs=None,
raise_when_negative_prediction=True,
raise_when_negative_error=True,
negative_prediction_to_zero=False,
verbose=True) -> gpd.GeoDataFrame:
"""
Function smooths aggregated block values, and transform those into
Expand All @@ -191,6 +197,9 @@ def smooth_blocks(semivariogram_model: TheoreticalVariogram,
raise_when_negative_error : bool, default=True
Raise error when prediction error is negative.

negative_prediction_to_zero : bool, default=False
When predicted value is below zero then set it to zero.

verbose : bool, default=True
Show progress bar

Expand Down Expand Up @@ -276,7 +285,8 @@ def smooth_blocks(semivariogram_model: TheoreticalVariogram,
number_of_neighbors=number_of_neighbors,
data_crs=data_crs,
raise_when_negative_prediction=raise_when_negative_prediction,
raise_when_negative_error=raise_when_negative_error
raise_when_negative_error=raise_when_negative_error,
negative_prediction_to_zero=negative_prediction_to_zero
)
return parsed

Expand Down Expand Up @@ -423,7 +433,8 @@ def regularize(self,
number_of_neighbors,
data_crs=None,
raise_when_negative_prediction=True,
raise_when_negative_error=True) -> gpd.GeoDataFrame:
raise_when_negative_error=True,
negative_prediction_to_zero: bool = False) -> gpd.GeoDataFrame:
"""
Function regularizes whole dataset and creates new values and error
maps based on the kriging type. Function does not predict unknown
Expand All @@ -444,6 +455,9 @@ def regularize(self,
raise_when_negative_error : bool, default=True
Raise error when prediction error is negative.

negative_prediction_to_zero : bool, default=False
When predicted value is below zero then set it to zero.

Returns
-------
regularized : gpd.GeoDataFrame
Expand All @@ -460,7 +474,8 @@ def regularize(self,
uid=block_id,
n_neighbours=number_of_neighbors,
pred_raise=raise_when_negative_prediction,
err_raise=raise_when_negative_error
err_raise=raise_when_negative_error,
negative_prediction_to_zero=negative_prediction_to_zero
)

interpolation_results.extend(
Expand Down Expand Up @@ -502,7 +517,12 @@ def _check_given_kriging_type(self, k_type):

return k_type

def _interpolate(self, uid, n_neighbours, pred_raise, err_raise) -> Dict:
def _interpolate(self,
uid,
n_neighbours,
pred_raise,
err_raise,
negative_prediction_to_zero) -> Dict:
"""
Function interpolates block values using one of Poisson Kriging types.

Expand All @@ -520,6 +540,9 @@ def _interpolate(self, uid, n_neighbours, pred_raise, err_raise) -> Dict:
err_raise : bool
Raise error when prediction error is negative.

negative_prediction_to_zero : bool
When predicted value is below zero then set it to zero.

Returns
-------
: dict
Expand All @@ -539,22 +562,25 @@ def _interpolate(self, uid, n_neighbours, pred_raise, err_raise) -> Dict:
unknown_block_index=uid,
number_of_neighbors=n_neighbours,
raise_when_negative_error=err_raise,
raise_when_negative_prediction=pred_raise)
raise_when_negative_prediction=pred_raise,
negative_prediction_to_zero=negative_prediction_to_zero)

elif self.kriging_type == 'atp':
model_output = area_to_point_pk(semivariogram_model=self.semivariogram_model,
point_support=self.point_support,
unknown_block_index=uid,
number_of_neighbors=n_neighbours,
raise_when_negative_prediction=pred_raise,
raise_when_negative_error=err_raise)
raise_when_negative_error=err_raise,
negative_prediction_to_zero=negative_prediction_to_zero)
elif self.kriging_type == 'cb':
model_output = centroid_poisson_kriging(semivariogram_model=self.semivariogram_model,
point_support=self.point_support,
unknown_block_index=uid,
number_of_neighbors=n_neighbours,
raise_when_negative_prediction=pred_raise,
raise_when_negative_error=err_raise)
raise_when_negative_error=err_raise,
negative_prediction_to_zero=negative_prediction_to_zero)
else:
self._raise_wrong_kriging_type_error()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def area_to_area_pk(semivariogram_model: TheoreticalVariogram,
number_of_neighbors: int,
neighbors_range: float = None,
raise_when_negative_prediction=True,
raise_when_negative_error=True) -> dict:
raise_when_negative_error=True,
negative_prediction_to_zero=False) -> dict:
"""
Function predicts areal value in an unknown location based on
the area-to-area Poisson Kriging
Expand Down Expand Up @@ -54,6 +55,9 @@ def area_to_area_pk(semivariogram_model: TheoreticalVariogram,
raise_when_negative_error : bool, default=True
Raise error when prediction error is negative.

negative_prediction_to_zero : bool, default=False
While prediction is negative, then set it to 0.

Returns
-------
results : Dict
Expand Down Expand Up @@ -213,6 +217,8 @@ def area_to_area_pk(semivariogram_model: TheoreticalVariogram,
f'not be lower than 0. Check your sampling '
f'grid, samples, number of neighbors or '
f'semivariogram model type.')
if negative_prediction_to_zero:
zhat = 0

sigmasq = np.matmul(w.T, covars)

Expand Down
58 changes: 34 additions & 24 deletions src/pyinterpolate/kriging/block/area_to_point_poisson_kriging.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
from pyinterpolate.kriging.block.weights import pk_weights_array
from pyinterpolate.semivariogram.deconvolution.block_to_block_semivariance import \
weighted_avg_point_support_semivariances
from pyinterpolate.semivariogram.theoretical.classes.theoretical_variogram import TheoreticalVariogram
from pyinterpolate.transform.select_poisson_kriging_data import select_poisson_kriging_data
from pyinterpolate.semivariogram.theoretical.classes.theoretical_variogram import \
TheoreticalVariogram
from pyinterpolate.transform.select_poisson_kriging_data import \
select_poisson_kriging_data
from pyinterpolate.transform.statistical import sem_to_cov
from pyinterpolate.transform.transform import add_ones

Expand All @@ -26,7 +28,8 @@ def area_to_point_pk(semivariogram_model: TheoreticalVariogram,
neighbors_range: float = None,
raise_when_negative_prediction=True,
raise_when_negative_error=True,
err_to_nan=True):
err_to_nan=True,
negative_prediction_to_zero=False):
"""
Function predicts point-support value in the unknown location based on
the area-to-point Poisson Kriging
Expand Down Expand Up @@ -60,6 +63,9 @@ def area_to_point_pk(semivariogram_model: TheoreticalVariogram,
When point interpolation returns ``ValueError`` then set prediction
or variance error to ``NaN``.

negative_prediction_to_zero : bool, default=False
While prediction is negative, then set it to 0.

Returns
-------
results : Dict[numpy array]
Expand Down Expand Up @@ -261,16 +267,21 @@ def area_to_point_pk(semivariogram_model: TheoreticalVariogram,

if zhat < 0:
if raise_when_negative_prediction:
if err_to_nan:
predicted_points.append(
[upoint[0], upoint[1], np.nan, np.nan]
)
continue
else:
raise ValueError(f'Predicted value is {zhat} and it '
f'should not be lower than 0. Check your '
f'sampling grid, samples, number of '
f'neighbors or semivariogram model type.')
raise ValueError(f'Predicted value is {zhat} and it '
f'should not be lower than 0. Check your '
f'sampling grid, samples, number of '
f'neighbors or semivariogram model type.')
if err_to_nan:
predicted_points.append(
[upoint[0], upoint[1], np.nan, np.nan]
)
continue

if negative_prediction_to_zero:
predicted_points.append(
[upoint[0], upoint[1], 0, np.nan]
)
continue

point_pop = upoint[2]
zhat = (zhat * point_pop) / tot_unknown_value
Expand All @@ -282,17 +293,16 @@ def area_to_point_pk(semivariogram_model: TheoreticalVariogram,

if sigmasq < 0:
if raise_when_negative_error:
if err_to_nan:
predicted_points.append(
[upoint[0], upoint[1], zhat, np.nan]
)
continue
else:
raise ValueError(f'Predicted error value is {sigmasq} and '
f'it should not be lower than 0. '
f'Check your sampling grid, samples, '
f'number of neighbors or semivariogram '
f'model type.')
raise ValueError(f'Predicted error value is {sigmasq} and '
f'it should not be lower than 0. '
f'Check your sampling grid, samples, '
f'number of neighbors or semivariogram '
f'model type.')
if err_to_nan:
predicted_points.append(
[upoint[0], upoint[1], zhat, np.nan]
)
continue
else:
sigma = 0
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ def centroid_poisson_kriging(semivariogram_model: TheoreticalVariogram,
is_weighted_by_point_support=True,
raise_when_negative_prediction=True,
raise_when_negative_error=True,
allow_lsa=False) -> Dict:
allow_lsa=False,
negative_prediction_to_zero=False) -> Dict:
"""
Function performs centroid-based Poisson Kriging of blocks (areal) data.

Expand Down Expand Up @@ -64,6 +65,9 @@ def centroid_poisson_kriging(semivariogram_model: TheoreticalVariogram,
when you have clusters in your dataset,
that can lead to singular or near-singular matrix creation.

negative_prediction_to_zero : bool, default=False
While prediction is negative, then set it to 0.

Returns
-------
results : Dict
Expand Down Expand Up @@ -207,6 +211,9 @@ def centroid_poisson_kriging(semivariogram_model: TheoreticalVariogram,
f'grid, samples, number of neighbors or '
f'semivariogram model type.')

if negative_prediction_to_zero:
zhat = 0

sigmasq = np.matmul(output_weights.T, covars)

if sigmasq < 0:
Expand Down
4 changes: 4 additions & 0 deletions tests/test_core/test_smooth_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ def test_smooth_blocks():
semivariogram_model=THEO,
point_support=PS,
number_of_neighbors=8,
raise_when_negative_prediction=True,
raise_when_negative_error=False,
negative_prediction_to_zero=False,
verbose=True
)
smoothed: gpd.GeoDataFrame
print(smoothed.columns)
assert isinstance(smoothed, gpd.GeoDataFrame)

Expand Down
Loading