Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PopFS

Population-aware, welfare-aware feature selection.

PopFS selects a small subset of features that performs well across a set of known subpopulations, not just on their pooled average. The objective is a generalized-mean (power) welfare over per-population utilities, so the user can choose anything from utilitarian (alpha=1, arithmetic mean) to Rawlsian (alpha=-inf, worst-case).

The package ships four selectors that share a common interface and a common evaluator, so you can benchmark them head-to-head on any dataset with known subgroup structure:

Selector Idea
PopFS Full pipeline: SIS + multitask group-lasso screen + welfare-aware Gauss-Newton greedy + swap refinement
PopFSScreen Screening stage only (SIS + MT-lasso, no greedy refinement)
Lasso Pooled L1 baseline (sklearn Lasso / L1-LogisticRegression)
XGBoost Pooled tree-importance baseline (falls back to ExtraTrees if xgboost is not installed)

All four return a SelectionResult and can be scored with popfs.evaluate to produce per-population + welfare-aggregate metrics.


Installation

pip install .
# or with the tree-baseline extra (installs xgboost):
pip install ".[xgboost]"

Requires Python ≥ 3.9. Core dependencies: numpy, pandas, scipy, scikit-learn. xgboost is optional; if absent, the XGBoost selector transparently falls back to sklearn.ensemble.ExtraTrees.

Quick tour

import numpy as np
from popfs import Population, PopFS, evaluate, fit_population_teachers

# 1. Assemble a list of Populations, one per subgroup.
pops = [
    Population(X_train=..., X_val=..., X_test=...,
               y_train=..., y_val=..., y_test=...,
               name="group_A", task="regression"),
    Population(X_train=..., X_val=..., X_test=...,
               y_train=..., y_val=..., y_test=...,
               name="group_B", task="regression"),
]

# 2. Fit per-population teachers (shared across selectors + evaluate()).
fit_population_teachers(pops, teacher_kind="hgb", seed=0)

# 3. Run PopFS.
selector = PopFS(k=8, welfare_alpha=1.0,           # utilitarian
                 p0=100, d_screen=30, top_l=10,
                 selection_objective="teacher", seed=0)
result = selector.fit(pops, feature_names=[...])

# 4. Score any subset — even one selected by another method.
ev = evaluate(result.selected_indices, pops, welfare_alpha=1.0)
print(ev.summary["teacher_power_welfare"], ev.summary["label_power_welfare"])

Choosing welfare_alpha

alpha Welfare interpretation
+∞ Best-population utility (max)
1.0 Arithmetic mean (utilitarian) — the default
0.0 Geometric mean (Nash bargaining)
-1.0, etc. Increasingly Rawlsian; downweights populations with low utility
-∞ Worst-population utility (min, Rawlsian max-min)

alpha=-np.inf is a common choice when you care specifically about the worst-off subpopulation.

API surface

from popfs import (
    Population,             # dataclass: per-subgroup train/val/test arrays
    SelectionResult,        # return type of every selector's .fit()
    EvaluationResult,       # return type of evaluate()
    PopFS, PopFSScreen,     # our selectors
    Lasso, XGBoost,         # pooled baselines
    evaluate,               # method-agnostic scorer
    power_welfare,          # generalized-mean aggregator
    power_welfare_gain,
    fit_population_teachers,# pseudo-labeler used before selection
    __version__,
)

Task types

  • Regression (task="regression"): continuous y. Teacher = a full-feature Ridge/HGB fit; loss = MSE.
  • Classification (task="classification", binary): y ∈ {0, 1}. Teacher = full-feature HGB probability estimate; loss = log loss.

About

Population-Robust Feature Selection via Generalized Welfare Optimization

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages