Created
October 2, 2023 03:25
-
-
Save kenluck2001/06625f60217180b31063dff7464e0ac8 to your computer and use it in GitHub Desktop.
Differential privacy mechanisms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Evaluation source code | |
Author: Kenneth Emeka Odoh | |
References: | |
https://becominghuman.ai/differential-privacy-noise-adding-mechanisms-ede242dcbb2e | |
https://arxiv.org/pdf/1912.04222.pdf | |
https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf | |
Code was tested in Pthon 2.7 | |
""" | |
import pandas as pd | |
import numpy as np | |
SEED = 65535 | |
np.random.seed(SEED) # MAKE EXPERIMENTS REPRODUCIBLE | |
avg = lambda xs : sum(xs) / len(xs) | |
uFunc2 = lambda xs, y : abs(avg(xs) - y) # ranking function | |
def getSensistivity(dataLst): | |
''' | |
Calculate sensitivity | |
input: | |
dataLst: list of element (raw data), 1D | |
Output: | |
return sensitivity in float | |
''' | |
maxVal = float ('-inf') | |
for xVal in dataLst: | |
for yVal in dataLst: | |
curDiff = abs (xVal - yVal) | |
if maxVal < curDiff: | |
maxVal = curDiff | |
return maxVal | |
def getSensistivityOpt(sortLst): | |
''' | |
Calculate sensitivity (optimized) | |
input: | |
sortLst: sorted list of element (raw data), 1D | |
Output: | |
return sensitivity in float | |
''' | |
left = 0 | |
right = len (sortLst) - 1 | |
maxVal = float ('-inf') | |
while left <= right: | |
xVal, yVal = sortLst[left], sortLst[right] | |
curDiff = abs (xVal - yVal) | |
if maxVal < curDiff: | |
maxVal = curDiff | |
left = left + 1 | |
right = right - 1 | |
return maxVal | |
def LaplaceMech (dataLst, epsilon, sensitivity=1): | |
''' | |
Laplace mechanism | |
input: | |
dataLst: list of element (raw data), 1D | |
epsilon: magnitude of noise | |
sensitivity: sensitivity of data | |
Output: | |
noisy response from laplace machanism | |
''' | |
noisyLaplaceResponse = [ xdata + np.random.laplace(loc=0, scale=sensitivity/epsilon) for xdata in dataLst] | |
return noisyLaplaceResponse | |
def GaussianMech (dataLst, epsilon, delta, sensitivity=1): | |
''' | |
Gaussian mechanism | |
input: | |
dataLst: list of element (raw data), 1D | |
epsilon: magnitude of noise | |
delta: attacker's guessing advantage | |
sensitivity: sensitivity of data | |
Output: | |
noisy response from gaussian machanism | |
''' | |
sigma = np.sqrt(2 * sensitivity**2 * np.log(1.25 / delta)) / epsilon | |
noisyGaussianResponse = [ xdata + np.random.normal(loc=0, scale=sigma) for xdata in dataLst] | |
return noisyGaussianResponse | |
def ExponentialMech(x, R, u, sensitivity, epsilon): | |
''' | |
Exponential mechanism | |
input: | |
x: list of element (raw data), 1D | |
R: set of element (raw data), 1D | |
u: ranking functor | |
sensitivity: sensitivity of data | |
epsilon: magnitude of noise | |
Output: | |
noisy response from exponential machanism | |
''' | |
# Calculate the score for each element of R | |
scores = [u(x, r) for r in R] | |
# Calculate the probability for each element, based on its score | |
probabilities = [np.exp(epsilon * score / (2 * sensitivity)) for score in scores] | |
# Normalize the probabilties so they sum to 1 | |
probabilities = probabilities / np.linalg.norm(probabilities, ord=1) | |
# Choose an element from R based on the probabilities | |
return np.random.choice(R, 1, p=probabilities)[0] | |
if __name__ == '__main__': | |
epsilon = 0.0337 | |
delta = 0.1 | |
data = { | |
's/n' : [1, 2, 3, 4, 5, 6], | |
'physics' : [90, 85, 70, 45, 50, 90], | |
'math' : [65, 85, 98, 95, 40, 50], | |
'chem' : [85, 60, 80, 50, 90, 30], | |
} | |
df = pd.DataFrame(data) | |
print ("#########################################") | |
print ("Original data df: \n{}".format(df)) | |
physicsDF = df['physics'] | |
mathDF = df['math'] | |
chemDF = df['chem'] | |
sensPhysics = getSensistivity(physicsDF) # sensitivity of physics | |
sensMath = getSensistivity(mathDF) # sensitivity of maths | |
sensChem = getSensistivity(chemDF) # sensitivity of chemistry | |
sensitivity = max ([sensPhysics, sensMath, sensChem]) | |
print ("sensitivity : {}".format(sensitivity)) | |
print ("#########################################") | |
print ("############Laplace Mechanism############") | |
print ("#########################################") | |
noisyLapPhysics = LaplaceMech (physicsDF, epsilon, sensitivity) | |
noisyLapMath = LaplaceMech (mathDF, epsilon, sensitivity) | |
noisyLapChem = LaplaceMech (chemDF, epsilon, sensitivity) | |
data = { | |
's/n' : [1, 2, 3, 4, 5, 6], | |
'physics' : noisyLapPhysics, | |
'math' : noisyLapMath, | |
'chem' : noisyLapChem, | |
} | |
lapDF = pd.DataFrame(data) | |
print ("Noisy Response: \n{}".format(lapDF)) | |
print ("#########################################") | |
print ("############Gaussian Mechanism###########") | |
print ("#########################################") | |
noisyGausPhysics = GaussianMech (physicsDF, epsilon, delta, sensitivity) | |
noisyGausMath = GaussianMech (mathDF, epsilon, delta, sensitivity) | |
noisyGausChem = GaussianMech (chemDF, epsilon, delta, sensitivity) | |
data = { | |
's/n' : [1, 2, 3, 4, 5, 6], | |
'physics' : noisyGausPhysics, | |
'math' : noisyGausMath, | |
'chem' : noisyGausChem, | |
} | |
gaussianDF = pd.DataFrame(data) | |
print ("Noisy Response: \n{}".format(gaussianDF)) | |
print ("#########################################") | |
print ("###########Exponential Mechanism#########") | |
print ("#########################################") | |
noisyExpPhysics = [ExponentialMech(physicsDF, physicsDF, uFunc2, sensitivity, epsilon) for _ in range(len(physicsDF))] | |
noisyExpMath = [ExponentialMech(mathDF, mathDF, uFunc2, sensitivity, epsilon) for _ in range(len(mathDF))] | |
noisyExpChem = [ExponentialMech(chemDF, chemDF, uFunc2, sensitivity, epsilon) for _ in range(len(chemDF))] | |
data = { | |
's/n' : [1, 2, 3, 4, 5, 6], | |
'physics' : noisyExpPhysics, | |
'math' : noisyExpMath, | |
'chem' : noisyExpChem, | |
} | |
expDF = pd.DataFrame(data) | |
print ("Noisy Response: \n{}".format(expDF)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment