rainfallqc 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/PKG-INFO +4 -1
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/pyproject.toml +9 -4
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/__init__.py +4 -1
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/checks/comparison_checks.py +14 -3
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/checks/gauge_checks.py +24 -13
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/checks/neighbourhood_checks.py +9 -0
- rainfallqc-0.2.2/src/rainfallqc/checks/pypwsqc_filters.py +475 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/checks/timeseries_checks.py +11 -2
- rainfallqc-0.2.2/src/rainfallqc/core/all_qc_checks.py +98 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/qc_frameworks/apply_qc_framework.py +0 -1
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/qc_frameworks/inbuilt_qc_frameworks.py +12 -2
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/utils/data_readers.py +34 -8
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/utils/data_utils.py +24 -1
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/utils/neighbourhood_utils.py +87 -24
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/utils/spatial_utils.py +32 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/LICENSE +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/README.rst +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/checks/__init__.py +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/core/__init__.py +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_CDD_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_CWD_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_PRCPTOT_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_R99p_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_Rx1day_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_SDII_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/ETCCDI/__init__.py +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/data/__init__.py +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/qc_frameworks/__init__.py +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/utils/__init__.py +0 -0
- {rainfallqc-0.2.0 → rainfallqc-0.2.2}/src/rainfallqc/utils/stats.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rainfallqc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Quality control for rainfall data
|
|
5
5
|
Author-email: Tom Keel <tomkee@ceh.ac.uk>
|
|
6
6
|
Maintainer-email: Tom Keel <tomkee@ceh.ac.uk>
|
|
@@ -23,10 +23,13 @@ Requires-Dist: scipy
|
|
|
23
23
|
Requires-Dist: numpy
|
|
24
24
|
Requires-Dist: polars>=1.30
|
|
25
25
|
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: pyarrow
|
|
26
27
|
Requires-Dist: xarray
|
|
27
28
|
Requires-Dist: netCDF4
|
|
28
29
|
Requires-Dist: bottleneck
|
|
29
30
|
Requires-Dist: geopy
|
|
31
|
+
Requires-Dist: poligrain
|
|
32
|
+
Requires-Dist: pypwsqc
|
|
30
33
|
Requires-Dist: pip ; extra == "dev"
|
|
31
34
|
Requires-Dist: numpy ; extra == "dev"
|
|
32
35
|
Requires-Dist: bump-my-version ; extra == "dev"
|
|
@@ -30,10 +30,13 @@ dependencies = [
|
|
|
30
30
|
"numpy",
|
|
31
31
|
"polars>=1.30",
|
|
32
32
|
"pandas",
|
|
33
|
+
"pyarrow",
|
|
33
34
|
"xarray",
|
|
34
35
|
"netCDF4",
|
|
35
36
|
"bottleneck",
|
|
36
|
-
"geopy"
|
|
37
|
+
"geopy",
|
|
38
|
+
"poligrain",
|
|
39
|
+
"pypwsqc",
|
|
37
40
|
]
|
|
38
41
|
|
|
39
42
|
[project.optional-dependencies]
|
|
@@ -65,7 +68,7 @@ homepage = "https://github.com/thomasjkeel/RainfallQC"
|
|
|
65
68
|
target-version = ["py310", "py311", "py312", "py313"]
|
|
66
69
|
|
|
67
70
|
[tool.bumpversion]
|
|
68
|
-
current_version = "0.2.
|
|
71
|
+
current_version = "0.2.2"
|
|
69
72
|
commit = true
|
|
70
73
|
message = "Bump version: {current_version} → {new_version}"
|
|
71
74
|
commit_args = ""
|
|
@@ -146,8 +149,10 @@ case-sensitive = true
|
|
|
146
149
|
|
|
147
150
|
[tool.ruff.lint.per-file-ignores]
|
|
148
151
|
"tests/*.py" = [
|
|
149
|
-
"ANN001",
|
|
150
|
-
"
|
|
152
|
+
"ANN001",
|
|
153
|
+
"ANN201",
|
|
154
|
+
"ANN202", # Missing type annotation
|
|
155
|
+
"D103", # Missing docstring in public function
|
|
151
156
|
]
|
|
152
157
|
|
|
153
158
|
[tool.mypy]
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
__author__ = """Tom Keel"""
|
|
4
4
|
__email__ = "tomkee@ceh.ac.uk"
|
|
5
|
-
__version__ = "0.2.
|
|
5
|
+
__version__ = "0.2.2"
|
|
6
6
|
|
|
7
|
+
from rainfallqc import core, utils
|
|
7
8
|
from rainfallqc.checks import (
|
|
8
9
|
comparison_checks,
|
|
9
10
|
gauge_checks,
|
|
@@ -18,4 +19,6 @@ __all__ = [
|
|
|
18
19
|
"gauge_checks",
|
|
19
20
|
"neighbourhood_checks",
|
|
20
21
|
"timeseries_checks",
|
|
22
|
+
"core",
|
|
23
|
+
"utils",
|
|
21
24
|
]
|
|
@@ -11,9 +11,11 @@ import numpy as np
|
|
|
11
11
|
import polars as pl
|
|
12
12
|
import xarray as xr
|
|
13
13
|
|
|
14
|
+
from rainfallqc.core.all_qc_checks import qc_check
|
|
14
15
|
from rainfallqc.utils import data_readers, data_utils, neighbourhood_utils, stats
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
@qc_check("check_annual_exceedance_etccdi_r99p", require_non_negative=True)
|
|
17
19
|
def check_annual_exceedance_etccdi_r99p(
|
|
18
20
|
data: pl.DataFrame, target_gauge_col: str, gauge_lat: int | float, gauge_lon: int | float
|
|
19
21
|
) -> list:
|
|
@@ -43,7 +45,9 @@ def check_annual_exceedance_etccdi_r99p(
|
|
|
43
45
|
etccdi_r99p = data_readers.load_etccdi_data(etccdi_var="R99p")
|
|
44
46
|
|
|
45
47
|
# 2. Get nearest local R99p value to the gauge coordinates
|
|
46
|
-
nearby_etccdi_r99p = neighbourhood_utils.
|
|
48
|
+
nearby_etccdi_r99p = neighbourhood_utils.get_nearest_non_nan_etccdi_val_to_gauge(
|
|
49
|
+
etccdi_r99p, etccdi_name="R99p", gauge_lat=gauge_lat, gauge_lon=gauge_lon
|
|
50
|
+
)
|
|
47
51
|
|
|
48
52
|
# 3. Get sum of rainfall above the 99th percentile per year
|
|
49
53
|
sum_rainfall_above_99percentile_per_year = get_sum_rainfall_above_percentile_per_year(
|
|
@@ -58,6 +62,7 @@ def check_annual_exceedance_etccdi_r99p(
|
|
|
58
62
|
return exceedance_flags
|
|
59
63
|
|
|
60
64
|
|
|
65
|
+
@qc_check("check_annual_exceedance_etccdi_prcptot", require_non_negative=True)
|
|
61
66
|
def check_annual_exceedance_etccdi_prcptot(
|
|
62
67
|
data: pl.DataFrame, target_gauge_col: str, gauge_lat: int | float, gauge_lon: int | float
|
|
63
68
|
) -> list:
|
|
@@ -87,7 +92,9 @@ def check_annual_exceedance_etccdi_prcptot(
|
|
|
87
92
|
etccdi_prcptot = data_readers.load_etccdi_data(etccdi_var="PRCPTOT")
|
|
88
93
|
|
|
89
94
|
# 2. Get nearest local PRCPTOT value to the gauge coordinates
|
|
90
|
-
nearby_etccdi_prcptot = neighbourhood_utils.
|
|
95
|
+
nearby_etccdi_prcptot = neighbourhood_utils.get_nearest_non_nan_etccdi_val_to_gauge(
|
|
96
|
+
etccdi_prcptot, etccdi_name="PRCPTOT", gauge_lat=gauge_lat, gauge_lon=gauge_lon
|
|
97
|
+
)
|
|
91
98
|
|
|
92
99
|
# 3. Get sum of rainfall above the 99th percentile per year
|
|
93
100
|
sum_rainfall_above_99percentile_per_year = get_sum_rainfall_above_percentile_per_year(
|
|
@@ -102,6 +109,7 @@ def check_annual_exceedance_etccdi_prcptot(
|
|
|
102
109
|
return exceedance_flags
|
|
103
110
|
|
|
104
111
|
|
|
112
|
+
@qc_check("check_exceedance_of_rainfall_world_record", require_non_negative=True)
|
|
105
113
|
def check_exceedance_of_rainfall_world_record(data: pl.DataFrame, target_gauge_col: str, time_res: str) -> pl.DataFrame:
|
|
106
114
|
"""
|
|
107
115
|
Check exceedance of rainfall world record.
|
|
@@ -135,6 +143,7 @@ def check_exceedance_of_rainfall_world_record(data: pl.DataFrame, target_gauge_c
|
|
|
135
143
|
return data_w_flags.select(["time", "world_record_check"])
|
|
136
144
|
|
|
137
145
|
|
|
146
|
+
@qc_check("check_hourly_exceedance_etccdi_rx1day", require_non_negative=True)
|
|
138
147
|
def check_hourly_exceedance_etccdi_rx1day(
|
|
139
148
|
data: pl.DataFrame, target_gauge_col: str, gauge_lat: int | float, gauge_lon: int | float
|
|
140
149
|
) -> pl.DataFrame:
|
|
@@ -173,7 +182,9 @@ def check_hourly_exceedance_etccdi_rx1day(
|
|
|
173
182
|
etccdi_rx1day = data_readers.load_etccdi_data(etccdi_var="Rx1day")
|
|
174
183
|
|
|
175
184
|
# 3. Get nearest local Rx1day value to the gauge coordinates
|
|
176
|
-
nearby_etccdi_rx1day = neighbourhood_utils.
|
|
185
|
+
nearby_etccdi_rx1day = neighbourhood_utils.get_nearest_non_nan_etccdi_val_to_gauge(
|
|
186
|
+
etccdi_rx1day, etccdi_name="Rx1day", gauge_lat=gauge_lat, gauge_lon=gauge_lon
|
|
187
|
+
)
|
|
177
188
|
|
|
178
189
|
# 4. Get local maximum ETCCDI value
|
|
179
190
|
max_nearby_etccdi_rx1day = np.max(nearby_etccdi_rx1day["Rx1day"])
|
|
@@ -10,9 +10,11 @@ Classes and functions ordered by appearance in IntenseQC framework.
|
|
|
10
10
|
import polars as pl
|
|
11
11
|
import scipy.stats
|
|
12
12
|
|
|
13
|
+
from rainfallqc.core.all_qc_checks import qc_check
|
|
13
14
|
from rainfallqc.utils import data_utils, stats
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
@qc_check("check_years_where_nth_percentile_is_zero", require_non_negative=True)
|
|
16
18
|
def check_years_where_nth_percentile_is_zero(data: pl.DataFrame, target_gauge_col: str, quantile: float) -> list:
|
|
17
19
|
"""
|
|
18
20
|
Return years where the n-th percentiles is zero.
|
|
@@ -38,6 +40,7 @@ def check_years_where_nth_percentile_is_zero(data: pl.DataFrame, target_gauge_co
|
|
|
38
40
|
return nth_perc.filter(pl.col(target_gauge_col) == 0)["time"].dt.year().to_list()
|
|
39
41
|
|
|
40
42
|
|
|
43
|
+
@qc_check("check_years_where_annual_mean_k_top_rows_are_zero", require_non_negative=True)
|
|
41
44
|
def check_years_where_annual_mean_k_top_rows_are_zero(data: pl.DataFrame, target_gauge_col: str, k: int) -> list:
|
|
42
45
|
"""
|
|
43
46
|
Return year list where the annual mean top-K rows are zero.
|
|
@@ -63,6 +66,7 @@ def check_years_where_annual_mean_k_top_rows_are_zero(data: pl.DataFrame, target
|
|
|
63
66
|
return data_top_k.filter(pl.col(target_gauge_col) == 0)["time"].dt.year().to_list()
|
|
64
67
|
|
|
65
68
|
|
|
69
|
+
@qc_check("check_temporal_bias", require_non_negative=True)
|
|
66
70
|
def check_temporal_bias(
|
|
67
71
|
data: pl.DataFrame,
|
|
68
72
|
target_gauge_col: str,
|
|
@@ -109,6 +113,7 @@ def check_temporal_bias(
|
|
|
109
113
|
return int(p_val < p_threshold)
|
|
110
114
|
|
|
111
115
|
|
|
116
|
+
@qc_check("check_intermittency", require_non_negative=True)
|
|
112
117
|
def check_intermittency(
|
|
113
118
|
data: pl.DataFrame, target_gauge_col: str, no_data_threshold: int = 2, annual_count_threshold: int = 5
|
|
114
119
|
) -> list:
|
|
@@ -135,20 +140,24 @@ def check_intermittency(
|
|
|
135
140
|
List of years with intermittency issues.
|
|
136
141
|
|
|
137
142
|
"""
|
|
138
|
-
# 1.
|
|
143
|
+
# 1. Check data has consistent time step
|
|
144
|
+
data_utils.check_data_has_consistent_time_step(data)
|
|
145
|
+
|
|
146
|
+
# 2. Replace missing values with NaN
|
|
139
147
|
data = data_utils.replace_missing_vals_with_nan(data, target_gauge_col)
|
|
140
148
|
|
|
141
|
-
#
|
|
149
|
+
# 3. Mark missing values
|
|
142
150
|
data = data.with_columns(pl.col(target_gauge_col).is_nan().alias("is_missing"))
|
|
143
151
|
|
|
144
|
-
#
|
|
152
|
+
# 4. Assign group numbers to consecutive missing values
|
|
145
153
|
grouped = data.with_columns(
|
|
146
154
|
pl.when(pl.col("is_missing"))
|
|
147
155
|
.then((~pl.col("is_missing")).cum_sum()) # Only number missing stretches
|
|
148
156
|
.otherwise(None)
|
|
149
157
|
.alias("group")
|
|
150
158
|
)
|
|
151
|
-
|
|
159
|
+
|
|
160
|
+
# 5. Count size of each missing group
|
|
152
161
|
group_counts = (
|
|
153
162
|
grouped.filter(pl.col("is_missing"))
|
|
154
163
|
.group_by("group")
|
|
@@ -156,21 +165,21 @@ def check_intermittency(
|
|
|
156
165
|
.filter(pl.col("count") >= no_data_threshold)
|
|
157
166
|
)
|
|
158
167
|
|
|
159
|
-
#
|
|
168
|
+
# 6. Keep only valid groups
|
|
160
169
|
valid_missing_groups = group_counts["group"].to_list()
|
|
161
170
|
valid_missing = grouped.filter(pl.col("group").is_in(valid_missing_groups))
|
|
162
171
|
|
|
163
|
-
#
|
|
172
|
+
# 7. Get first and last time for each group
|
|
164
173
|
first_last = (
|
|
165
174
|
valid_missing.sort("time")
|
|
166
175
|
.group_by("group")
|
|
167
176
|
.agg([pl.first("time").alias("start_time"), pl.last("time").alias("end_time")])
|
|
168
177
|
)
|
|
169
178
|
|
|
170
|
-
#
|
|
179
|
+
# 8. Add stable row index to full sorted data
|
|
171
180
|
df_sorted = data.sort("time").with_row_index("row_idx")
|
|
172
181
|
|
|
173
|
-
#
|
|
182
|
+
# 9. Lookup row indices of group bounds
|
|
174
183
|
first_last_with_idx = (
|
|
175
184
|
first_last.join(df_sorted.select(["time", "row_idx"]), left_on="start_time", right_on="time")
|
|
176
185
|
.rename({"row_idx": "start_idx"})
|
|
@@ -178,7 +187,7 @@ def check_intermittency(
|
|
|
178
187
|
.rename({"row_idx": "end_idx"})
|
|
179
188
|
)
|
|
180
189
|
|
|
181
|
-
#
|
|
190
|
+
# 10. Compute prev/next indices and fetch values
|
|
182
191
|
row_lookup = df_sorted.select([pl.col("row_idx"), pl.col(target_gauge_col)])
|
|
183
192
|
|
|
184
193
|
first_last_with_vals = (
|
|
@@ -189,21 +198,22 @@ def check_intermittency(
|
|
|
189
198
|
.join(row_lookup.rename({target_gauge_col: "next_val"}), left_on="next_idx", right_on="row_idx")
|
|
190
199
|
)
|
|
191
200
|
|
|
192
|
-
#
|
|
201
|
+
# 11. Filter to groups bounded by zero
|
|
193
202
|
bounded_by_zero = first_last_with_vals.filter((pl.col("prev_val") == 0) & (pl.col("next_val") == 0))
|
|
194
203
|
|
|
195
|
-
#
|
|
204
|
+
# 12. Extract year from each bounded group's start time
|
|
196
205
|
bounded_years = bounded_by_zero.select(pl.col("start_time").dt.year().alias("year"))
|
|
197
206
|
|
|
198
|
-
#
|
|
207
|
+
# 13. Count how many bounded groups occur per year
|
|
199
208
|
year_counts = bounded_years.group_by("year").len()
|
|
200
209
|
|
|
201
|
-
#
|
|
210
|
+
# 14. Get years exceeding threshold
|
|
202
211
|
years_w_intermittency = year_counts.filter(pl.col("len") >= annual_count_threshold)["year"].to_list()
|
|
203
212
|
|
|
204
213
|
return years_w_intermittency
|
|
205
214
|
|
|
206
215
|
|
|
216
|
+
@qc_check("check_breakpoints", require_non_negative=True)
|
|
207
217
|
def check_breakpoints(
|
|
208
218
|
data: pl.DataFrame,
|
|
209
219
|
target_gauge_col: str,
|
|
@@ -240,6 +250,7 @@ def check_breakpoints(
|
|
|
240
250
|
return 0
|
|
241
251
|
|
|
242
252
|
|
|
253
|
+
@qc_check("check_min_val_change", require_non_negative=True)
|
|
243
254
|
def check_min_val_change(data: pl.DataFrame, target_gauge_col: str, expected_min_val: float) -> list:
|
|
244
255
|
"""
|
|
245
256
|
Return years when the minimum recorded value changes.
|
|
@@ -12,9 +12,11 @@ from typing import Iterable, List
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
import polars as pl
|
|
14
14
|
|
|
15
|
+
from rainfallqc.core.all_qc_checks import qc_check
|
|
15
16
|
from rainfallqc.utils import data_readers, data_utils, neighbourhood_utils, stats
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
@qc_check("check_wet_neighbours", require_non_negative=True)
|
|
18
20
|
def check_wet_neighbours(
|
|
19
21
|
neighbour_data: pl.DataFrame,
|
|
20
22
|
target_gauge_col: str,
|
|
@@ -129,6 +131,7 @@ def check_wet_neighbours(
|
|
|
129
131
|
return neighbour_data_w_wet_flags
|
|
130
132
|
|
|
131
133
|
|
|
134
|
+
@qc_check("check_dry_neighbours", require_non_negative=True)
|
|
132
135
|
def check_dry_neighbours(
|
|
133
136
|
neighbour_data: pl.DataFrame,
|
|
134
137
|
target_gauge_col: str,
|
|
@@ -261,6 +264,7 @@ def check_dry_neighbours(
|
|
|
261
264
|
return neighbour_data_w_dry_flags
|
|
262
265
|
|
|
263
266
|
|
|
267
|
+
@qc_check("check_monthly_neighbours", require_non_negative=True)
|
|
264
268
|
def check_monthly_neighbours(
|
|
265
269
|
monthly_neighbour_data: pl.DataFrame,
|
|
266
270
|
target_gauge_col: str,
|
|
@@ -355,6 +359,7 @@ def check_monthly_neighbours(
|
|
|
355
359
|
return monthly_neighbour_data_w_flags.select(["time", "majority_monthly_flag"])
|
|
356
360
|
|
|
357
361
|
|
|
362
|
+
@qc_check("check_timing_offset", require_non_negative=True)
|
|
358
363
|
def check_timing_offset(
|
|
359
364
|
neighbour_data: pl.DataFrame,
|
|
360
365
|
target_gauge_col: str,
|
|
@@ -436,6 +441,7 @@ def check_timing_offset(
|
|
|
436
441
|
return offset_flag
|
|
437
442
|
|
|
438
443
|
|
|
444
|
+
@qc_check("check_neighbour_affinity_index", require_non_negative=True)
|
|
439
445
|
def check_neighbour_affinity_index(
|
|
440
446
|
neighbour_data: pl.DataFrame, target_gauge_col: str, neighbouring_gauge_col: str
|
|
441
447
|
) -> float:
|
|
@@ -471,6 +477,7 @@ def check_neighbour_affinity_index(
|
|
|
471
477
|
return stats.affinity_index(neighbour_data, binary_col="rain_not_minima")
|
|
472
478
|
|
|
473
479
|
|
|
480
|
+
@qc_check("check_neighbour_correlation", require_non_negative=True)
|
|
474
481
|
def check_neighbour_correlation(
|
|
475
482
|
neighbour_data: pl.DataFrame, target_gauge_col: str, neighbouring_gauge_col: str
|
|
476
483
|
) -> float:
|
|
@@ -501,6 +508,7 @@ def check_neighbour_correlation(
|
|
|
501
508
|
return stats.gauge_correlation(neighbour_data, target_col=target_gauge_col, other_col=neighbouring_gauge_col)
|
|
502
509
|
|
|
503
510
|
|
|
511
|
+
@qc_check("check_daily_factor", require_non_negative=True)
|
|
504
512
|
def check_daily_factor(
|
|
505
513
|
neighbour_data: pl.DataFrame, target_gauge_col: str, neighbouring_gauge_col: str, averaging_method: str = "mean"
|
|
506
514
|
) -> float:
|
|
@@ -553,6 +561,7 @@ def check_daily_factor(
|
|
|
553
561
|
raise ValueError(f"{averaging_method} not recognised, please use 'mean' or 'median'")
|
|
554
562
|
|
|
555
563
|
|
|
564
|
+
@qc_check("check_monthly_factor", require_non_negative=True)
|
|
556
565
|
def check_monthly_factor(
|
|
557
566
|
neighbour_data: pl.DataFrame, target_gauge_col: str, neighbouring_gauge_col: str
|
|
558
567
|
) -> pl.DataFrame:
|