ThreeWToolkit 3.1.0__tar.gz → 3.2.1__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.
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/PKG-INFO +4 -4
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/pyproject.toml +1 -1
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/README.md +3 -3
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/assessment/model_assess.py +2 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/metrics/__init__.py +2 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/metrics/_classification.py +37 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit.egg-info/PKG-INFO +4 -4
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit.egg-info/SOURCES.txt +0 -7
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit.egg-info/top_level.txt +0 -1
- threewtoolkit-3.1.0/tests/test_clustering_models.py +0 -265
- threewtoolkit-3.1.0/tests/test_clustering_plots.py +0 -456
- threewtoolkit-3.1.0/tests/test_dataset.py +0 -155
- threewtoolkit-3.1.0/tests/test_distance_computer.py +0 -119
- threewtoolkit-3.1.0/tests/test_instance_quality_filter.py +0 -167
- threewtoolkit-3.1.0/tests/test_report_generation.py +0 -283
- threewtoolkit-3.1.0/tests/test_time_series_resampler.py +0 -138
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/LICENSE.md +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/README.md +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/setup.cfg +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/assessment/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/assessment/assessment_visualizations.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_consensus.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_distances.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_divisive.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_hierarchical.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_normalization.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_quality.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_resampling.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/clustering/_utils.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/constants.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_assessment.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_assessment_visualization.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_clustering.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_dataset.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_feature_extractor.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_instantiable.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_models.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_pipeline.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_prediction_strategies.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_preprocessing.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_trainer.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_transform.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/base_visualizer.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/dataset_outputs.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/core/enums.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/clustering_plots.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/correlation_heatmap.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/plot_fft.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/plot_multiple_series.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/plot_series.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/plot_utils.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/plots.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/seasonal_decomposition.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/three_w_chart.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/data_visualization/wavelet_spectrogram.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/dataset/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/dataset/csv_data_loader.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/dataset/parquet_dataset.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/dataset/subset_dataset.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/dataset/transform_dataset.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/dataset/transformed_dataset.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/feature_extraction/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/feature_extraction/adapters.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/feature_extraction/exponential_statistics.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/feature_extraction/statistical.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/feature_extraction/wavelet.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/feature_extraction/windowing.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/logging_config.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/metrics/_regression.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/models/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/models/mlp.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/models/sklearn_models.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/models/torch_models.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/pipeline.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/adapters.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/clean_signals.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/fill_labels.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/impute_missing.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/normalize.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/remap.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/preprocessing/rename_column.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/reports/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/reports/report_generation.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/trainer/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/trainer/sklearn_trainer.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/trainer/torch_trainer.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/__init__.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/data_splitter.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/data_utils.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/downloader.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/general_utils.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/model_recorder.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/template_manager.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/utils/trainer_logger.py +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit.egg-info/dependency_links.txt +0 -0
- {threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit.egg-info/requires.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ThreeWToolkit
|
|
3
|
-
Version: 3.1
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: A modular and open-source AI toolkit for time-series processing, aimed at fault detection and classification in oil well operation
|
|
5
5
|
Author-email: Ricardo Emanuel Vaz Vargas <ricardo.vargas@petrobras.com.br>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -127,7 +127,7 @@ To better understand how the system is organized, we can divide all classes into
|
|
|
127
127
|
## 📊 3W Dataset <a id="dataset"></a>
|
|
128
128
|
The **3W dataset** serves as a **reference dataset** for this project and is hosted on [Figshare](https://figshare.com/projects/3W_Dataset/251195). However, the toolkit is not limited to the 3W dataset and can be adapted for other datasets as well.
|
|
129
129
|
|
|
130
|
-
Further details on the 3W dataset’s structure, preprocessing, and usage are available in the [3W_DATASET_STRUCTURE.md](
|
|
130
|
+
Further details on the 3W dataset’s structure, preprocessing, and usage are available in the [3W_DATASET_STRUCTURE.md](https://github.com/petrobras/3W/blob/main/3W_DATASET_STRUCTURE.md) file.
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
## ⚙️ Installation & Setup <a id="installation"></a>
|
|
@@ -170,11 +170,11 @@ conda activate 3W
|
|
|
170
170
|
## 🪐 Jupyter Notebooks & Examples <a id="notebooks"></a>
|
|
171
171
|
A curated set of ready-to-use jupyter notebooks that demonstrate how to use the toolkit to common fault detection tasks using the 3W dataset. These examples accelerate onboarding and reproducibility.
|
|
172
172
|
|
|
173
|
-
The set of notebooks can be found in the [notebooks folder](
|
|
173
|
+
The set of notebooks can be found in the [notebooks folder](https://github.com/petrobras/3W/tree/main/toolkit/demos)
|
|
174
174
|
|
|
175
175
|
|
|
176
176
|
## 🤝 Contributing <a id="contributing"></a>
|
|
177
177
|
|
|
178
|
-
We welcome contributions to help us improve and expand the functionality of the 3W toolkit. To ensure a smooth collaboration process, please follow our contrubuting guidelines [here](
|
|
178
|
+
We welcome contributions to help us improve and expand the functionality of the 3W toolkit. To ensure a smooth collaboration process, please follow our contrubuting guidelines [here](https://github.com/petrobras/3W/blob/main/CONTRIBUTING.md).
|
|
179
179
|
|
|
180
180
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ThreeWToolkit"
|
|
3
|
-
version = "3.1
|
|
3
|
+
version = "3.2.1"
|
|
4
4
|
description = "A modular and open-source AI toolkit for time-series processing, aimed at fault detection and classification in oil well operation"
|
|
5
5
|
readme = { file = "toolkit/ThreeWToolkit/README.md", content-type = "text/markdown" }
|
|
6
6
|
license = { text = "Apache-2.0" }
|
|
@@ -63,7 +63,7 @@ To better understand how the system is organized, we can divide all classes into
|
|
|
63
63
|
## 📊 3W Dataset <a id="dataset"></a>
|
|
64
64
|
The **3W dataset** serves as a **reference dataset** for this project and is hosted on [Figshare](https://figshare.com/projects/3W_Dataset/251195). However, the toolkit is not limited to the 3W dataset and can be adapted for other datasets as well.
|
|
65
65
|
|
|
66
|
-
Further details on the 3W dataset’s structure, preprocessing, and usage are available in the [3W_DATASET_STRUCTURE.md](
|
|
66
|
+
Further details on the 3W dataset’s structure, preprocessing, and usage are available in the [3W_DATASET_STRUCTURE.md](https://github.com/petrobras/3W/blob/main/3W_DATASET_STRUCTURE.md) file.
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
## ⚙️ Installation & Setup <a id="installation"></a>
|
|
@@ -106,11 +106,11 @@ conda activate 3W
|
|
|
106
106
|
## 🪐 Jupyter Notebooks & Examples <a id="notebooks"></a>
|
|
107
107
|
A curated set of ready-to-use jupyter notebooks that demonstrate how to use the toolkit to common fault detection tasks using the 3W dataset. These examples accelerate onboarding and reproducibility.
|
|
108
108
|
|
|
109
|
-
The set of notebooks can be found in the [notebooks folder](
|
|
109
|
+
The set of notebooks can be found in the [notebooks folder](https://github.com/petrobras/3W/tree/main/toolkit/demos)
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
## 🤝 Contributing <a id="contributing"></a>
|
|
113
113
|
|
|
114
|
-
We welcome contributions to help us improve and expand the functionality of the 3W toolkit. To ensure a smooth collaboration process, please follow our contrubuting guidelines [here](
|
|
114
|
+
We welcome contributions to help us improve and expand the functionality of the 3W toolkit. To ensure a smooth collaboration process, please follow our contrubuting guidelines [here](https://github.com/petrobras/3W/blob/main/CONTRIBUTING.md).
|
|
115
115
|
|
|
116
116
|
|
{threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/assessment/model_assess.py
RENAMED
|
@@ -26,6 +26,7 @@ from ..metrics import (
|
|
|
26
26
|
f1_score,
|
|
27
27
|
average_precision_score,
|
|
28
28
|
explained_variance_score,
|
|
29
|
+
matthews_corrcoef,
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
logger = logging.getLogger(__name__)
|
|
@@ -51,6 +52,7 @@ class MetricRegistry:
|
|
|
51
52
|
if len(np.unique(y)) > 1
|
|
52
53
|
else 0.0
|
|
53
54
|
),
|
|
55
|
+
"matthews_corrcoef": matthews_corrcoef,
|
|
54
56
|
},
|
|
55
57
|
TaskTypeEnum.REGRESSION: {
|
|
56
58
|
"explained_variance": explained_variance_score,
|
|
@@ -6,6 +6,7 @@ from ._classification import (
|
|
|
6
6
|
recall_score,
|
|
7
7
|
f1_score,
|
|
8
8
|
roc_auc_score,
|
|
9
|
+
matthews_corrcoef,
|
|
9
10
|
)
|
|
10
11
|
|
|
11
12
|
from ._regression import explained_variance_score
|
|
@@ -18,5 +19,6 @@ __all__ = [
|
|
|
18
19
|
"recall_score",
|
|
19
20
|
"f1_score",
|
|
20
21
|
"roc_auc_score",
|
|
22
|
+
"matthews_corrcoef",
|
|
21
23
|
"explained_variance_score",
|
|
22
24
|
]
|
{threewtoolkit-3.1.0 → threewtoolkit-3.2.1}/toolkit/ThreeWToolkit/metrics/_classification.py
RENAMED
|
@@ -9,6 +9,7 @@ from sklearn.metrics import (
|
|
|
9
9
|
recall_score as sk_recall,
|
|
10
10
|
f1_score as sk_f1,
|
|
11
11
|
roc_auc_score as sk_roc_auc,
|
|
12
|
+
matthews_corrcoef as sk_mcc,
|
|
12
13
|
)
|
|
13
14
|
from sklearn.preprocessing import label_binarize
|
|
14
15
|
|
|
@@ -287,3 +288,39 @@ def roc_auc_score(
|
|
|
287
288
|
multi_class=multi_class,
|
|
288
289
|
labels=labels,
|
|
289
290
|
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@validate_call(config=_validate_config)
|
|
294
|
+
def matthews_corrcoef(
|
|
295
|
+
y_true: np.ndarray | pd.Series | list,
|
|
296
|
+
y_pred: np.ndarray | pd.Series | list,
|
|
297
|
+
sample_weight: np.ndarray | pd.Series | list | None = None,
|
|
298
|
+
) -> float:
|
|
299
|
+
"""
|
|
300
|
+
Calculates the Matthews Correlation Coefficient (MCC).
|
|
301
|
+
|
|
302
|
+
MCC is a balanced metric for evaluating classification models,
|
|
303
|
+
particularly useful for imbalanced datasets. Its value ranges
|
|
304
|
+
from -1 to 1:
|
|
305
|
+
|
|
306
|
+
- 1: Perfect prediction
|
|
307
|
+
- 0: Random prediction
|
|
308
|
+
- -1: Total disagreement between prediction and truth
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
y_true: True labels.
|
|
312
|
+
y_pred: Predicted labels.
|
|
313
|
+
sample_weight: Sample weights. Default is None.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
The calculated MCC value.
|
|
317
|
+
|
|
318
|
+
Raises:
|
|
319
|
+
TypeError: If any argument has an invalid type.
|
|
320
|
+
ValueError: If array dimensions are incompatible.
|
|
321
|
+
"""
|
|
322
|
+
return sk_mcc(
|
|
323
|
+
y_true=y_true,
|
|
324
|
+
y_pred=y_pred,
|
|
325
|
+
sample_weight=sample_weight,
|
|
326
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ThreeWToolkit
|
|
3
|
-
Version: 3.1
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: A modular and open-source AI toolkit for time-series processing, aimed at fault detection and classification in oil well operation
|
|
5
5
|
Author-email: Ricardo Emanuel Vaz Vargas <ricardo.vargas@petrobras.com.br>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -127,7 +127,7 @@ To better understand how the system is organized, we can divide all classes into
|
|
|
127
127
|
## 📊 3W Dataset <a id="dataset"></a>
|
|
128
128
|
The **3W dataset** serves as a **reference dataset** for this project and is hosted on [Figshare](https://figshare.com/projects/3W_Dataset/251195). However, the toolkit is not limited to the 3W dataset and can be adapted for other datasets as well.
|
|
129
129
|
|
|
130
|
-
Further details on the 3W dataset’s structure, preprocessing, and usage are available in the [3W_DATASET_STRUCTURE.md](
|
|
130
|
+
Further details on the 3W dataset’s structure, preprocessing, and usage are available in the [3W_DATASET_STRUCTURE.md](https://github.com/petrobras/3W/blob/main/3W_DATASET_STRUCTURE.md) file.
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
## ⚙️ Installation & Setup <a id="installation"></a>
|
|
@@ -170,11 +170,11 @@ conda activate 3W
|
|
|
170
170
|
## 🪐 Jupyter Notebooks & Examples <a id="notebooks"></a>
|
|
171
171
|
A curated set of ready-to-use jupyter notebooks that demonstrate how to use the toolkit to common fault detection tasks using the 3W dataset. These examples accelerate onboarding and reproducibility.
|
|
172
172
|
|
|
173
|
-
The set of notebooks can be found in the [notebooks folder](
|
|
173
|
+
The set of notebooks can be found in the [notebooks folder](https://github.com/petrobras/3W/tree/main/toolkit/demos)
|
|
174
174
|
|
|
175
175
|
|
|
176
176
|
## 🤝 Contributing <a id="contributing"></a>
|
|
177
177
|
|
|
178
|
-
We welcome contributions to help us improve and expand the functionality of the 3W toolkit. To ensure a smooth collaboration process, please follow our contrubuting guidelines [here](
|
|
178
|
+
We welcome contributions to help us improve and expand the functionality of the 3W toolkit. To ensure a smooth collaboration process, please follow our contrubuting guidelines [here](https://github.com/petrobras/3W/blob/main/CONTRIBUTING.md).
|
|
179
179
|
|
|
180
180
|
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
LICENSE.md
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
|
-
tests/test_clustering_models.py
|
|
5
|
-
tests/test_clustering_plots.py
|
|
6
|
-
tests/test_dataset.py
|
|
7
|
-
tests/test_distance_computer.py
|
|
8
|
-
tests/test_instance_quality_filter.py
|
|
9
|
-
tests/test_report_generation.py
|
|
10
|
-
tests/test_time_series_resampler.py
|
|
11
4
|
toolkit/ThreeWToolkit/README.md
|
|
12
5
|
toolkit/ThreeWToolkit/__init__.py
|
|
13
6
|
toolkit/ThreeWToolkit/constants.py
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
import numpy as np
|
|
3
|
-
from pydantic import ValidationError
|
|
4
|
-
|
|
5
|
-
from ThreeWToolkit.core.base_clustering import (
|
|
6
|
-
HierarchicalClusteringConfig,
|
|
7
|
-
DivisiveClusteringConfig,
|
|
8
|
-
MultivariateConsensusConfig,
|
|
9
|
-
)
|
|
10
|
-
from ThreeWToolkit.core.enums import LinkageMethodEnum
|
|
11
|
-
from ThreeWToolkit.clustering import (
|
|
12
|
-
HierarchicalClusterer,
|
|
13
|
-
DivisiveRanker,
|
|
14
|
-
MultivariateConsensus,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class TestHierarchicalClusterer:
|
|
19
|
-
"""Test suite for HierarchicalClusterer estimator."""
|
|
20
|
-
|
|
21
|
-
@pytest.fixture
|
|
22
|
-
def distance_matrix(self):
|
|
23
|
-
"""Two tight pairs: (0,1) and (2,3)."""
|
|
24
|
-
return np.array(
|
|
25
|
-
[
|
|
26
|
-
[0.0, 1.0, 5.0, 6.0],
|
|
27
|
-
[1.0, 0.0, 4.0, 5.0],
|
|
28
|
-
[5.0, 4.0, 0.0, 2.0],
|
|
29
|
-
[6.0, 5.0, 2.0, 0.0],
|
|
30
|
-
]
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
@pytest.fixture
|
|
34
|
-
def config(self):
|
|
35
|
-
return HierarchicalClusteringConfig(
|
|
36
|
-
linkage_method=LinkageMethodEnum.AVERAGE,
|
|
37
|
-
default_threshold=0.5,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
@pytest.fixture
|
|
41
|
-
def fitted_clusterer(self, config, distance_matrix):
|
|
42
|
-
clusterer = HierarchicalClusterer(config)
|
|
43
|
-
clusterer.fit(distance_matrix)
|
|
44
|
-
return clusterer
|
|
45
|
-
|
|
46
|
-
def test_fit_returns_self(self, config, distance_matrix):
|
|
47
|
-
clusterer = HierarchicalClusterer(config)
|
|
48
|
-
result = clusterer.fit(distance_matrix)
|
|
49
|
-
assert result is clusterer
|
|
50
|
-
|
|
51
|
-
def test_linkage_matrix_stored(self, fitted_clusterer):
|
|
52
|
-
assert fitted_clusterer.linkage_matrix_ is not None
|
|
53
|
-
assert fitted_clusterer.linkage_matrix_.ndim == 2
|
|
54
|
-
assert fitted_clusterer.linkage_matrix_.shape[1] == 4
|
|
55
|
-
|
|
56
|
-
def test_distance_matrix_normalized(self, fitted_clusterer):
|
|
57
|
-
assert fitted_clusterer.distance_matrix_normalized_ is not None
|
|
58
|
-
assert fitted_clusterer.distance_matrix_normalized_.max() <= 1.0
|
|
59
|
-
|
|
60
|
-
def test_clusters_at_low_threshold(self, fitted_clusterer):
|
|
61
|
-
"""At a very low threshold, each instance is its own cluster."""
|
|
62
|
-
labels = fitted_clusterer.get_clusters_at_threshold(0.01)
|
|
63
|
-
assert len(labels) == 4
|
|
64
|
-
assert len(set(labels)) == 4
|
|
65
|
-
|
|
66
|
-
def test_clusters_at_high_threshold(self, fitted_clusterer):
|
|
67
|
-
"""At a high threshold, all instances merge into one cluster."""
|
|
68
|
-
labels = fitted_clusterer.get_clusters_at_threshold(1.0)
|
|
69
|
-
assert len(labels) == 4
|
|
70
|
-
assert len(set(labels)) == 1
|
|
71
|
-
|
|
72
|
-
def test_find_main_cluster_indices(self, fitted_clusterer):
|
|
73
|
-
indices = fitted_clusterer.find_main_cluster_indices(1.0)
|
|
74
|
-
assert sorted(indices) == [0, 1, 2, 3]
|
|
75
|
-
|
|
76
|
-
def test_raises_before_fit(self, config):
|
|
77
|
-
clusterer = HierarchicalClusterer(config)
|
|
78
|
-
with pytest.raises(RuntimeError, match="must be fitted"):
|
|
79
|
-
clusterer.get_clusters_at_threshold(0.5)
|
|
80
|
-
|
|
81
|
-
def test_zero_distance_matrix(self, config):
|
|
82
|
-
"""All-zero distance matrix should not crash."""
|
|
83
|
-
zeros = np.zeros((3, 3))
|
|
84
|
-
clusterer = HierarchicalClusterer(config)
|
|
85
|
-
clusterer.fit(zeros)
|
|
86
|
-
labels = clusterer.get_clusters_at_threshold(0.5)
|
|
87
|
-
assert len(labels) == 3
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
class TestDivisiveRanker:
|
|
91
|
-
"""Test suite for DivisiveRanker estimator."""
|
|
92
|
-
|
|
93
|
-
@pytest.fixture
|
|
94
|
-
def distance_matrix(self):
|
|
95
|
-
"""Instance 2 is the outlier (highest total distance)."""
|
|
96
|
-
return np.array(
|
|
97
|
-
[
|
|
98
|
-
[0.0, 1.0, 10.0],
|
|
99
|
-
[1.0, 0.0, 9.0],
|
|
100
|
-
[10.0, 9.0, 0.0],
|
|
101
|
-
]
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
@pytest.fixture
|
|
105
|
-
def config(self):
|
|
106
|
-
return DivisiveClusteringConfig()
|
|
107
|
-
|
|
108
|
-
@pytest.fixture
|
|
109
|
-
def fitted_ranker(self, config, distance_matrix):
|
|
110
|
-
ranker = DivisiveRanker(config)
|
|
111
|
-
ranker.fit(distance_matrix)
|
|
112
|
-
return ranker
|
|
113
|
-
|
|
114
|
-
def test_fit_returns_self(self, config, distance_matrix):
|
|
115
|
-
ranker = DivisiveRanker(config)
|
|
116
|
-
result = ranker.fit(distance_matrix)
|
|
117
|
-
assert result is ranker
|
|
118
|
-
|
|
119
|
-
def test_ranking_length_matches_instances(self, fitted_ranker):
|
|
120
|
-
ranking = fitted_ranker.get_ranked_indices()
|
|
121
|
-
assert len(ranking) == 3
|
|
122
|
-
|
|
123
|
-
def test_ranking_contains_all_indices(self, fitted_ranker):
|
|
124
|
-
ranking = fitted_ranker.get_ranked_indices()
|
|
125
|
-
assert sorted(ranking) == [0, 1, 2]
|
|
126
|
-
|
|
127
|
-
def test_outlier_eliminated_first(self, fitted_ranker):
|
|
128
|
-
"""Instance 2 has the largest distance sum and should be eliminated first."""
|
|
129
|
-
ranking = fitted_ranker.get_ranked_indices()
|
|
130
|
-
assert ranking[0] == 2
|
|
131
|
-
|
|
132
|
-
def test_elimination_distances_length(self, fitted_ranker):
|
|
133
|
-
assert len(fitted_ranker.elimination_distances_) == 3
|
|
134
|
-
|
|
135
|
-
def test_last_elimination_distance_is_zero(self, fitted_ranker):
|
|
136
|
-
assert fitted_ranker.elimination_distances_[-1] == 0.0
|
|
137
|
-
|
|
138
|
-
def test_raises_before_fit(self, config):
|
|
139
|
-
ranker = DivisiveRanker(config)
|
|
140
|
-
with pytest.raises(RuntimeError, match="must be fitted"):
|
|
141
|
-
ranker.get_ranked_indices()
|
|
142
|
-
|
|
143
|
-
def test_raises_on_non_square_matrix(self, config):
|
|
144
|
-
ranker = DivisiveRanker(config)
|
|
145
|
-
with pytest.raises(ValueError, match="2D square"):
|
|
146
|
-
ranker.fit(np.array([[1.0, 2.0]]))
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
class TestMultivariateConsensus:
|
|
150
|
-
"""Test suite for MultivariateConsensus estimator."""
|
|
151
|
-
|
|
152
|
-
@pytest.fixture
|
|
153
|
-
def config(self):
|
|
154
|
-
return MultivariateConsensusConfig(
|
|
155
|
-
min_threshold=0.1,
|
|
156
|
-
max_threshold=1.0,
|
|
157
|
-
threshold_step=0.1,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
@pytest.fixture
|
|
161
|
-
def fitted_hierarchical_models(self):
|
|
162
|
-
"""Build two fitted HierarchicalClusterers for two variables."""
|
|
163
|
-
cfg = HierarchicalClusteringConfig(
|
|
164
|
-
linkage_method=LinkageMethodEnum.AVERAGE,
|
|
165
|
-
default_threshold=0.5,
|
|
166
|
-
)
|
|
167
|
-
# Variable A: instances 0,1 are close; instance 2 is far
|
|
168
|
-
dm_a = np.array(
|
|
169
|
-
[
|
|
170
|
-
[0.0, 1.0, 10.0],
|
|
171
|
-
[1.0, 0.0, 9.0],
|
|
172
|
-
[10.0, 9.0, 0.0],
|
|
173
|
-
]
|
|
174
|
-
)
|
|
175
|
-
model_a = HierarchicalClusterer(cfg)
|
|
176
|
-
model_a.fit(dm_a)
|
|
177
|
-
|
|
178
|
-
# Variable B: similar structure
|
|
179
|
-
dm_b = np.array(
|
|
180
|
-
[
|
|
181
|
-
[0.0, 2.0, 8.0],
|
|
182
|
-
[2.0, 0.0, 7.0],
|
|
183
|
-
[8.0, 7.0, 0.0],
|
|
184
|
-
]
|
|
185
|
-
)
|
|
186
|
-
model_b = HierarchicalClusterer(cfg)
|
|
187
|
-
model_b.fit(dm_b)
|
|
188
|
-
|
|
189
|
-
return {"var_A": model_a, "var_B": model_b}
|
|
190
|
-
|
|
191
|
-
def test_fit_returns_self(self, config, fitted_hierarchical_models):
|
|
192
|
-
consensus = MultivariateConsensus(config)
|
|
193
|
-
result = consensus.fit(fitted_hierarchical_models)
|
|
194
|
-
assert result is consensus
|
|
195
|
-
|
|
196
|
-
def test_selection_mask_shape(self, config, fitted_hierarchical_models):
|
|
197
|
-
consensus = MultivariateConsensus(config)
|
|
198
|
-
consensus.fit(fitted_hierarchical_models)
|
|
199
|
-
|
|
200
|
-
n_thresholds = len(consensus.thresholds_analyzed_)
|
|
201
|
-
assert consensus.selection_mask_.shape[0] == n_thresholds
|
|
202
|
-
assert consensus.selection_mask_.shape[1] > 0
|
|
203
|
-
|
|
204
|
-
def test_common_counts_populated(self, config, fitted_hierarchical_models):
|
|
205
|
-
consensus = MultivariateConsensus(config)
|
|
206
|
-
consensus.fit(fitted_hierarchical_models)
|
|
207
|
-
|
|
208
|
-
assert len(consensus.common_counts_) == len(consensus.thresholds_analyzed_)
|
|
209
|
-
|
|
210
|
-
def test_high_threshold_selects_all(self, config, fitted_hierarchical_models):
|
|
211
|
-
consensus = MultivariateConsensus(config)
|
|
212
|
-
consensus.fit(fitted_hierarchical_models)
|
|
213
|
-
|
|
214
|
-
selected = consensus.get_selected_indices_at_threshold(1.0)
|
|
215
|
-
assert len(selected) == 3
|
|
216
|
-
|
|
217
|
-
def test_low_threshold_selects_fewer(self, config, fitted_hierarchical_models):
|
|
218
|
-
consensus = MultivariateConsensus(config)
|
|
219
|
-
consensus.fit(fitted_hierarchical_models)
|
|
220
|
-
|
|
221
|
-
selected_low = consensus.get_selected_indices_at_threshold(0.1)
|
|
222
|
-
selected_high = consensus.get_selected_indices_at_threshold(1.0)
|
|
223
|
-
assert len(selected_low) <= len(selected_high)
|
|
224
|
-
|
|
225
|
-
def test_raises_before_fit(self, config):
|
|
226
|
-
consensus = MultivariateConsensus(config)
|
|
227
|
-
with pytest.raises(RuntimeError, match="not fitted"):
|
|
228
|
-
consensus.get_selected_indices_at_threshold(0.5)
|
|
229
|
-
|
|
230
|
-
def test_with_valid_indices_map(self, config, fitted_hierarchical_models):
|
|
231
|
-
valid_indices = {
|
|
232
|
-
"var_A": [0, 1, 2],
|
|
233
|
-
"var_B": [0, 1, 2],
|
|
234
|
-
}
|
|
235
|
-
consensus = MultivariateConsensus(config)
|
|
236
|
-
consensus.fit(
|
|
237
|
-
fitted_hierarchical_models,
|
|
238
|
-
valid_indices_map=valid_indices,
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
assert consensus._is_fitted
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
class TestMultivariateConsensusConfig:
|
|
245
|
-
"""Test suite for MultivariateConsensusConfig validation."""
|
|
246
|
-
|
|
247
|
-
def test_default_values(self):
|
|
248
|
-
config = MultivariateConsensusConfig()
|
|
249
|
-
assert config.min_threshold == 0.1
|
|
250
|
-
assert config.max_threshold == 1.0
|
|
251
|
-
assert config.threshold_step == 0.1
|
|
252
|
-
|
|
253
|
-
def test_max_must_be_greater_than_min(self):
|
|
254
|
-
with pytest.raises(ValidationError, match="max_threshold"):
|
|
255
|
-
MultivariateConsensusConfig(
|
|
256
|
-
min_threshold=0.5,
|
|
257
|
-
max_threshold=0.3,
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
def test_equal_min_max_rejected(self):
|
|
261
|
-
with pytest.raises(ValidationError, match="max_threshold"):
|
|
262
|
-
MultivariateConsensusConfig(
|
|
263
|
-
min_threshold=0.5,
|
|
264
|
-
max_threshold=0.5,
|
|
265
|
-
)
|