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
1 change: 1 addition & 0 deletions glide/confidence_intervals/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__(self, bootstrap_estimates: NDArray, confidence_level: float = 0.95)

@property
def confidence_level(self) -> float:
"""Confidence level of the interval; setting it recomputes the bounds."""
return self._confidence_level

@confidence_level.setter
Expand Down
1 change: 1 addition & 0 deletions glide/confidence_intervals/clt.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self, mean: float, std: float, confidence_level: float = 0.95) -> N

@property
def confidence_level(self) -> float:
"""Confidence level of the interval; setting it recomputes the bounds."""
return self._confidence_level

@confidence_level.setter
Expand Down
6 changes: 3 additions & 3 deletions glide/engines/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@


class MeanEstimationEngine(Protocol[DatasetT, TuningParameterT]):
def preprocess(self, **fields: NDArray) -> DatasetT: ...
def _preprocess(self, **fields: NDArray) -> DatasetT: ...

def fit_tuning_parameter(self, dataset: DatasetT, *, power_tuning: bool) -> TuningParameterT: ...
def _fit_tuning_parameter(self, dataset: DatasetT, *, power_tuning: bool) -> TuningParameterT: ...

def compute_mean_and_std(self, dataset: DatasetT, tuning_parameter: TuningParameterT) -> Tuple[float, float]: ...
def _compute_mean_and_std(self, dataset: DatasetT, tuning_parameter: TuningParameterT) -> Tuple[float, float]: ...
6 changes: 3 additions & 3 deletions glide/engines/classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@


class ClassicalMeanEngine:
def preprocess(self, y: NDArray) -> NDArray:
def _preprocess(self, y: NDArray) -> NDArray:
not_nan_mask = ~np.isnan(y)
y_valid = y[not_nan_mask]
_validate_min_samples(y_valid, "y")
return y_valid

def fit_tuning_parameter(self, dataset: NDArray, *, power_tuning: bool) -> None:
def _fit_tuning_parameter(self, dataset: NDArray, *, power_tuning: bool) -> None:
return None

def compute_mean_and_std(self, dataset: NDArray, tuning_parameter: None) -> Tuple[float, float]:
def _compute_mean_and_std(self, dataset: NDArray, tuning_parameter: None) -> Tuple[float, float]:
n_samples = len(dataset)
mean = np.mean(dataset)
std = np.std(dataset, ddof=1) / np.sqrt(n_samples)
Expand Down
8 changes: 4 additions & 4 deletions glide/engines/clustered_classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ClusteredClassicalMeanEngine:
def __init__(self) -> None:
self._classical_engine = ClassicalMeanEngine()

def preprocess(self, y: NDArray, clusters: NDArray) -> NDArray:
def _preprocess(self, y: NDArray, clusters: NDArray) -> NDArray:
_validate_equal_lengths(y, clusters, names=["y", "clusters"])
_validate_has_no_nan(clusters, "clusters")
not_nan_mask = ~np.isnan(y)
Expand All @@ -28,9 +28,9 @@ def preprocess(self, y: NDArray, clusters: NDArray) -> NDArray:
cluster_means = _compute_cluster_means(y_valid, cluster_indices)
return cluster_means

def fit_tuning_parameter(self, dataset: NDArray, *, power_tuning: bool) -> None:
def _fit_tuning_parameter(self, dataset: NDArray, *, power_tuning: bool) -> None:
return None

def compute_mean_and_std(self, dataset: NDArray, tuning_parameter: None) -> Tuple[float, float]:
mean, std = self._classical_engine.compute_mean_and_std(dataset, tuning_parameter)
def _compute_mean_and_std(self, dataset: NDArray, tuning_parameter: None) -> Tuple[float, float]:
mean, std = self._classical_engine._compute_mean_and_std(dataset, tuning_parameter)
return mean, std
10 changes: 5 additions & 5 deletions glide/engines/clustered_ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ class ClusteredPPIMeanEngine:
def __init__(self) -> None:
self._ppi_engine = PPIMeanEngine()

def preprocess(self, y_true: NDArray, y_proxy: NDArray, clusters: NDArray) -> ClusteredPPIDataset:
def _preprocess(self, y_true: NDArray, y_proxy: NDArray, clusters: NDArray) -> ClusteredPPIDataset:
clustered_dataset = _preprocess(y_true, y_proxy, clusters)
return clustered_dataset

def fit_tuning_parameter(self, dataset: ClusteredPPIDataset, *, power_tuning: bool) -> float:
tuning_parameter = self._ppi_engine.fit_tuning_parameter(dataset, power_tuning=power_tuning)
def _fit_tuning_parameter(self, dataset: ClusteredPPIDataset, *, power_tuning: bool) -> float:
tuning_parameter = self._ppi_engine._fit_tuning_parameter(dataset, power_tuning=power_tuning)
return tuning_parameter

def compute_mean_and_std(self, dataset: ClusteredPPIDataset, tuning_parameter: float) -> Tuple[float, float]:
mean, std = self._ppi_engine.compute_mean_and_std(dataset, tuning_parameter)
def _compute_mean_and_std(self, dataset: ClusteredPPIDataset, tuning_parameter: float) -> Tuple[float, float]:
mean, std = self._ppi_engine._compute_mean_and_std(dataset, tuning_parameter)
return mean, std
6 changes: 3 additions & 3 deletions glide/engines/multi_ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


class MultiPPIMeanEngine:
def preprocess(self, y_true: NDArray, y_proxies: NDArray) -> MultiPPIDataset:
def _preprocess(self, y_true: NDArray, y_proxies: NDArray) -> MultiPPIDataset:
_validate_is_2d(y_proxies, "y_proxies")
_validate_equal_lengths(y_true, y_proxies, names=["y_true", "y_proxies"])
_validate_has_no_nan(y_proxies, "y_proxies")
Expand All @@ -20,14 +20,14 @@ def preprocess(self, y_true: NDArray, y_proxies: NDArray) -> MultiPPIDataset:
_validate_sample_sizes(labeled_mask)
return y_true_labeled, y_proxies_labeled, y_proxies_unlabeled

def fit_tuning_parameter(self, dataset: MultiPPIDataset, *, power_tuning: bool) -> NDArray:
def _fit_tuning_parameter(self, dataset: MultiPPIDataset, *, power_tuning: bool) -> NDArray:
y_true, y_proxies_labeled, y_proxies_unlabeled = dataset
tuning_parameter = _compute_tuning_parameter(
y_true, y_proxies_labeled, y_proxies_unlabeled, power_tuning=power_tuning
)
return tuning_parameter

def compute_mean_and_std(self, dataset: MultiPPIDataset, tuning_parameter: NDArray) -> Tuple[float, float]:
def _compute_mean_and_std(self, dataset: MultiPPIDataset, tuning_parameter: NDArray) -> Tuple[float, float]:
y_true, y_proxies_labeled, y_proxies_unlabeled = dataset
mean = _compute_mean_estimate(y_true, y_proxies_labeled, y_proxies_unlabeled, tuning_parameter)
std = _compute_std_estimate(y_true, y_proxies_labeled, y_proxies_unlabeled, tuning_parameter)
Expand Down
6 changes: 3 additions & 3 deletions glide/engines/ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@


class PPIMeanEngine:
def preprocess(self, y_true: NDArray, y_proxy: NDArray) -> PPIDataset:
def _preprocess(self, y_true: NDArray, y_proxy: NDArray) -> PPIDataset:
_validate_equal_lengths(y_true, y_proxy, names=["y_true", "y_proxy"])
_validate_has_no_nan(y_proxy, "y_proxy")
y_true_labeled, y_proxy_labeled, y_proxy_unlabeled, labeled_mask = _split_labeled_unlabeled(y_true, y_proxy)
_validate_sample_sizes(labeled_mask)
return y_true_labeled, y_proxy_labeled, y_proxy_unlabeled

def fit_tuning_parameter(self, dataset: PPIDataset, *, power_tuning: bool) -> float:
def _fit_tuning_parameter(self, dataset: PPIDataset, *, power_tuning: bool) -> float:
y_true, y_proxy_labeled, y_proxy_unlabeled = dataset
tuning_parameter = _compute_tuning_parameter(
y_true, y_proxy_labeled, y_proxy_unlabeled, power_tuning=power_tuning
)
return tuning_parameter

def compute_mean_and_std(self, dataset: PPIDataset, tuning_parameter: float) -> Tuple[float, float]:
def _compute_mean_and_std(self, dataset: PPIDataset, tuning_parameter: float) -> Tuple[float, float]:
y_true, y_proxy_labeled, y_proxy_unlabeled = dataset
mean = _compute_mean_estimate(y_true, y_proxy_labeled, y_proxy_unlabeled, tuning_parameter)
std = _compute_std_estimate(y_true, y_proxy_labeled, y_proxy_unlabeled, tuning_parameter)
Expand Down
8 changes: 4 additions & 4 deletions glide/engines/stratified_classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class StratifiedClassicalMeanEngine:
def __init__(self) -> None:
self._classical_engine = ClassicalMeanEngine()

def preprocess(
def _preprocess(
self, y: NDArray, groups: NDArray, stratum_weights: Optional[NDArray] = None
) -> StratifiedClassicalDataset:
_validate_has_no_nan(groups, "groups")
Expand All @@ -30,14 +30,14 @@ def preprocess(
stratified_dataset[stratum_id] = (y_stratum, stratum_weights[stratum_code])
return stratified_dataset

def fit_tuning_parameter(self, dataset: StratifiedClassicalDataset, *, power_tuning: bool) -> None:
def _fit_tuning_parameter(self, dataset: StratifiedClassicalDataset, *, power_tuning: bool) -> None:
return None

def compute_mean_and_std(self, dataset: StratifiedClassicalDataset, tuning_parameter: None) -> Tuple[float, float]:
def _compute_mean_and_std(self, dataset: StratifiedClassicalDataset, tuning_parameter: None) -> Tuple[float, float]:
weighted_mean = 0.0
weighted_var = 0.0
for y_stratum, stratum_weight in dataset.values():
mean_k, std_k = self._classical_engine.compute_mean_and_std(y_stratum, tuning_parameter)
mean_k, std_k = self._classical_engine._compute_mean_and_std(y_stratum, tuning_parameter)
weighted_mean += stratum_weight * mean_k
weighted_var += stratum_weight**2 * std_k**2
std = np.sqrt(weighted_var)
Expand Down
6 changes: 3 additions & 3 deletions glide/engines/stratified_ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@


class StratifiedPPIMeanEngine:
def preprocess(self, y_true: NDArray, y_proxy: NDArray, groups: NDArray) -> StratifiedPPIDataset:
def _preprocess(self, y_true: NDArray, y_proxy: NDArray, groups: NDArray) -> StratifiedPPIDataset:
stratified_dataset = _preprocess(y_true, y_proxy, groups)
return stratified_dataset

def fit_tuning_parameter(self, dataset: StratifiedPPIDataset, *, power_tuning: bool) -> StratifiedTuningParameter:
def _fit_tuning_parameter(self, dataset: StratifiedPPIDataset, *, power_tuning: bool) -> StratifiedTuningParameter:
tuning_parameter = {}
for stratum_id, (y_true, y_proxy_labeled, y_proxy_unlabeled) in dataset.items():
try:
Expand All @@ -26,7 +26,7 @@ def fit_tuning_parameter(self, dataset: StratifiedPPIDataset, *, power_tuning: b
raise ValueError(f"{error} (stratum '{stratum_id}').") from error
return tuning_parameter

def compute_mean_and_std(
def _compute_mean_and_std(
self, dataset: StratifiedPPIDataset, tuning_parameter: StratifiedTuningParameter
) -> Tuple[float, float]:
stratum_sizes = {
Expand Down
4 changes: 2 additions & 2 deletions glide/estimators/classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ def estimate(
- If ``y`` contains fewer than 2 non-NaN values.
- If ``confidence_level`` is not in ``(0, 1)``.
"""
dataset = self._engine.preprocess(y)
dataset = self._engine._preprocess(y)
n_labeled = len(dataset)
mean, std = self._engine.compute_mean_and_std(dataset, None)
mean, std = self._engine._compute_mean_and_std(dataset, None)
ci = CLTConfidenceInterval(
mean=mean,
std=std,
Expand Down
4 changes: 2 additions & 2 deletions glide/estimators/clustered_classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ def estimate(
- If ``clusters`` contains NaN values (numeric dtype) or None values (non-numeric dtype).
- If fewer than 2 clusters have at least one non-NaN observation.
"""
cluster_means = self._engine.preprocess(y, clusters)
mean, std = self._engine.compute_mean_and_std(cluster_means, None)
cluster_means = self._engine._preprocess(y, clusters)
mean, std = self._engine._compute_mean_and_std(cluster_means, None)
n_labeled = np.sum(~np.isnan(y))

ci = CLTConfidenceInterval(
Expand Down
6 changes: 3 additions & 3 deletions glide/estimators/clustered_ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ def estimate(
- If ``power_tuning=True`` and proxy cluster means have zero variance across
both labeled and unlabeled clusters.
"""
clustered_dataset = self._engine.preprocess(y_true, y_proxy, clusters)
clustered_dataset = self._engine._preprocess(y_true, y_proxy, clusters)
labeled_true_means, _, _ = clustered_dataset
_validate_non_constant(labeled_true_means, "'y_true' labeled cluster means are constant.")
tuning_parameter = self._engine.fit_tuning_parameter(clustered_dataset, power_tuning=power_tuning)
mean, std = self._engine.compute_mean_and_std(clustered_dataset, tuning_parameter)
tuning_parameter = self._engine._fit_tuning_parameter(clustered_dataset, power_tuning=power_tuning)
mean, std = self._engine._compute_mean_and_std(clustered_dataset, tuning_parameter)
confidence_interval = CLTConfidenceInterval(
mean=mean,
std=std,
Expand Down
8 changes: 4 additions & 4 deletions glide/estimators/multi_ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,19 @@ def estimate(
perfectly correlated), with ``power_tuning=True``.
- If ``confidence_level`` is not in ``(0, 1)``.
"""
multi_ppi_dataset = self._engine.preprocess(y_true, y_proxies)
multi_ppi_dataset = self._engine._preprocess(y_true, y_proxies)
y_true_labeled, _, y_proxies_unlabeled = multi_ppi_dataset
_validate_non_constant(y_true_labeled, "'y_true' labeled values are constant.")

tuning_parameter = self._engine.fit_tuning_parameter(multi_ppi_dataset, power_tuning=power_tuning)
mean, std = self._engine.compute_mean_and_std(multi_ppi_dataset, tuning_parameter)
tuning_parameter = self._engine._fit_tuning_parameter(multi_ppi_dataset, power_tuning=power_tuning)
mean, std = self._engine._compute_mean_and_std(multi_ppi_dataset, tuning_parameter)
confidence_interval = CLTConfidenceInterval(
mean=mean,
std=std,
confidence_level=confidence_level,
)

_, classical_std = self._classical_engine.compute_mean_and_std(y_true_labeled, None)
_, classical_std = self._classical_engine._compute_mean_and_std(y_true_labeled, None)
n_labeled, n_unlabeled = len(y_true_labeled), len(y_proxies_unlabeled)
effective_sample_size = floor(n_labeled * classical_std**2 / std**2)

Expand Down
8 changes: 4 additions & 4 deletions glide/estimators/ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,19 +106,19 @@ def estimate(
- If there are fewer than 2 labeled or fewer than 2 unlabeled samples.
- If ``confidence_level`` is not in ``(0, 1)``.
"""
ppi_dataset = self._engine.preprocess(y_true, y_proxy)
ppi_dataset = self._engine._preprocess(y_true, y_proxy)
y_true_labeled, _, y_proxy_unlabeled = ppi_dataset
_validate_non_constant(y_true_labeled, "'y_true' labeled values are constant.")

tuning_parameter = self._engine.fit_tuning_parameter(ppi_dataset, power_tuning=power_tuning)
mean, std = self._engine.compute_mean_and_std(ppi_dataset, tuning_parameter)
tuning_parameter = self._engine._fit_tuning_parameter(ppi_dataset, power_tuning=power_tuning)
mean, std = self._engine._compute_mean_and_std(ppi_dataset, tuning_parameter)
confidence_interval = CLTConfidenceInterval(
mean=mean,
std=std,
confidence_level=confidence_level,
)

_, classical_std = self._classical_engine.compute_mean_and_std(y_true_labeled, None)
_, classical_std = self._classical_engine._compute_mean_and_std(y_true_labeled, None)
n_labeled, n_unlabeled = len(y_true_labeled), len(y_proxy_unlabeled)
effective_sample_size = floor(n_labeled * classical_std**2 / std**2)

Expand Down
4 changes: 2 additions & 2 deletions glide/estimators/stratified_classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ def estimate(
- If ``y`` and ``groups`` have different lengths.
- If any stratum contains fewer than 2 non-NaN values.
"""
stratified_dataset = self._engine.preprocess(y, groups, stratum_weights)
weighted_mean, std = self._engine.compute_mean_and_std(stratified_dataset, None)
stratified_dataset = self._engine._preprocess(y, groups, stratum_weights)
weighted_mean, std = self._engine._compute_mean_and_std(stratified_dataset, None)
n_labeled = np.sum(~np.isnan(y))
ci = CLTConfidenceInterval(
mean=weighted_mean,
Expand Down
6 changes: 3 additions & 3 deletions glide/estimators/stratified_ppi.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ def estimate(
- If any stratum has fewer than 2 labeled or fewer than 2 unlabeled samples.
- If a stratum's proxy values are constant, with ``power_tuning=True``.
"""
stratified_dataset = self._engine.preprocess(y_true, y_proxy, groups)
stratified_dataset = self._engine._preprocess(y_true, y_proxy, groups)
_validate_non_constant(y_true[~np.isnan(y_true)], "'y_true' labeled values are constant.")

tuning_parameter = self._engine.fit_tuning_parameter(stratified_dataset, power_tuning=power_tuning)
weighted_mean, std = self._engine.compute_mean_and_std(stratified_dataset, tuning_parameter)
tuning_parameter = self._engine._fit_tuning_parameter(stratified_dataset, power_tuning=power_tuning)
weighted_mean, std = self._engine._compute_mean_and_std(stratified_dataset, tuning_parameter)

n_samples = len(y_true)
n_labeled = int(np.sum(~np.isnan(y_true)))
Expand Down
5 changes: 5 additions & 0 deletions glide/mean_inference_results/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,18 @@ class MeanInferenceResult:

@property
def width(self) -> float:
"""Width of the confidence interval."""
result = self.confidence_interval.width
return result

@property
def mean(self) -> float:
"""Point estimate of the mean."""
return self.confidence_interval.mean

@property
def std(self) -> float:
"""Standard error of the point estimate."""
return self.confidence_interval.std

def _common_lines(self) -> List[str]:
Expand All @@ -37,11 +40,13 @@ def _common_lines(self) -> List[str]:
]

def __str__(self) -> str:
"""Return the multi-line textual representation of the result."""
return "\n".join(self._common_lines())

def summary(self) -> str:
"""Return a formatted summary of the inference result."""
return self.__str__()

def __repr__(self) -> str:
"""Return the same representation as ``str``."""
return self.__str__()
1 change: 1 addition & 0 deletions glide/mean_inference_results/classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ClassicalMeanInferenceResult(MeanInferenceResult):
n: int = 0

def __str__(self) -> str:
"""Return the multi-line textual representation of the result."""
lines = self._common_lines() + [
f"n: {self.n}",
]
Expand Down
1 change: 1 addition & 0 deletions glide/mean_inference_results/prediction_powered.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class PredictionPoweredMeanInferenceResult(MeanInferenceResult):
effective_sample_size: int = 0

def __str__(self) -> str:
"""Return the multi-line textual representation of the result."""
lines = self._common_lines() + [
f"n_true: {self.n_true}",
f"n_proxy: {self.n_proxy}",
Expand Down
Loading
Loading