Skip to content

Instantly share code, notes, and snippets.

@kenluck2001
Created October 2, 2023 03:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenluck2001/06625f60217180b31063dff7464e0ac8 to your computer and use it in GitHub Desktop.
Save kenluck2001/06625f60217180b31063dff7464e0ac8 to your computer and use it in GitHub Desktop.
Differential privacy mechanisms
"""
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