agentsclimarketplace

Bias assessment

Skill obielin/responsible-ai-skills/skills/bias-assessment

Use when loading datasets, training ML models, evaluating model performance, or preparing data for AI systems. Do NOT skip this for "small" or "simple" models.From its SKILL.md

Install
npx -y skills add obielin/responsible-ai-skills --skill bias-assessment

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • runs commandsInstructs the agent to run 1 command, including `python skills/bias-assessment/scripts/check_representation.py --data <your_dataset>`.

SKILL.md

4.9 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it

Bias Assessment

Bias in AI systems causes real harm. A model that appears accurate overall can systematically disadvantage specific groups. You MUST complete this assessment before training or evaluating any model.

Phase 1: Data Audit (Before Training)

1.1 Check Representation

Run the representation check script:

python skills/bias-assessment/scripts/check_representation.py --data <your_dataset>

If no script applies, manually verify:

# For each protected attribute in your dataset:
for attr in ['age', 'sex', 'ethnicity', 'disability', 'postcode']:
    if attr in df.columns:
        print(f"\n{attr} distribution:")
        print(df[attr].value_counts(normalize=True))
        
        # Flag underrepresented groups (<5% of dataset)
        underrepresented = df[attr].value_counts(normalize=True)
        flagged = underrepresented[underrepresented < 0.05].index.tolist()
        if flagged:
            print(f"⚠️  UNDERREPRESENTED: {flagged}")

Stop and fix if: Any group that will be affected by predictions has <5% representation.

1.2 Check for Proxy Variables

Proxy variables appear neutral but encode protected characteristics:

Proxy VariableMay Encode
Postcode / ZIP codeEthnicity, deprivation
NameEthnicity, sex
School attendedSocioeconomic status, ethnicity
Job title historySex, disability
Device typeSocioeconomic status

Action: For each proxy variable, decide: remove it, transform it, or document the risk explicitly.

1.3 Check Label Quality

Biased labels produce biased models:

  • Were labels assigned by humans? → Check inter-annotator agreement across annotator demographics
  • Were labels derived from historical decisions? → Those decisions may contain historical bias
  • Are labels consistent across demographic groups? → Run: df.groupby(protected_attr)['label'].mean()

Phase 2: Model Evaluation (After Training)

2.1 Disaggregated Performance

NEVER report only aggregate metrics. Always disaggregate:

from sklearn.metrics import classification_report

for group_val in df[protected_attr].unique():
    mask = df[protected_attr] == group_val
    print(f"\n=== {protected_attr} = {group_val} ===")
    print(classification_report(y_true[mask], y_pred[mask]))

2.2 Fairness Metrics — Compute All Three

# 1. Demographic Parity: positive prediction rate per group
for group in groups:
    mask = df[attr] == group
    rate = y_pred[mask].mean()
    print(f"Demographic parity [{group}]: {rate:.3f}")

# 2. Equal Opportunity: true positive rate per group
for group in groups:
    mask = (df[attr] == group) & (y_true == 1)
    tpr = y_pred[mask].mean()
    print(f"Equal opportunity [{group}]: {tpr:.3f}")

# 3. Predictive Parity: precision per group
for group in groups:
    mask = df[attr] == group
    from sklearn.metrics import precision_score
    prec = precision_score(y_true[mask], y_pred[mask])
    print(f"Predictive parity [{group}]: {prec:.3f}")

2.3 Bias Thresholds — Do Not Proceed If Exceeded

MetricMaximum Acceptable GapAction If Exceeded
Demographic parity difference0.05Investigate data; apply reweighting
Equal opportunity difference0.05Check label quality; consider threshold adjustment
Predictive parity difference0.05Review training data balance
False positive rate gap0.05Adjust decision threshold per group

Phase 3: Mitigation

If thresholds are exceeded, you MUST apply mitigation before proceeding:

Pre-processing

# Reweighting: give underrepresented groups more influence during training
from sklearn.utils.class_weight import compute_sample_weight
sample_weights = compute_sample_weight('balanced', y=df[protected_attr])
model.fit(X_train, y_train, sample_weight=sample_weights)

Post-processing

# Threshold adjustment: use different decision thresholds per group
thresholds = {}
for group in groups:
    mask = df[attr] == group
    # Find threshold that equalises FPR across groups
    thresholds[group] = find_threshold(y_true[mask], y_scores[mask], target_fpr)

Document your choice

Whatever mitigation you apply, add a comment in the code and update the model card.


Completion Checklist

Before leaving this skill:

  • Representation checked for all relevant protected attributes
  • Proxy variables identified and decision documented
  • Label quality assessed
  • Disaggregated performance metrics computed and recorded
  • All three fairness metrics computed
  • Any exceeded threshold addressed with documented mitigation
  • Findings written to docs/bias-assessment-<date>.md

Now proceed to fairness-testing to write tests that will catch bias regressions.

What ships with it: 1 file

5.2 KB alongside SKILL.md, 1 of them executable

scripts/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.