Base Class
quack.bag_generator.base.BaseBagGenerator
Bases: ABC, BaseEstimator
Abstract base class for all dataset-shift bag generators.
A bag generator draws repeated "bags" (labeled subsets) of a fixed
size from a labeled dataset (X, y), simulating a specific kind of
dataset shift between training and test-time distributions. Bags
produced this way follow the standard evaluation protocol in the
quantification literature (the "Artificial Prevalence Protocol", APP),
letting quantifiers be benchmarked across the full spectrum of
possible test-time class prevalences (or covariate shifts) rather than
relying on a single fixed train/test split.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_bags
|
int
|
Number of bags to generate. |
= 100
|
bag_size
|
int
|
Number of instances per bag. If None, defaults to |
= None
|
random_state
|
int, RandomState instance or None
|
Controls the randomness of the bag sampling process. Pass an int for
reproducible bags across repeated calls to |
= None
|
Source code in quack/bag_generator/base.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
generate(X, y)
abstractmethod
Lazily yields n_bags labeled bags (X_bag, y_bag) drawn from (X, y).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
array-like, sparse matrix
|
The pool of features to draw bags from. |
array-like
|
y
|
array-like of shape (n_samples,)
|
The corresponding labels. |
required |
Yields:
| Name | Type | Description |
|---|---|---|
X_bag |
ndarray of shape (bag_size, n_features)
|
Feature matrix of a single generated bag. |
y_bag |
ndarray of shape (bag_size,)
|
Corresponding labels for the generated bag. |
Source code in quack/bag_generator/base.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | |
to_list(X, y)
Eagerly materializes generate(X, y) into a list of (X_bag, y_bag).
Useful when the same set of bags needs to be iterated multiple times (e.g. once per quantifier being benchmarked), since generators can otherwise only be consumed once.
Returns:
| Name | Type | Description |
|---|---|---|
bags |
list[tuple[ndarray, ndarray]]
|
List of |
Source code in quack/bag_generator/base.py
72 73 74 75 76 77 78 79 80 81 82 83 84 | |
Prior Shift Bag Generator
quack.bag_generator._prior_shift.PriorShiftBagGenerator
Bases: BaseBagGenerator
Simulates Prior Probability Shift by resampling bags across the
class-prevalence simplex, preserving P(X|y).
For each bag, a target class-prevalence vector p is sampled (see
sampling_strategy) and then, independently for each class c,
round(p[c] * bag_size) instances are drawn from the pool of original
instances of class c — so the class-conditional feature distribution
P(X|y=c) is left untouched and only the marginal P(y) is shifted.
This is the standard "Artificial Prevalence Protocol" (APP) used to
benchmark quantifiers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_bags
|
int
|
Number of bags to generate. |
= 100
|
bag_size
|
int
|
Number of instances per bag. If None, defaults to |
= None
|
sampling_strategy
|
(uniform, dirichlet)
|
Strategy used to sample each bag's target prevalence vector:
- |
'uniform'
|
dirichlet_alpha
|
float | array-like of shape (n_classes,)
|
Concentration parameter(s) for the Dirichlet distribution. Only used
when |
= 1.0
|
with_replacement
|
bool
|
Whether instances are drawn with replacement from each class pool. Automatically forced to True for a given class/bag whenever the requested count exceeds the number of available instances of that class, regardless of this setting. |
= True
|
random_state
|
int, RandomState instance or None
|
Controls the randomness of both the prevalence sampling and the instance resampling. |
= None
|
Attributes:
| Name | Type | Description |
|---|---|---|
classes_ |
ndarray of shape (n_classes,)
|
The distinct class labels found in |
sampled_prevalences_ |
ndarray of shape (n_bags, n_classes)
|
The realized class prevalence of each generated bag's |
References
George Forman. Quantifying counts and costs via classification. Data Mining and Knowledge Discovery, 17(2):164-206, 2008.
Examples:
>>> from sklearn.datasets import make_classification
>>> from quack.bag_generator import PriorShiftBagGenerator
>>> X, y = make_classification(n_samples=500, n_classes=2, random_state=0)
>>> generator = PriorShiftBagGenerator(n_bags=5, bag_size=100, random_state=0)
>>> bags = generator.to_list(X, y)
>>> len(bags)
5
>>> generator.sampled_prevalences_.shape
(5, 2)
Source code in quack/bag_generator/_prior_shift.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | |
Covariate Shift Bag Generator
quack.bag_generator._covariate_shift.CovariateShiftBagGenerator
Bases: BaseBagGenerator
Simulates Covariate Shift by resampling bags biased towards random
regions of the feature space, preserving P(y|X).
For each bag, a random "pivot" instance is drawn from the dataset and every instance's RBF kernel similarity to that pivot is computed:
k(x, x_pivot) = exp( -gamma * ||x - x_pivot||^2 )
Instances are then resampled with probability proportional to their
similarity to the pivot, concentrating the bag around a random region
of the feature space. Since instances — and their original labels —
are drawn as-is (no label is ever altered), the conditional
distribution P(y|X) is left untouched; only the marginal feature
distribution P(X) (and, as a natural consequence in most real
datasets, the marginal P(y) too) is shifted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_bags
|
int
|
Number of bags to generate. |
= 100
|
bag_size
|
int
|
Number of instances per bag. If None, defaults to |
= None
|
gamma
|
float
|
RBF kernel coefficient. Controls how concentrated each bag is around
its pivot: larger values produce bags tightly clustered in feature
space (stronger shift); smaller values approach the original,
unshifted distribution. If None, defaults to |
= None
|
with_replacement
|
bool
|
Whether instances are drawn with replacement. Automatically forced
to True whenever |
= True
|
random_state
|
int, RandomState instance or None
|
Controls the randomness of both the pivot selection and the instance resampling. |
= None
|
Attributes:
| Name | Type | Description |
|---|---|---|
classes_ |
ndarray of shape (n_classes,)
|
The distinct class labels found in |
pivot_indices_ |
ndarray of shape (n_bags,)
|
The dataset index of the pivot instance used to build each bag. |
sampled_prevalences_ |
ndarray of shape (n_bags, n_classes)
|
The realized class prevalence of each generated bag's |
References
Bickel, S., Brückner, M., & Scheffer, T. (2009). Discriminative learning under covariate shift. Journal of Machine Learning Research, 10, 2137-2155.
Examples:
>>> from sklearn.datasets import make_classification
>>> from quack.bag_generator import CovariateShiftBagGenerator
>>> X, y = make_classification(n_samples=500, n_classes=2, random_state=0)
>>> generator = CovariateShiftBagGenerator(n_bags=5, bag_size=100, gamma=0.5, random_state=0)
>>> bags = generator.to_list(X, y)
>>> len(bags)
5
Source code in quack/bag_generator/_covariate_shift.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |