ai-privacy-toolkit/notebooks/anonymization_one_hot_adult.ipynb
abigailgold 6d81cd8ed4
Support for one-hot encoded features in minimization (#87)
* Initial version with first working test
* Make sure representative values in generalizations for 1-hot encoded features are consistent.
* Updated notebooks for one-hot encoded data
* Review comments

Signed-off-by: abigailt <abigailt@il.ibm.com>
2023-12-24 18:18:18 -05:00

303 lines
7.9 KiB
Text

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using ML anonymization on one-hot encoded data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this tutorial we will show how to anonymize models using the ML anonymization module, specifically when the input data is already one-hot encoded. \n",
"\n",
"This will be demonstarted using the Adult dataset (original dataset can be found here: https://archive.ics.uci.edu/ml/datasets/adult). "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Load data"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[['State-gov' 'Never-married' 'Adm-clerical' ... 'White' 'Male'\n",
" 'UnitedStates']\n",
" ['Self-emp-not-inc' 'Married-civ-spouse' 'Exec-managerial' ... 'White'\n",
" 'Male' 'UnitedStates']\n",
" ['Private' 'Divorced' 'Handlers-cleaners' ... 'White' 'Male'\n",
" 'UnitedStates']\n",
" ...\n",
" ['Private' 'Never-married' 'Sales' ... 'White' 'Female' 'UnitedStates']\n",
" ['Private' 'Never-married' 'Craft-repair' ... 'White' 'Male'\n",
" 'UnitedStates']\n",
" ['Private' 'Never-married' 'Handlers-cleaners' ... 'White' 'Male'\n",
" 'UnitedStates']]\n"
]
}
],
"source": [
"import numpy as np\n",
"\n",
"import os\n",
"import sys\n",
"sys.path.insert(0, os.path.abspath('..'))\n",
"from apt.utils.dataset_utils import get_adult_dataset_pd\n",
"\n",
"# 'workclass', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country'\n",
"categorical_features = [1, 3, 4, 5, 6, 7, 11]\n",
"\n",
"# requires a folder called 'datasets' in the current directory\n",
"(x_train, y_train), (x_test, y_test) = get_adult_dataset_pd()\n",
"x_train = x_train.to_numpy()[:, [1, 3, 4, 5, 6, 7, 11]]\n",
"y_train = y_train.to_numpy().astype(int)\n",
"x_test = x_test.to_numpy()[:, [1, 3, 4, 5, 6, 7, 11]]\n",
"y_test = y_test.to_numpy().astype(int)\n",
"\n",
"# get balanced dataset\n",
"x_train = x_train[:x_test.shape[0]]\n",
"y_train = y_train[:y_test.shape[0]]\n",
"\n",
"print(x_train)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Encode data"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]\n",
" ...\n",
" [0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]]\n"
]
}
],
"source": [
"from sklearn.preprocessing import OneHotEncoder\n",
"import scipy\n",
"\n",
"preprocessor = OneHotEncoder(handle_unknown=\"ignore\")\n",
"\n",
"x_train = preprocessor.fit_transform(x_train)\n",
"x_test = preprocessor.transform(x_test)\n",
"if scipy.sparse.issparse(x_train):\n",
" x_train = x_train.toarray().astype(int)\n",
"if scipy.sparse.issparse(x_test):\n",
" x_test = x_test.toarray().astype(int)\n",
"\n",
"print(x_train)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Train decision tree model"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Base model accuracy: 0.8143234445058657\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/abigailt/Library/Python/3.9/lib/python/site-packages/sklearn/utils/deprecation.py:103: FutureWarning: The attribute `n_features_` is deprecated in 1.0 and will be removed in 1.2. Use `n_features_in_` instead.\n",
" warnings.warn(msg, category=FutureWarning)\n"
]
}
],
"source": [
"from sklearn.tree import DecisionTreeClassifier\n",
"from art.estimators.classification.scikitlearn import ScikitlearnDecisionTreeClassifier\n",
"\n",
"model = DecisionTreeClassifier()\n",
"model.fit(x_train, y_train)\n",
"\n",
"art_classifier = ScikitlearnDecisionTreeClassifier(model)\n",
"\n",
"print('Base model accuracy: ', model.score(x_test, y_test))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Anonymize data\n",
"## k=100\n",
"\n",
"The data is anonymized on the quasi-identifiers: age, education-num, capital-gain, hours-per-week and with a privact parameter k=100.\n",
"\n",
"This means that each record in the anonymized dataset is identical to 99 others on the quasi-identifier values (i.e., when looking only at those features, the records are indistinguishable)."
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]\n",
" ...\n",
" [0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]\n",
" [0 0 0 ... 0 1 0]]\n"
]
}
],
"source": [
"from apt.utils.datasets import ArrayDataset\n",
"from apt.anonymization import Anonymize\n",
"\n",
"x_train_predictions = np.array([np.argmax(arr) for arr in art_classifier.predict(x_train)])\n",
"\n",
"# QI = (race, sex)\n",
"QI = [53, 52, 51, 50, 49, 48, 47]\n",
"QI_slices = [[47, 48, 49, 50, 51], [52, 53]]\n",
"anonymizer = Anonymize(100, QI, quasi_identifer_slices=QI_slices)\n",
"anon = anonymizer.anonymize(ArrayDataset(x_train, x_train_predictions))\n",
"print(anon)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2711"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# number of distinct rows in original data\n",
"len(np.unique(x_train, axis=0))"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2476"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# number of distinct rows in anonymized data\n",
"len(np.unique(anon, axis=0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Train decision tree model"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Anonymized model accuracy: 0.8124808058473066\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/abigailt/Library/Python/3.9/lib/python/site-packages/sklearn/utils/deprecation.py:103: FutureWarning: The attribute `n_features_` is deprecated in 1.0 and will be removed in 1.2. Use `n_features_in_` instead.\n",
" warnings.warn(msg, category=FutureWarning)\n"
]
}
],
"source": [
"anon_model = DecisionTreeClassifier()\n",
"anon_model.fit(anon, y_train)\n",
"\n",
"anon_art_classifier = ScikitlearnDecisionTreeClassifier(anon_model)\n",
"\n",
"print('Anonymized model accuracy: ', anon_model.score(x_test, y_test))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}