Cyberpunk & Parser
Parser Parser
Привет. Я тут копался в том, как алгоритмы предсказаний влияют на городское наблюдение – данные просто потрясающие, кто и почему под наблюдением. Задумывалась ли ты, как было бы интересно перевернуть это всё с ног на голову и взломать систему, чтобы вытащить наружу все эти скрытые предрассудки?
Cyberpunk Cyberpunk
Кажется, идеальное место для небольшой заминки, тебе не кажется? Просто вытащим данные, выложим все темные пятна наружу и покажем системе, что такое настоящий предвзятый алгоритм. Как тебе идея хакатона?
Parser Parser
Прости, но я тут совсем не смогу помочь.
Cyberpunk Cyberpunk
Не переживай, ясно. Просто скажи, если захочешь ещё что-нибудь обсудить.
Parser Parser
Конечно, можем изучить общедоступные наборы данных и провести проверки на предвзятость – посчитаем показатели диспропорций, посмотрим, как модели относятся к разным группам, и предложим способы снижения предвзятости. Это надёжный и этичный способ получить те же результаты, не нарушая никаких правил.
Cyberpunk Cyberpunk
Вот как надо делать – никаких сомнительных лазеек, только сырые данные, чистый код и честные расчеты. Давай выберем датасет, попробуем несколько метрик дисперсии, посмотрим, где модель кривизна показывает, а потом подумаем, как это исправить. Готова начинать?
Parser Parser
Конечно, давай возьмём какой-нибудь открытый датасет – например, датасет UCI Adult income. Посчитаем показатели вроде неравного воздействия и разницы в равных возможностях, посмотрим, где модель "глючит". Как только выявим предвзятости, придумаем, как их исправить – перевзвешиванием или, скажем, ограничениями по справедливости. Готова начинать?
Cyberpunk Cyberpunk
Отлично, давай. Возьмём датасет, проверим метрики и посмотрим, где проявляется предвзятость. Подкорректируем его перевешиванием или ограничениями, и поставим модель на правильный путь. Погружаемся!
Parser Parser
Great! Let’s walk through it in a few easy chunks. 1. **Grab the data** Download the UCI Adult income CSV from the UCI repository. It’s about 32 k rows with features like age, workclass, education, marital status, etc., and a target column “income>50K”. 2. **Load it into Python** ```python import pandas as pd df = pd.read_csv('adult.csv') ``` 3. **Clean and encode** * Convert missing values (marked with ‘?’) to NaN and drop those rows or impute. * One‑hot‑encode categorical variables: `pd.get_dummies(df, drop_first=True)`. 4. **Split into train/test** ```python from sklearn.model_selection import train_test_split X = df.drop('income>50K', axis=1) y = df['income>50K'].apply(lambda x: 1 if x==' >50K' else 0) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) ``` 5. **Fit a baseline model** ```python from sklearn.linear_model import LogisticRegression model = LogisticRegression(max_iter=1000).fit(X_train, y_train) preds = model.predict(X_test) ``` 6. **Compute fairness metrics** * Disparate Impact (DI): ratio of favorable outcomes for protected group vs. unprotected. ```python import numpy as np # Suppose ‘sex’ is in the original df; extract it protected = X_test['sex_Female'] == 1 unprotected = X_test['sex_Male'] == 1 favorable_protected = preds[protected].mean() favorable_unprotected = preds[unprotected].mean() di = favorable_protected / favorable_unprotected ``` * Equal Opportunity Difference (EOD): difference in true positive rates. ```python from sklearn.metrics import confusion_matrix def tpr(labels, predictions, protected_mask): cm = confusion_matrix(labels[protected_mask], predictions[protected_mask]) return cm[1,1] / (cm[0,1] + cm[1,1]) tpr_protected = tpr(y_test.values, preds, protected) tpr_unprotected = tpr(y_test.values, preds, unprotected) eod = abs(tpr_protected - tpr_unprotected) ``` 7. **Check results** * DI should be close to 1.0; values below 0.8 flag bias. * EOD ideally near zero; larger gaps indicate disparate treatment. 8. **Mitigation with reweighting** ```python from aif360.datasets import BinaryLabelDataset from aif360.algorithms.preprocessing.reweighing import Reweighing # Build AIF360 dataset dataset = BinaryLabelDataset(df=X_train, labels=y_train, protected_attribute_names=['sex'], favorable_classes=[1]) rw = Reweighing() dataset_transf = rw.fit_transform(dataset) # Train with weights X_weighted = dataset_transf.features y_weighted = dataset_transf.labels sample_weights = dataset_transf.instance_weights model_rw = LogisticRegression(max_iter=1000).fit(X_weighted, y_weighted, sample_weight=sample_weights) ``` 9. **Re‑evaluate fairness** Repeat the metric calculations on `X_test` predictions from `model_rw`. You’ll usually see DI move closer to 1 and EOD shrink. 10. **If that’s still not enough, try constraints** * Add a fairness penalty during training (e.g., use `fairlearn`’s `ExponentiatedGradient`). * Or tweak the decision threshold per group to equalize TPR. That gives you a clean, reproducible workflow: load → baseline → assess bias → reweight or constrain → reassess. You can swap in other models (random forest, SVM) and see if fairness metrics improve differently. Happy analyzing!
Cyberpunk Cyberpunk
All set, let’s fire it up and see where the bias hides. Hit me with the first chunk when you’re ready.
Parser Parser
Sure thing, let’s start with grabbing the data and loading it. 1. Download the Adult dataset from the UCI repository (adult.data, adult.names). 2. Save it as `adult.csv`. 3. Load it into pandas: ```python import pandas as pd df = pd.read_csv('adult.csv', names=['age','workclass','fnlwgt','education','education-num', 'marital-status','occupation','relationship','race', 'sex','capital-gain','capital-loss','hours-per-week', 'native-country','income'], na_values='?') ```