pg-sui 1.0.2.1__py3-none-any.whl → 1.6.8__py3-none-any.whl
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.
Potentially problematic release.
This version of pg-sui might be problematic. Click here for more details.
- {pg_sui-1.0.2.1.dist-info → pg_sui-1.6.8.dist-info}/METADATA +51 -70
- pg_sui-1.6.8.dist-info/RECORD +78 -0
- {pg_sui-1.0.2.1.dist-info → pg_sui-1.6.8.dist-info}/WHEEL +1 -1
- pg_sui-1.6.8.dist-info/entry_points.txt +4 -0
- pg_sui-1.6.8.dist-info/top_level.txt +1 -0
- pgsui/__init__.py +35 -54
- pgsui/_version.py +34 -0
- pgsui/cli.py +635 -0
- pgsui/data_processing/config.py +576 -0
- pgsui/data_processing/containers.py +1782 -0
- pgsui/data_processing/transformers.py +121 -1103
- pgsui/electron/app/__main__.py +5 -0
- pgsui/electron/app/icons/icons/1024x1024.png +0 -0
- pgsui/electron/app/icons/icons/128x128.png +0 -0
- pgsui/electron/app/icons/icons/16x16.png +0 -0
- pgsui/electron/app/icons/icons/24x24.png +0 -0
- pgsui/electron/app/icons/icons/256x256.png +0 -0
- pgsui/electron/app/icons/icons/32x32.png +0 -0
- pgsui/electron/app/icons/icons/48x48.png +0 -0
- pgsui/electron/app/icons/icons/512x512.png +0 -0
- pgsui/electron/app/icons/icons/64x64.png +0 -0
- pgsui/electron/app/icons/icons/icon.icns +0 -0
- pgsui/electron/app/icons/icons/icon.ico +0 -0
- pgsui/electron/app/main.js +189 -0
- pgsui/electron/app/package-lock.json +6893 -0
- pgsui/electron/app/package.json +50 -0
- pgsui/electron/app/preload.js +15 -0
- pgsui/electron/app/server.py +146 -0
- pgsui/electron/app/ui/logo.png +0 -0
- pgsui/electron/app/ui/renderer.js +130 -0
- pgsui/electron/app/ui/styles.css +59 -0
- pgsui/electron/app/ui/ui_shim.js +72 -0
- pgsui/electron/bootstrap.py +43 -0
- pgsui/electron/launch.py +59 -0
- pgsui/electron/package.json +14 -0
- pgsui/example_data/popmaps/{test.popmap → phylogen_nomx.popmap} +185 -99
- pgsui/example_data/vcf_files/phylogen_subset14K.vcf.gz +0 -0
- pgsui/example_data/vcf_files/phylogen_subset14K.vcf.gz.tbi +0 -0
- pgsui/impute/deterministic/imputers/allele_freq.py +691 -0
- pgsui/impute/deterministic/imputers/mode.py +679 -0
- pgsui/impute/deterministic/imputers/nmf.py +221 -0
- pgsui/impute/deterministic/imputers/phylo.py +971 -0
- pgsui/impute/deterministic/imputers/ref_allele.py +530 -0
- pgsui/impute/supervised/base.py +339 -0
- pgsui/impute/supervised/imputers/hist_gradient_boosting.py +293 -0
- pgsui/impute/supervised/imputers/random_forest.py +287 -0
- pgsui/impute/unsupervised/base.py +924 -0
- pgsui/impute/unsupervised/callbacks.py +89 -263
- pgsui/impute/unsupervised/imputers/autoencoder.py +972 -0
- pgsui/impute/unsupervised/imputers/nlpca.py +1264 -0
- pgsui/impute/unsupervised/imputers/ubp.py +1288 -0
- pgsui/impute/unsupervised/imputers/vae.py +957 -0
- pgsui/impute/unsupervised/loss_functions.py +158 -0
- pgsui/impute/unsupervised/models/autoencoder_model.py +208 -558
- pgsui/impute/unsupervised/models/nlpca_model.py +149 -468
- pgsui/impute/unsupervised/models/ubp_model.py +198 -1317
- pgsui/impute/unsupervised/models/vae_model.py +259 -618
- pgsui/impute/unsupervised/nn_scorers.py +215 -0
- pgsui/utils/classification_viz.py +591 -0
- pgsui/utils/misc.py +35 -480
- pgsui/utils/plotting.py +514 -824
- pgsui/utils/scorers.py +212 -438
- pg_sui-1.0.2.1.dist-info/RECORD +0 -75
- pg_sui-1.0.2.1.dist-info/top_level.txt +0 -3
- pgsui/example_data/phylip_files/test_n10.phy +0 -118
- pgsui/example_data/phylip_files/test_n100.phy +0 -118
- pgsui/example_data/phylip_files/test_n2.phy +0 -118
- pgsui/example_data/phylip_files/test_n500.phy +0 -118
- pgsui/example_data/structure_files/test.nopops.1row.10sites.str +0 -117
- pgsui/example_data/structure_files/test.nopops.2row.100sites.str +0 -234
- pgsui/example_data/structure_files/test.nopops.2row.10sites.str +0 -234
- pgsui/example_data/structure_files/test.nopops.2row.30sites.str +0 -234
- pgsui/example_data/structure_files/test.nopops.2row.allsites.str +0 -234
- pgsui/example_data/structure_files/test.pops.1row.10sites.str +0 -117
- pgsui/example_data/structure_files/test.pops.2row.10sites.str +0 -234
- pgsui/example_data/trees/test.iqtree +0 -376
- pgsui/example_data/trees/test.qmat +0 -5
- pgsui/example_data/trees/test.rate +0 -2033
- pgsui/example_data/trees/test.tre +0 -1
- pgsui/example_data/trees/test_n10.rate +0 -19
- pgsui/example_data/trees/test_n100.rate +0 -109
- pgsui/example_data/trees/test_n500.rate +0 -509
- pgsui/example_data/trees/test_siterates.txt +0 -2024
- pgsui/example_data/trees/test_siterates_n10.txt +0 -10
- pgsui/example_data/trees/test_siterates_n100.txt +0 -100
- pgsui/example_data/trees/test_siterates_n500.txt +0 -500
- pgsui/example_data/vcf_files/test.vcf +0 -244
- pgsui/example_data/vcf_files/test.vcf.gz +0 -0
- pgsui/example_data/vcf_files/test.vcf.gz.tbi +0 -0
- pgsui/impute/estimators.py +0 -735
- pgsui/impute/impute.py +0 -1486
- pgsui/impute/simple_imputers.py +0 -1439
- pgsui/impute/supervised/iterative_imputer_fixedparams.py +0 -785
- pgsui/impute/supervised/iterative_imputer_gridsearch.py +0 -1027
- pgsui/impute/unsupervised/keras_classifiers.py +0 -702
- pgsui/impute/unsupervised/models/in_development/cnn_model.py +0 -486
- pgsui/impute/unsupervised/neural_network_imputers.py +0 -1424
- pgsui/impute/unsupervised/neural_network_methods.py +0 -1549
- pgsui/pg_sui.py +0 -261
- pgsui/utils/sequence_tools.py +0 -407
- simulation/sim_benchmarks.py +0 -333
- simulation/sim_treeparams.py +0 -475
- test/__init__.py +0 -0
- test/pg_sui_simtest.py +0 -215
- test/pg_sui_testing.py +0 -523
- test/test.py +0 -297
- test/test_pgsui.py +0 -374
- test/test_tkc.py +0 -214
- {pg_sui-1.0.2.1.dist-info → pg_sui-1.6.8.dist-info/licenses}/LICENSE +0 -0
- /pgsui/{example_data/trees → electron/app}/__init__.py +0 -0
- /pgsui/impute/{unsupervised/models/in_development → supervised/imputers}/__init__.py +0 -0
- {simulation → pgsui/impute/unsupervised/imputers}/__init__.py +0 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from typing import Dict, Literal
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from sklearn.metrics import (
|
|
5
|
+
accuracy_score,
|
|
6
|
+
average_precision_score,
|
|
7
|
+
f1_score,
|
|
8
|
+
precision_score,
|
|
9
|
+
recall_score,
|
|
10
|
+
roc_auc_score,
|
|
11
|
+
)
|
|
12
|
+
from snpio.utils.logging import LoggerManager
|
|
13
|
+
from torch import Tensor
|
|
14
|
+
|
|
15
|
+
from pgsui.utils.misc import validate_input_type
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Scorer:
|
|
19
|
+
"""Class for evaluating the performance of a model using various metrics.
|
|
20
|
+
|
|
21
|
+
This module provides a unified interface for computing common evaluation metrics. It supports accuracy, F1 score, precision, recall, ROC AUC, average precision, and macro-average precision. The class can handle both raw and one-hot encoded labels and includes options for logging and averaging methods.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
prefix: str,
|
|
27
|
+
average: Literal["weighted", "macro", "micro"] = "macro",
|
|
28
|
+
verbose: bool = False,
|
|
29
|
+
debug: bool = False,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Initialize a Scorer object.
|
|
32
|
+
|
|
33
|
+
This class provides a unified interface for computing common evaluation metrics. It supports accuracy, F1 score, precision, recall, ROC AUC, average precision, and macro-average precision. The class can handle both raw and one-hot encoded labels and includes options for logging and averaging methods.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
prefix (str): The prefix to use for logging.
|
|
37
|
+
average (Literal["weighted", "macro", "micro"]): The averaging method to use for metrics. Must be one of 'micro', 'macro', or 'weighted'. Defaults to 'weighted'.
|
|
38
|
+
verbose (bool): If True, enable verbose logging. Defaults to False.
|
|
39
|
+
debug (bool): If True, enable debug logging. Defaults to False.
|
|
40
|
+
"""
|
|
41
|
+
logman = LoggerManager(
|
|
42
|
+
name=__name__, prefix=prefix, debug=debug, verbose=verbose
|
|
43
|
+
)
|
|
44
|
+
self.logger = logman.get_logger()
|
|
45
|
+
|
|
46
|
+
if average not in {"micro", "macro", "weighted"}:
|
|
47
|
+
msg = f"Invalid average parameter: {average}. Must be one of 'micro', 'macro', or 'weighted'."
|
|
48
|
+
self.logger.error(msg)
|
|
49
|
+
raise ValueError(msg)
|
|
50
|
+
|
|
51
|
+
self.average = average
|
|
52
|
+
|
|
53
|
+
def accuracy(self, y_true: np.ndarray, y_pred: np.ndarray) -> float:
|
|
54
|
+
"""Compute the accuracy score.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
y_true (np.ndarray): Ground truth (correct) target values.
|
|
58
|
+
y_pred (np.ndarray): Estimated target values.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
float: The accuracy score.
|
|
62
|
+
"""
|
|
63
|
+
return accuracy_score(y_true, y_pred)
|
|
64
|
+
|
|
65
|
+
def f1(self, y_true: np.ndarray, y_pred: np.ndarray) -> float:
|
|
66
|
+
"""Compute the F1 score.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
y_true (np.ndarray): Ground truth (correct) target values.
|
|
70
|
+
y_pred (np.ndarray): Estimated target values.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
float: The F1 score.
|
|
74
|
+
"""
|
|
75
|
+
return f1_score(y_true, y_pred, average=self.average, zero_division=0.0)
|
|
76
|
+
|
|
77
|
+
def precision(self, y_true: np.ndarray, y_pred: np.ndarray) -> float:
|
|
78
|
+
"""Compute the precision score.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
y_true (np.ndarray): Ground truth (correct) target values.
|
|
82
|
+
y_pred (np.ndarray): Estimated target values.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
float: The precision score.
|
|
86
|
+
"""
|
|
87
|
+
return precision_score(y_true, y_pred, average=self.average, zero_division=0.0)
|
|
88
|
+
|
|
89
|
+
def recall(self, y_true: np.ndarray, y_pred: np.ndarray) -> float:
|
|
90
|
+
"""Compute the recall score.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
y_true (np.ndarray): Ground truth (correct) target values.
|
|
94
|
+
y_pred (np.ndarray): Estimated target values.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
float: The recall score.
|
|
98
|
+
"""
|
|
99
|
+
return recall_score(y_true, y_pred, average=self.average, zero_division=0.0)
|
|
100
|
+
|
|
101
|
+
def roc_auc(self, y_true: np.ndarray, y_pred_proba: np.ndarray) -> float:
|
|
102
|
+
"""Compute the ROC AUC score.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
y_true (np.ndarray): Ground truth (correct) target values.
|
|
106
|
+
y_pred_proba (np.ndarray): Predicted probabilities.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
float: The ROC AUC score.
|
|
110
|
+
"""
|
|
111
|
+
if len(np.unique(y_true)) < 2:
|
|
112
|
+
return 0.5
|
|
113
|
+
return roc_auc_score(
|
|
114
|
+
y_true, y_pred_proba, average=self.average, multi_class="ovr"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# This method now correctly expects one-hot encoded true labels
|
|
118
|
+
def average_precision(
|
|
119
|
+
self, y_true_ohe: np.ndarray, y_pred_proba: np.ndarray
|
|
120
|
+
) -> float:
|
|
121
|
+
"""Compute the average precision score.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
y_true_ohe (np.ndarray): One-hot encoded ground truth target values.
|
|
125
|
+
y_pred_proba (np.ndarray): Predicted probabilities.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
float: The average precision score.
|
|
129
|
+
"""
|
|
130
|
+
return average_precision_score(y_true_ohe, y_pred_proba, average=self.average)
|
|
131
|
+
|
|
132
|
+
def pr_macro(self, y_true_ohe: np.ndarray, y_pred_proba: np.ndarray) -> float:
|
|
133
|
+
"""Compute the macro-average precision score.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
y_true_ohe (np.ndarray): One-hot encoded ground truth target values.
|
|
137
|
+
y_pred_proba (np.ndarray): Predicted probabilities.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
float: The macro-average precision score.
|
|
141
|
+
"""
|
|
142
|
+
return average_precision_score(y_true_ohe, y_pred_proba, average="macro")
|
|
143
|
+
|
|
144
|
+
def evaluate(
|
|
145
|
+
self,
|
|
146
|
+
y_true: np.ndarray | Tensor | list,
|
|
147
|
+
y_pred: np.ndarray | Tensor | list,
|
|
148
|
+
y_true_ohe: np.ndarray | Tensor | list,
|
|
149
|
+
y_pred_proba: np.ndarray | Tensor | list,
|
|
150
|
+
objective_mode: bool = False,
|
|
151
|
+
tune_metric: Literal[
|
|
152
|
+
"pr_macro",
|
|
153
|
+
"roc_auc",
|
|
154
|
+
"average_precision",
|
|
155
|
+
"accuracy",
|
|
156
|
+
"f1",
|
|
157
|
+
"precision",
|
|
158
|
+
"recall",
|
|
159
|
+
] = "pr_macro",
|
|
160
|
+
) -> Dict[str, float]:
|
|
161
|
+
"""Evaluate the model using various metrics.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
y_true: Ground truth (correct) target values.
|
|
165
|
+
y_pred: Estimated target values.
|
|
166
|
+
y_true_ohe: One-hot encoded ground truth target values.
|
|
167
|
+
y_pred_proba: Predicted probabilities.
|
|
168
|
+
objective_mode: If True, only compute the metric specified by ``tune_metric``. Defaults to False.
|
|
169
|
+
tune_metric: The metric to optimize during tuning. Defaults to "pr_macro".
|
|
170
|
+
"""
|
|
171
|
+
y_true, y_pred, y_true_ohe, y_pred_proba = [
|
|
172
|
+
validate_input_type(x) for x in (y_true, y_pred, y_true_ohe, y_pred_proba)
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
# NOTE: This is redundant because it's handled in the calling class
|
|
176
|
+
# TODO: Remove redundancy
|
|
177
|
+
valid_mask = np.logical_and(y_true >= 0, ~np.isnan(y_true))
|
|
178
|
+
|
|
179
|
+
if not np.any(valid_mask):
|
|
180
|
+
return {tune_metric: 0.0} if objective_mode else {}
|
|
181
|
+
|
|
182
|
+
y_true = y_true[valid_mask]
|
|
183
|
+
y_pred = y_pred[valid_mask]
|
|
184
|
+
y_true_ohe = y_true_ohe[valid_mask]
|
|
185
|
+
y_pred_proba = y_pred_proba[valid_mask]
|
|
186
|
+
|
|
187
|
+
if objective_mode:
|
|
188
|
+
metric_calculators = {
|
|
189
|
+
"pr_macro": lambda: self.pr_macro(y_true_ohe, y_pred_proba),
|
|
190
|
+
"roc_auc": lambda: self.roc_auc(y_true, y_pred_proba),
|
|
191
|
+
"average_precision": lambda: self.average_precision(
|
|
192
|
+
y_true_ohe, y_pred_proba
|
|
193
|
+
),
|
|
194
|
+
"accuracy": lambda: self.accuracy(y_true, y_pred),
|
|
195
|
+
"f1": lambda: self.f1(y_true, y_pred),
|
|
196
|
+
"precision": lambda: self.precision(y_true, y_pred),
|
|
197
|
+
"recall": lambda: self.recall(y_true, y_pred),
|
|
198
|
+
}
|
|
199
|
+
if tune_metric not in metric_calculators:
|
|
200
|
+
msg = f"Invalid tune_metric provided: '{tune_metric}'."
|
|
201
|
+
self.logger.error(msg)
|
|
202
|
+
raise ValueError(msg)
|
|
203
|
+
|
|
204
|
+
metrics = {tune_metric: metric_calculators[tune_metric]()}
|
|
205
|
+
else:
|
|
206
|
+
metrics = {
|
|
207
|
+
"accuracy": self.accuracy(y_true, y_pred),
|
|
208
|
+
"f1": self.f1(y_true, y_pred),
|
|
209
|
+
"precision": self.precision(y_true, y_pred),
|
|
210
|
+
"recall": self.recall(y_true, y_pred),
|
|
211
|
+
"roc_auc": self.roc_auc(y_true, y_pred_proba),
|
|
212
|
+
"average_precision": self.average_precision(y_true_ohe, y_pred_proba),
|
|
213
|
+
"pr_macro": self.pr_macro(y_true_ohe, y_pred_proba),
|
|
214
|
+
}
|
|
215
|
+
return {k: float(v) for k, v in metrics.items()}
|