core-lens 0.1.dev190__tar.gz → 0.1.dev191__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.
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/PKG-INFO +1 -1
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/_version.py +2 -2
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/namespaces/stats.py +29 -16
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/ISSUE_TEMPLATE/blank-proposal.yaml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/pull_request_template.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/workflows/ci.yml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/workflows/gh-pages.yml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/workflows/pre-release.yml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.github/workflows/release.yml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.gitignore +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.gitmessage +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.pre-commit-config.yaml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/.python-version +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/CONTRIBUTING.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/LICENSE +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/README.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/SKILLS.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/README.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_aoi.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_entity.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_export.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_polars_utils.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_result.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_schema.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_season.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_spatial.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/bench_view.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/benchmarks/run_all.sh +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/Makefile +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/make.bat +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/concepts.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/conf.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/export.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/index.rst +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/intro.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/logging.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/plots.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/plugins.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/queries.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/quickstart.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/docs/source/stats.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/examples/demo_mws.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/examples/demo_tehsil.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/hooks/mypy.sh +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/hooks/no-parquet-outside-fixtures.sh +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/hooks/pytest.sh +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/pyproject.toml +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/__main__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/aoi.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/entity.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/namespaces/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/namespaces/plot.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/result.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/base/view.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/entities/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/entities/farms.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/entities/mws.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/entities/tehsil.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/entities/waterbody.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/export/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/export/formats.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/py.typed +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/schema/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/schema/detection.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/schema/profile.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/utils/__init__.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/utils/paths.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/utils/polars_utils.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/utils/season.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/src/core_lens/utils/spatial.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/fixtures/generate_fixtures.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/conftest.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_aoi.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_entities.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_entity.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_export.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_main.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_plot.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_polars_utils.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_profile.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_result.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_schema_detection.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_schema_profile.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_season.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_season_config.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_spatial.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_stats.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/tests/unit/test_view.py +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/usage.md +0 -0
- {core_lens-0.1.dev190 → core_lens-0.1.dev191}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: core-lens
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.dev191
|
|
4
4
|
Summary: Query, analyse, and visualise CoreStack's microwatershed and Earth science data through a clean, composable Python API.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ApoorvaKashyap/core-lens
|
|
6
6
|
Project-URL: Issues, https://github.com/ApoorvaKashyap/core-lens/issues
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1, '
|
|
21
|
+
__version__ = version = '0.1.dev191'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 'dev191')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -777,6 +777,17 @@ class StatsNamespace:
|
|
|
777
777
|
Raises:
|
|
778
778
|
ValueError: If ``mode``/``method`` invalid, observation count too low, or
|
|
779
779
|
``baseline`` and ``target_years`` overlap.
|
|
780
|
+
|
|
781
|
+
Notes:
|
|
782
|
+
**STL fitting scope.** For ``AnomalyTsMethod.STL`` the decomposition
|
|
783
|
+
(trend + seasonal + remainder) is fit on the *entire* series of each entity,
|
|
784
|
+
baseline and target years together. ``baseline`` is used only to calibrate the scale (standard deviation) of the remainder; ``target_years`` selects which points are scored. Scores are ``remainder / baseline_remainder_std``.
|
|
785
|
+
|
|
786
|
+
Because target observations take part in the fit, the trend and seasonal components can partly absorb target-period anomalies, shrinking the remainder and lowering the score. The effect grows with the size and duration of the anomaly; a sustained shift can be absorbed almost entirely into the trend. Scores therefore measure deviation from a locally fitted trend and seasonal pattern, not from the baseline's "normal" behaviour, and the method is conservative: it may miss anomalies but is unlikely to over-flag them.
|
|
787
|
+
|
|
788
|
+
A stricter alternative is to fit on the baseline only and forecast the target period (e.g. ``statsmodels.tsa.forecasting.stl.STLForecast``), scoring forecast errors against the baseline error spread. This is not implemented.
|
|
789
|
+
|
|
790
|
+
For sub-annual data, residuals are matched to rows by the finer time column (``date``/``period``), not by year, so each observation gets its own score.
|
|
780
791
|
"""
|
|
781
792
|
if baseline is not None and target_years is not None:
|
|
782
793
|
b_lo, b_hi = baseline
|
|
@@ -976,7 +987,8 @@ class StatsNamespace:
|
|
|
976
987
|
# ---- CUSUM / STL: inherently sequential/per-entity, partition_by instead of filter-loop ----
|
|
977
988
|
else:
|
|
978
989
|
rows: list[dict[str, Any]] = []
|
|
979
|
-
|
|
990
|
+
sort_cols = list(dict.fromkeys([year_col, output_time_col]))
|
|
991
|
+
for sub in df.sort(sort_cols).partition_by(key, maintain_order=True):
|
|
980
992
|
eid = sub[key][0]
|
|
981
993
|
base_vals = (
|
|
982
994
|
sub.filter(
|
|
@@ -1027,6 +1039,7 @@ class StatsNamespace:
|
|
|
1027
1039
|
full = sub.filter(pl.col(column).is_not_null())
|
|
1028
1040
|
full_vals = full[column].to_numpy().astype(float)
|
|
1029
1041
|
full_years = full[year_col].to_list()
|
|
1042
|
+
full_times = full[output_time_col].to_list()
|
|
1030
1043
|
|
|
1031
1044
|
period = (
|
|
1032
1045
|
26 if len(full_vals) >= 52 else max(2, len(full_vals) // 2)
|
|
@@ -1036,13 +1049,13 @@ class StatsNamespace:
|
|
|
1036
1049
|
3 * period
|
|
1037
1050
|
) # want ~3 cycles minimum for a trustworthy seasonal fit, not just 2
|
|
1038
1051
|
|
|
1039
|
-
if len(full_vals) <
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1052
|
+
# if len(full_vals) < min_reliable:
|
|
1053
|
+
# warnings.warn(
|
|
1054
|
+
# f"StatsNamespace.anomaly: entity {eid!r} has {len(full_vals)} points, "
|
|
1055
|
+
# f"period={period} needs >= {min_reliable} for a reliable STL fit. Skipping."
|
|
1056
|
+
# )
|
|
1057
|
+
# n_dropped += 1
|
|
1058
|
+
# continue
|
|
1046
1059
|
|
|
1047
1060
|
if len(full_vals) < min_required:
|
|
1048
1061
|
warnings.warn(
|
|
@@ -1058,21 +1071,21 @@ class StatsNamespace:
|
|
|
1058
1071
|
res = STL(full_vals, period=period).fit()
|
|
1059
1072
|
resid = res.resid
|
|
1060
1073
|
|
|
1061
|
-
#
|
|
1062
|
-
#
|
|
1063
|
-
|
|
1074
|
+
# Key residuals by the fine-grained time column (date/period).
|
|
1075
|
+
# Keying by year collapses ~26 fortnights into one value.
|
|
1076
|
+
resid_by_time = dict(zip(full_times, resid))
|
|
1064
1077
|
base_resid = [
|
|
1065
|
-
|
|
1066
|
-
for y in full_years
|
|
1078
|
+
r
|
|
1079
|
+
for y, r in zip(full_years, resid)
|
|
1067
1080
|
if baseline[0] <= y <= baseline[1]
|
|
1068
1081
|
]
|
|
1069
1082
|
std = _sf(pl.Series(base_resid).std(ddof=1)) or 1.0
|
|
1070
1083
|
|
|
1071
1084
|
ts_scores = [
|
|
1072
|
-
float(
|
|
1073
|
-
if
|
|
1085
|
+
float(resid_by_time[t] / std)
|
|
1086
|
+
if t in resid_by_time
|
|
1074
1087
|
else float("nan")
|
|
1075
|
-
for
|
|
1088
|
+
for t in eval_times
|
|
1076
1089
|
]
|
|
1077
1090
|
ts_flags = [
|
|
1078
1091
|
abs(s) > threshold if s == s else False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|