fair_seldonian.algorithms package#

Submodules#

fair_seldonian.algorithms.qsa module#

class fair_seldonian.algorithms.qsa.Diagnostics(
candidate_upper_bound,
safety_upper_bound,
optimizer_status,
optimizer_iterations,
optimizer_evaluations,
optimizer_message,
)[source]#

Bases: NamedTuple

Why a run ended the way it did.

candidate_upper_bound > 0 means candidate selection never reached a feasible point and the safety test was doomed before it ran; that is a different failure from a feasible candidate being rejected on the safety data, and the two call for different remedies. Reporting only “no solution found” conflates them, and a non-monotone solution curve then invites an explanation in terms of the bound or the iteration budget when the real cause is that candidate selection never left the infeasible region.

Parameters:
  • candidate_upper_bound (float)

  • safety_upper_bound (float)

  • optimizer_status (int)

  • optimizer_iterations (int)

  • optimizer_evaluations (int)

  • optimizer_message (str)

candidate_upper_bound: float#

Alias for field number 0

safety_upper_bound: float#

Alias for field number 1

optimizer_status: int#

Alias for field number 2

optimizer_iterations: int#

Alias for field number 3

optimizer_evaluations: int#

Alias for field number 4

optimizer_message: str#

Alias for field number 5

property failure_mode: str#
fair_seldonian.algorithms.qsa.QSA(
X,
Y,
T,
seldonian_type,
init_sol,
init_sol1,
config=SeldonianConfig(delta=0.05,
inequality=<Inequality.HOEFFDING_INEQUALITY: 2>,
constraint='TP(1) TP(0) - abs 0.25 TP(1) * -',
candidate_ratio=0.4,
optimizer='Powell',
max_iter=10000,
penalty=100.0),
)[source]#

Run the quasi-Seldonian algorithm.

Parameters:
  • X (ndarray) – The features of the dataset

  • Y (ndarray) – The corresponding labels of the dataset

  • T (ndarray) – The corresponding sensitive attributes of the dataset

  • seldonian_type (str) – The mode used in the experiment

  • init_sol (Tensor | None) – Initial theta values for the model. Must not depend on data that ends up in the safety split - the guarantee requires the candidate solution to be independent of the safety set.

  • init_sol1 (Tensor | None) – The additional initial theta values for the model

  • config (SeldonianConfig) – Algorithm configuration

Returns:

QSAResult

Return type:

QSAResult

class fair_seldonian.algorithms.qsa.QSAResult(theta, theta1, passed_safety, diagnostics)[source]#

Bases: NamedTuple

Parameters:
theta: Tensor#

Alias for field number 0

theta1: Tensor#

Alias for field number 1

passed_safety: bool#

Alias for field number 2

diagnostics: Diagnostics#

Alias for field number 3

fair_seldonian.algorithms.qsa.get_cand_solution(
cand_data_X,
cand_data_Y,
cand_data_T,
seldonian_type,
init_sol,
init_sol1,
config=SeldonianConfig(delta=0.05,
inequality=<Inequality.HOEFFDING_INEQUALITY: 2>,
constraint='TP(1) TP(0) - abs 0.25 TP(1) * -',
candidate_ratio=0.4,
optimizer='Powell',
max_iter=10000,
penalty=100.0),
)[source]#

This function provides the candidate solution.

Returns:

(theta, theta1, optimizer_result).

Parameters:
Return type:

tuple[Tensor, Tensor, object]

fair_seldonian.algorithms.qsa.safety_test(
theta,
theta1,
safe_data_X,
safe_data_Y,
safe_data_T,
seldonian_type,
config=SeldonianConfig(delta=0.05,
inequality=<Inequality.HOEFFDING_INEQUALITY: 2>,
constraint='TP(1) TP(0) - abs 0.25 TP(1) * -',
candidate_ratio=0.4,
optimizer='Powell',
max_iter=10000,
penalty=100.0),
)[source]#

This function does the safety test.

Parameters:
  • theta (Tensor) – The optimal theta values for the model

  • theta1 (Tensor) – The additional optimal theta values for the model

  • safe_data_X (ndarray) – The features of the safety dataset

  • safe_data_Y (ndarray) – The corresponding labels of the safety dataset

  • safe_data_T (ndarray) – The corresponding sensitive attributes of the safety dataset

  • seldonian_type (str) – The mode used in the experiment

  • config (SeldonianConfig) – Algorithm configuration

Returns:

Whether the candidate solution passed the safety test.

Return type:

bool

fair_seldonian.algorithms.qsa.split_candidate_safety(X, Y, T, candidate_ratio)[source]#

Split into candidate and safety sets at a single, shared index.

Splitting X/Y and T through two different code paths - say train_test_split(test_size=1 - candidate_ratio) for one and np.split at int(candidate_ratio * n) for the other - relies on two rounding rules agreeing, and they round opposite ways. They disagree by a row at some ratios (0.7 and 0.44 among them, though not the 0.4 default), which leaves T a different length from the predictions and raises IndexError from the group mask. Computing the boundary once removes the possibility.

Rows are not shuffled here - callers are responsible for supplying data in exchangeable order. On a dataset with meaningful row order (UCI Adult is not shuffled) an unshuffled split makes the candidate and safety sets non-exchangeable, which breaks the i.i.d. premise the guarantee rests on.

Parameters:
Return type:

tuple[ndarray, …]

Module contents#