Skip to content

Commit 9369ae7

Browse files
authored
[MNT] Diffprivlib 0.6.2 (#77)
* Deprecating n_features_ attribute in PCA * Updating PCA test * Adding parameter constraints and validation * Updating github actions versions * Updating more github actions versions * Adding library legacy tests * Adding tests to support Python 3.11 * Removing unreachable branch * Updating version number
1 parent 049f463 commit 9369ae7

File tree

16 files changed

+98
-43
lines changed

16 files changed

+98
-43
lines changed

.github/workflows/code.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ jobs:
1414
build:
1515
runs-on: ubuntu-latest
1616
steps:
17-
- uses: actions/checkout@v2
18-
- uses: actions/setup-python@v2
17+
- uses: actions/checkout@v3
18+
- uses: actions/setup-python@v4
1919
with:
20-
python-version: 3.9
20+
python-version: '3.10'
2121
- name: Install dependencies
2222
run: |
2323
python -m pip install --upgrade pip
@@ -28,7 +28,7 @@ jobs:
2828
run: |
2929
pytest --cov-report=xml --cov=diffprivlib --cov-append
3030
- name: Codecov upload
31-
uses: codecov/codecov-action@v2.1.0
31+
uses: codecov/codecov-action@v3
3232
- name: pycodestyle
3333
run: pycodestyle --max-line-length=120 diffprivlib
3434
- name: pylint

.github/workflows/deploy.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ jobs:
1010
runs-on: ubuntu-latest
1111

1212
steps:
13-
- uses: actions/checkout@v2
14-
- uses: actions/setup-python@v2
13+
- uses: actions/checkout@v3
14+
- uses: actions/setup-python@v4
1515
with:
16-
python-version: 3.9
16+
python-version: '3.10'
1717

1818
- name: Update pip
1919
run: python -m pip install --upgrade pip
@@ -33,6 +33,6 @@ jobs:
3333
.
3434
- name: Publish distribution 📦 to PyPI
3535
if: startsWith(github.ref, 'refs/tags')
36-
uses: pypa/gh-action-pypi-publish@master
36+
uses: pypa/gh-action-pypi-publish@release/v1
3737
with:
3838
password: ${{ secrets.PYPI_API_TOKEN }}

.github/workflows/general.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ jobs:
1717
strategy:
1818
fail-fast: false
1919
matrix:
20-
python-version: ['3.8', '3.9', '3.10']
20+
python-version: ['3.8', '3.9', '3.10', '3.11']
2121

2222
steps:
23-
- uses: actions/checkout@v2
23+
- uses: actions/checkout@v3
2424
- name: Set up Python ${{ matrix.python-version }}
25-
uses: actions/setup-python@v2
25+
uses: actions/setup-python@v4
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828
- name: Install dependencies

.github/workflows/libraries.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,19 @@ jobs:
2525
- library: numpy
2626
version: 1.22.4
2727
python-version: '3.10'
28+
- library: numpy
29+
version: 1.23.5
30+
python-version: '3.10'
2831

2932
- library: scikit-learn
3033
version: 0.24.2
3134
python-version: 3.9
3235
- library: scikit-learn
3336
version: 1.0.2
3437
python-version: '3.10'
38+
- library: scikit-learn
39+
version: 1.1.3
40+
python-version: '3.10'
3541

3642
- library: scipy
3743
version: 1.7.3
@@ -44,9 +50,9 @@ jobs:
4450
python-version: '3.10'
4551

4652
steps:
47-
- uses: actions/checkout@v2
53+
- uses: actions/checkout@v3
4854
- name: Set up Python ${{ matrix.python-version }}
49-
uses: actions/setup-python@v2
55+
uses: actions/setup-python@v4
5056
with:
5157
python-version: ${{ matrix.python-version }}
5258
- name: Install dependencies

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Use diffprivlib if you are looking to:
1717
- Explore the impact of differential privacy on machine learning accuracy using classification and clustering models
1818
- Build your own differential privacy applications, using our extensive collection of mechanisms
1919

20-
Diffprivlib supports Python versions 3.8 to 3.10.
20+
Diffprivlib supports Python versions 3.8 to 3.11.
2121

2222
## Getting started: [Machine learning with differential privacy in 30 seconds](https://github.com/IBM/differential-privacy-library/blob/main/notebooks/30seconds.ipynb)
2323
We're using the [Iris dataset](https://archive.ics.uci.edu/ml/datasets/iris), so let's load it and perform an 80/20 train/test split.

diffprivlib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929
from diffprivlib import tools
3030
from diffprivlib.accountant import BudgetAccountant
3131

32-
__version__ = '0.6.1'
32+
__version__ = '0.6.2'

diffprivlib/mechanisms/gaussian.py

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -175,36 +175,33 @@ def b_minus(val):
175175

176176
delta_0 = b_plus(0)
177177

178-
if delta_0 == 0:
179-
alpha = 1
178+
if delta_0 < 0:
179+
target_func = b_plus
180180
else:
181-
if delta_0 < 0:
182-
target_func = b_plus
183-
else:
184-
target_func = b_minus
181+
target_func = b_minus
185182

186-
# Find the starting interval by doubling the initial size until the target_func sign changes, as suggested
187-
# in the paper
188-
left = 0
189-
right = 1
183+
# Find the starting interval by doubling the initial size until the target_func sign changes, as suggested
184+
# in the paper
185+
left = 0
186+
right = 1
190187

191-
while target_func(left) * target_func(right) > 0:
192-
left = right
193-
right *= 2
188+
while target_func(left) * target_func(right) > 0:
189+
left = right
190+
right *= 2
194191

195-
# Binary search code copied from mechanisms.LaplaceBoundedDomain
196-
old_interval_size = (right - left) * 2
192+
# Binary search code copied from mechanisms.LaplaceBoundedDomain
193+
old_interval_size = (right - left) * 2
197194

198-
while old_interval_size > right - left:
199-
old_interval_size = right - left
200-
middle = (right + left) / 2
195+
while old_interval_size > right - left:
196+
old_interval_size = right - left
197+
middle = (right + left) / 2
201198

202-
if target_func(middle) * target_func(left) <= 0:
203-
right = middle
204-
if target_func(middle) * target_func(right) <= 0:
205-
left = middle
199+
if target_func(middle) * target_func(left) <= 0:
200+
right = middle
201+
if target_func(middle) * target_func(right) <= 0:
202+
left = middle
206203

207-
alpha = np.sqrt(1 + (left + right) / 4) + (-1 if delta_0 < 0 else 1) * np.sqrt((left + right) / 4)
204+
alpha = np.sqrt(1 + (left + right) / 4) + (-1 if delta_0 < 0 else 1) * np.sqrt((left + right) / 4)
208205

209206
return alpha * self.sensitivity / np.sqrt(2 * self.epsilon)
210207

diffprivlib/models/forest.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class RandomForestClassifier(skRandomForestClassifier, DiffprivlibMixin): # pyl
128128
129129
"""
130130

131+
_parameter_constraints = DiffprivlibMixin._copy_parameter_constraints(
132+
skRandomForestClassifier, "n_estimators", "n_jobs", "verbose", "random_state", "warm_start")
133+
131134
def __init__(self, n_estimators=10, *, epsilon=1.0, bounds=None, classes=None, n_jobs=1, verbose=0, accountant=None,
132135
random_state=None, max_depth=5, warm_start=False, shuffle=False, **unused_args):
133136
super().__init__(
@@ -145,7 +148,11 @@ def __init__(self, n_estimators=10, *, epsilon=1.0, bounds=None, classes=None, n
145148
self.shuffle = shuffle
146149
self.accountant = BudgetAccountant.load_default(accountant)
147150

148-
self.base_estimator = DecisionTreeClassifier()
151+
# Todo: Remove when scikit-learn v1.2 is a min requirement
152+
if hasattr(self, "estimator"):
153+
self.estimator = DecisionTreeClassifier()
154+
else:
155+
self.base_estimator = DecisionTreeClassifier()
149156
self.estimator_params = ("max_depth", "epsilon", "bounds", "classes")
150157

151158
self._warn_unused_args(unused_args)
@@ -170,6 +177,7 @@ def fit(self, X, y, sample_weight=None):
170177
self : object
171178
Fitted estimator.
172179
"""
180+
self._validate_params()
173181
self.accountant.check(self.epsilon, 0)
174182

175183
if sample_weight is not None:
@@ -250,6 +258,7 @@ def fit(self, X, y, sample_weight=None):
250258
# that case. However, for joblib 0.12+ we respect any
251259
# parallel_backend contexts set at a higher level,
252260
# since correctness does not rely on using threads.
261+
# Todo: Remove when scikit-learn v1.1 is a min requirement
253262
try:
254263
trees = Parallel(n_jobs=self.n_jobs, verbose=self.verbose, prefer="threads")(
255264
delayed(_parallel_build_trees)(
@@ -332,9 +341,12 @@ class DecisionTreeClassifier(skDecisionTreeClassifier, DiffprivlibMixin):
332341
333342
"""
334343

344+
_parameter_constraints = DiffprivlibMixin._copy_parameter_constraints(
345+
skDecisionTreeClassifier, "max_depth", "random_state")
346+
335347
def __init__(self, max_depth=5, *, epsilon=1, bounds=None, classes=None, random_state=None, accountant=None,
336348
**unused_args):
337-
# TODO: Remove try...except when sklearn v1.0 is min-requirement
349+
# Todo: Remove when scikit-learn v1.0 is a min requirement
338350
try:
339351
super().__init__( # pylint: disable=unexpected-keyword-arg
340352
criterion=None,
@@ -391,6 +403,7 @@ def fit(self, X, y, sample_weight=None, check_input=True):
391403
self : DecisionTreeClassifier
392404
Fitted estimator.
393405
"""
406+
self._validate_params()
394407
random_state = check_random_state(self.random_state)
395408

396409
self.accountant.check(self.epsilon, 0)

diffprivlib/models/k_means.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class KMeans(sk_cluster.KMeans, DiffprivlibMixin):
7878
7979
"""
8080

81+
_parameter_constraints = DiffprivlibMixin._copy_parameter_constraints(
82+
sk_cluster.KMeans, "n_clusters", "random_state")
83+
8184
def __init__(self, n_clusters=8, *, epsilon=1.0, bounds=None, random_state=None, accountant=None, **unused_args):
8285
super().__init__(n_clusters=n_clusters, random_state=random_state)
8386

@@ -113,6 +116,7 @@ def fit(self, X, y=None, sample_weight=None):
113116
self : class
114117
115118
"""
119+
self._validate_params()
116120
self.accountant.check(self.epsilon, 0)
117121

118122
if sample_weight is not None:

diffprivlib/models/linear_regression.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ class LinearRegression(sk_lr.LinearRegression, DiffprivlibMixin):
221221
regression analysis under differential privacy." arXiv preprint arXiv:1208.0219 (2012).
222222
223223
"""
224+
225+
_parameter_constraints = DiffprivlibMixin._copy_parameter_constraints(
226+
sk_lr.LinearRegression, "fit_intercept", "copy_X")
227+
224228
def __init__(self, *, epsilon=1.0, bounds_X=None, bounds_y=None, fit_intercept=True, copy_X=True, random_state=None,
225229
accountant=None, **unused_args):
226230
super().__init__(fit_intercept=fit_intercept, copy_X=copy_X, n_jobs=None)
@@ -253,6 +257,7 @@ def fit(self, X, y, sample_weight=None):
253257
self : returns an instance of self.
254258
255259
"""
260+
self._validate_params()
256261
self.accountant.check(self.epsilon, 0)
257262

258263
if sample_weight is not None:

0 commit comments

Comments
 (0)