aisp 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aisp/__init__.py +1 -1
- aisp/base/__init__.py +3 -1
- aisp/base/_base.py +65 -0
- aisp/base/_classifier.py +9 -17
- aisp/base/_clusterer.py +76 -0
- aisp/base/mutation.py +44 -0
- aisp/csa/__init__.py +1 -1
- aisp/csa/{_ai_immune_recognition_sys.py → _ai_recognition_sys.py} +49 -60
- aisp/csa/_base.py +10 -25
- aisp/csa/_cell.py +20 -6
- aisp/exceptions.py +17 -1
- aisp/ina/__init__.py +14 -0
- aisp/ina/_ai_network.py +553 -0
- aisp/ina/_base.py +124 -0
- aisp/nsa/_base.py +3 -3
- aisp/nsa/_negative_selection.py +70 -76
- aisp/utils/distance.py +4 -4
- aisp/utils/types.py +31 -0
- aisp/utils/validation.py +47 -0
- {aisp-0.2.0.dist-info → aisp-0.3.0.dist-info}/METADATA +11 -5
- aisp-0.3.0.dist-info/RECORD +30 -0
- {aisp-0.2.0.dist-info → aisp-0.3.0.dist-info}/WHEEL +1 -1
- aisp-0.2.0.dist-info/RECORD +0 -23
- {aisp-0.2.0.dist-info → aisp-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {aisp-0.2.0.dist-info → aisp-0.3.0.dist-info}/top_level.txt +0 -0
aisp/ina/_base.py
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
"""Base Class for Network Theory Algorithms."""
|
2
|
+
|
3
|
+
from abc import ABC
|
4
|
+
from typing import Optional
|
5
|
+
|
6
|
+
from numpy import typing as npt
|
7
|
+
|
8
|
+
import numpy as np
|
9
|
+
|
10
|
+
from ..base import BaseClusterer
|
11
|
+
from ..exceptions import FeatureDimensionMismatch
|
12
|
+
from ..utils.types import FeatureType
|
13
|
+
|
14
|
+
|
15
|
+
class BaseAiNet(BaseClusterer, ABC):
|
16
|
+
"""Abstract base class for AINet-based clustering algorithms."""
|
17
|
+
|
18
|
+
@staticmethod
|
19
|
+
def _check_and_raise_exceptions_fit(
|
20
|
+
X: npt.NDArray
|
21
|
+
):
|
22
|
+
"""
|
23
|
+
Verify the fit parameters and throw exceptions if the verification is not successful.
|
24
|
+
|
25
|
+
Parameters
|
26
|
+
----------
|
27
|
+
X : npt.NDArray
|
28
|
+
Training array, containing the samples and their characteristics,
|
29
|
+
[``N samples`` (rows)][``N features`` (columns)].
|
30
|
+
|
31
|
+
Raises
|
32
|
+
------
|
33
|
+
TypeError
|
34
|
+
If X is not an ndarray or list.
|
35
|
+
"""
|
36
|
+
if not isinstance(X, np.ndarray) and not isinstance(X, list):
|
37
|
+
raise TypeError("X is not an ndarray or list.")
|
38
|
+
|
39
|
+
@staticmethod
|
40
|
+
def _check_and_raise_exceptions_predict(
|
41
|
+
X: npt.NDArray,
|
42
|
+
expected: int = 0,
|
43
|
+
feature_type: FeatureType = "continuous-features"
|
44
|
+
) -> None:
|
45
|
+
"""
|
46
|
+
Verify the predict parameters and throw exceptions if the verification is not successful.
|
47
|
+
|
48
|
+
Parameters
|
49
|
+
----------
|
50
|
+
X : npt.NDArray
|
51
|
+
Input array for prediction, containing the samples and their characteristics,
|
52
|
+
[``N samples`` (rows)][``N features`` (columns)].
|
53
|
+
expected : int, default=0
|
54
|
+
Expected number of features per sample (columns in X).
|
55
|
+
feature_type : FeatureType, default="continuous-features"
|
56
|
+
Specifies the type of features: "continuous-features", "binary-features",
|
57
|
+
or "ranged-features".
|
58
|
+
|
59
|
+
|
60
|
+
Raises
|
61
|
+
------
|
62
|
+
TypeError
|
63
|
+
If X is not a ndarray or list.
|
64
|
+
FeatureDimensionMismatch
|
65
|
+
If the number of features in X does not match the expected number.
|
66
|
+
ValueError
|
67
|
+
If feature_type is "binary-features" and X contains values other than 0 and 1.
|
68
|
+
"""
|
69
|
+
if not isinstance(X, (np.ndarray, list)):
|
70
|
+
raise TypeError("X is not an ndarray or list")
|
71
|
+
if expected != len(X[0]):
|
72
|
+
raise FeatureDimensionMismatch(
|
73
|
+
expected,
|
74
|
+
len(X[0]),
|
75
|
+
"X"
|
76
|
+
)
|
77
|
+
|
78
|
+
if feature_type != "binary-features":
|
79
|
+
return
|
80
|
+
|
81
|
+
# Checks if matrix X contains only binary samples. Otherwise, raises an exception.
|
82
|
+
if not np.isin(X, [0, 1]).all():
|
83
|
+
raise ValueError(
|
84
|
+
"The array X contains values that are not composed only of 0 and 1."
|
85
|
+
)
|
86
|
+
|
87
|
+
@staticmethod
|
88
|
+
def _generate_random_antibodies(
|
89
|
+
n_samples: int,
|
90
|
+
n_features: int,
|
91
|
+
feature_type: FeatureType = "continuous-features",
|
92
|
+
bounds: Optional[npt.NDArray[np.float64]] = None
|
93
|
+
) -> npt.NDArray:
|
94
|
+
"""
|
95
|
+
Generate a random antibody population.
|
96
|
+
|
97
|
+
Parameters
|
98
|
+
----------
|
99
|
+
n_samples : int
|
100
|
+
Number of antibodies (samples) to generate.
|
101
|
+
n_features : int
|
102
|
+
Number of features (dimensions) for each antibody.
|
103
|
+
feature_type : FeatureType, default="continuous-features"
|
104
|
+
Specifies the type of features: "continuous-features", "binary-features",
|
105
|
+
or "ranged-features".
|
106
|
+
bounds : np.ndarray
|
107
|
+
Array (n_features, 2) with min and max per dimension.
|
108
|
+
|
109
|
+
Returns
|
110
|
+
-------
|
111
|
+
npt.NDArray
|
112
|
+
Array of shape (n_samples, n_features) containing the generated antibodies.
|
113
|
+
Data type depends on the feature_type type (float for continuous/ranged, bool for
|
114
|
+
binary).
|
115
|
+
"""
|
116
|
+
if n_features <= 0:
|
117
|
+
raise ValueError("Number of features must be greater than zero.")
|
118
|
+
|
119
|
+
if feature_type == "binary-features":
|
120
|
+
return np.random.randint(0, 2, size=(n_samples, n_features)).astype(np.bool_)
|
121
|
+
if feature_type == "ranged-features" and bounds is not None:
|
122
|
+
return np.random.uniform(low=bounds[0], high=bounds[1], size=(n_samples, n_features))
|
123
|
+
|
124
|
+
return np.random.random_sample(size=(n_samples, n_features))
|
aisp/nsa/_base.py
CHANGED
@@ -20,8 +20,8 @@ class BaseNSA(BaseClassifier, ABC):
|
|
20
20
|
|
21
21
|
@staticmethod
|
22
22
|
def _check_and_raise_exceptions_fit(
|
23
|
-
X: npt.NDArray
|
24
|
-
y: npt.NDArray
|
23
|
+
X: npt.NDArray,
|
24
|
+
y: npt.NDArray,
|
25
25
|
_class_: Literal["RNSA", "BNSA"] = "RNSA",
|
26
26
|
) -> None:
|
27
27
|
"""Verify fit function parameters.
|
@@ -67,7 +67,7 @@ class BaseNSA(BaseClassifier, ABC):
|
|
67
67
|
|
68
68
|
@staticmethod
|
69
69
|
def _check_and_raise_exceptions_predict(
|
70
|
-
X: npt.NDArray
|
70
|
+
X: npt.NDArray,
|
71
71
|
expected: int = 0,
|
72
72
|
_class_: Literal["RNSA", "BNSA"] = "RNSA",
|
73
73
|
) -> None:
|
aisp/nsa/_negative_selection.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
"""Negative Selection Algorithm."""
|
2
2
|
|
3
|
-
from typing import Dict, Literal, Optional, Union
|
3
|
+
from typing import Any, Dict, Literal, Optional, Union
|
4
4
|
from tqdm import tqdm
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
import numpy.typing as npt
|
8
8
|
|
9
|
+
from ..base import set_seed_numba
|
9
10
|
from ._ns_core import (
|
10
11
|
check_detector_bnsa_validity,
|
11
12
|
bnsa_class_prediction,
|
@@ -90,14 +91,15 @@ class RNSA(BaseNSA):
|
|
90
91
|
k: int = 1,
|
91
92
|
metric: Literal["manhattan", "minkowski", "euclidean"] = "euclidean",
|
92
93
|
max_discards: int = 1000,
|
93
|
-
seed: int = None,
|
94
|
+
seed: Optional[int] = None,
|
94
95
|
algorithm: Literal["default-NSA", "V-detector"] = "default-NSA",
|
95
|
-
**kwargs:
|
96
|
+
**kwargs: Any,
|
96
97
|
):
|
97
|
-
self.metric = sanitize_choice(metric, ["manhattan", "minkowski"], "euclidean")
|
98
|
-
self.seed = sanitize_seed(seed)
|
98
|
+
self.metric: str = sanitize_choice(metric, ["manhattan", "minkowski"], "euclidean")
|
99
|
+
self.seed: Optional[int] = sanitize_seed(seed)
|
99
100
|
if self.seed is not None:
|
100
101
|
np.random.seed(seed)
|
102
|
+
set_seed_numba(self.seed)
|
101
103
|
self.k: int = sanitize_param(k, 1, lambda x: x > 1)
|
102
104
|
self.N: int = sanitize_param(N, 100, lambda x: x >= 1)
|
103
105
|
self.r: float = sanitize_param(r, 0.05, lambda x: x > 0)
|
@@ -108,20 +110,20 @@ class RNSA(BaseNSA):
|
|
108
110
|
self.max_discards: int = sanitize_param(max_discards, 1000, lambda x: x > 0)
|
109
111
|
|
110
112
|
# Retrieves the variables from kwargs.
|
111
|
-
self.p:
|
112
|
-
self.cell_bounds: bool = kwargs.get("cell_bounds", False)
|
113
|
-
self.non_self_label: str = kwargs.get("non_self_label", "non-self")
|
113
|
+
self.p: np.float64 = np.float64(kwargs.get("p", 2))
|
114
|
+
self.cell_bounds: bool = bool(kwargs.get("cell_bounds", False))
|
115
|
+
self.non_self_label: str = str(kwargs.get("non_self_label", "non-self"))
|
114
116
|
|
115
117
|
# Initializes the other class variables as None.
|
116
118
|
self._detectors: Union[dict, None] = None
|
117
|
-
self.classes: npt.NDArray =
|
119
|
+
self.classes: Union[npt.NDArray, list] = []
|
118
120
|
|
119
121
|
@property
|
120
|
-
def detectors(self) -> Dict[str, list[Detector]]:
|
122
|
+
def detectors(self) -> Optional[Dict[str, list[Detector]]]:
|
121
123
|
"""Returns the trained detectors, organized by class."""
|
122
124
|
return self._detectors
|
123
125
|
|
124
|
-
def fit(self, X: npt.NDArray, y: npt.NDArray, verbose: bool = True):
|
126
|
+
def fit(self, X: npt.NDArray, y: npt.NDArray, verbose: bool = True) -> "RNSA":
|
125
127
|
"""
|
126
128
|
Perform training according to X and y, using the negative selection method (NegativeSelect).
|
127
129
|
|
@@ -148,7 +150,6 @@ class RNSA(BaseNSA):
|
|
148
150
|
self : RNSA
|
149
151
|
Returns the instance itself.
|
150
152
|
"""
|
151
|
-
progress = None
|
152
153
|
super()._check_and_raise_exceptions_fit(X, y)
|
153
154
|
|
154
155
|
# Identifying the possible classes within the output array `y`.
|
@@ -158,22 +159,21 @@ class RNSA(BaseNSA):
|
|
158
159
|
# Separates the classes for training.
|
159
160
|
sample_index = self._slice_index_list_by_class(y)
|
160
161
|
# Progress bar for generating all detectors.
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
162
|
+
progress = tqdm(
|
163
|
+
total=int(self.N * (len(self.classes))),
|
164
|
+
bar_format="{desc} ┇{bar}┇ {n}/{total} detectors",
|
165
|
+
postfix="\n",
|
166
|
+
disable=not verbose
|
167
|
+
)
|
167
168
|
for _class_ in self.classes:
|
168
169
|
# Initializes the empty set that will contain the valid detectors.
|
169
170
|
valid_detectors_set = []
|
170
171
|
discard_count = 0
|
171
172
|
x_class = X[sample_index[_class_]]
|
172
173
|
# Indicating which class the algorithm is currently processing for the progress bar.
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
)
|
174
|
+
progress.set_description_str(
|
175
|
+
f"Generating the detectors for the {_class_} class:"
|
176
|
+
)
|
177
177
|
while len(valid_detectors_set) < self.N:
|
178
178
|
# Generates a candidate detector vector randomly with values between 0 and 1.
|
179
179
|
vector_x = np.random.random_sample(size=X.shape[1])
|
@@ -183,12 +183,12 @@ class RNSA(BaseNSA):
|
|
183
183
|
# If the detector is valid, add it to the list of valid detectors.
|
184
184
|
if valid_detector is not False:
|
185
185
|
discard_count = 0
|
186
|
-
|
187
|
-
valid_detector[1]
|
188
|
-
|
186
|
+
if self.algorithm == "V-detector" and isinstance(valid_detector, tuple):
|
187
|
+
radius = valid_detector[1]
|
188
|
+
else:
|
189
|
+
radius = None
|
189
190
|
valid_detectors_set.append(Detector(vector_x, radius))
|
190
|
-
|
191
|
-
progress.update(1)
|
191
|
+
progress.update(1)
|
192
192
|
else:
|
193
193
|
discard_count += 1
|
194
194
|
if discard_count == self.max_discards:
|
@@ -197,11 +197,11 @@ class RNSA(BaseNSA):
|
|
197
197
|
# Add detectors, with classes as keys in the dictionary.
|
198
198
|
list_detectors_by_class[_class_] = valid_detectors_set
|
199
199
|
# Notify completion of detector generation for the classes.
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
progress.set_description(
|
201
|
+
f"\033[92m✔ Non-self detectors for classes ({', '.join(map(str, self.classes))}) "
|
202
|
+
f"successfully generated\033[0m"
|
203
|
+
)
|
204
|
+
progress.close()
|
205
205
|
# Saves the found detectors in the attribute for the non-self detectors of the trained model
|
206
206
|
self._detectors = list_detectors_by_class
|
207
207
|
return self
|
@@ -258,9 +258,7 @@ class RNSA(BaseNSA):
|
|
258
258
|
elif not class_found:
|
259
259
|
average_distance: dict = {}
|
260
260
|
for _class_ in self.classes:
|
261
|
-
detectores =
|
262
|
-
map(lambda x: x.position, self._detectors[_class_])
|
263
|
-
)
|
261
|
+
detectores = [x.position for x in self._detectors[_class_]]
|
264
262
|
average_distance[_class_] = np.average(
|
265
263
|
[self.__distance(detector, line) for detector in detectores]
|
266
264
|
)
|
@@ -291,17 +289,17 @@ class RNSA(BaseNSA):
|
|
291
289
|
# If self.k > 1, uses the k nearest neighbors (kNN); otherwise, checks the detector
|
292
290
|
# without considering kNN.
|
293
291
|
if self.k > 1:
|
294
|
-
knn_list = []
|
292
|
+
knn_list: list = []
|
295
293
|
for x in x_class:
|
296
294
|
# Calculates the distance between the two vectors and adds it to the kNN list if
|
297
295
|
# the distance is smaller than the largest distance in the list.
|
298
|
-
|
296
|
+
self.__compare_knearest_neighbors_list(
|
299
297
|
knn_list, self.__distance(x, vector_x)
|
300
298
|
)
|
301
299
|
# If the average of the distances in the kNN list is less than the radius, Returns true.
|
302
300
|
distance_mean = np.mean(knn_list)
|
303
301
|
if self.algorithm == "V-detector":
|
304
|
-
return self.__detector_is_valid_to_vdetector(distance_mean, vector_x)
|
302
|
+
return self.__detector_is_valid_to_vdetector(float(distance_mean), vector_x)
|
305
303
|
if distance_mean > (self.r + self.r_s):
|
306
304
|
return True
|
307
305
|
else:
|
@@ -323,8 +321,8 @@ class RNSA(BaseNSA):
|
|
323
321
|
return False # Detector is not valid!
|
324
322
|
|
325
323
|
def __compare_knearest_neighbors_list(
|
326
|
-
self, knn:
|
327
|
-
) ->
|
324
|
+
self, knn: list, distance: float
|
325
|
+
) -> None:
|
328
326
|
"""
|
329
327
|
Compare the k-nearest neighbor distance at position k=1 in the list knn.
|
330
328
|
|
@@ -336,17 +334,11 @@ class RNSA(BaseNSA):
|
|
336
334
|
List of k-nearest neighbor distances.
|
337
335
|
distance : float
|
338
336
|
Distance to check.
|
339
|
-
|
340
|
-
Returns
|
341
|
-
-------
|
342
|
-
knn : npt.NDArray
|
343
|
-
Updated and sorted nearest neighbor list.
|
344
337
|
"""
|
345
338
|
# If the number of distances in kNN is less than k, adds the distance.
|
346
339
|
if len(knn) < self.k:
|
347
|
-
knn
|
340
|
+
knn.append(distance)
|
348
341
|
knn.sort()
|
349
|
-
return knn
|
350
342
|
|
351
343
|
# Otherwise, add the distance if the new distance is smaller than the largest
|
352
344
|
# distance in the list.
|
@@ -354,8 +346,6 @@ class RNSA(BaseNSA):
|
|
354
346
|
knn[self.k - 1] = distance
|
355
347
|
knn.sort()
|
356
348
|
|
357
|
-
return knn
|
358
|
-
|
359
349
|
def __compare_sample_to_detectors(self, line: npt.NDArray) -> Optional[str]:
|
360
350
|
"""
|
361
351
|
Compare a sample with the detectors, verifying if the sample is proper.
|
@@ -371,6 +361,9 @@ class RNSA(BaseNSA):
|
|
371
361
|
Returns the predicted class with the detectors or None if the sample does not qualify
|
372
362
|
for any class.
|
373
363
|
"""
|
364
|
+
if self._detectors is None:
|
365
|
+
return None
|
366
|
+
|
374
367
|
# List to store the classes and the average distance between the detectors and the sample.
|
375
368
|
possible_classes = []
|
376
369
|
for _class_ in self.classes:
|
@@ -453,7 +446,7 @@ class RNSA(BaseNSA):
|
|
453
446
|
if (p - new_detector_r) < 0 or (p + new_detector_r) > 1:
|
454
447
|
return False
|
455
448
|
|
456
|
-
return
|
449
|
+
return True, new_detector_r
|
457
450
|
|
458
451
|
|
459
452
|
class BNSA(BaseNSA):
|
@@ -491,7 +484,7 @@ class BNSA(BaseNSA):
|
|
491
484
|
N: int = 100,
|
492
485
|
aff_thresh: float = 0.1,
|
493
486
|
max_discards: int = 1000,
|
494
|
-
seed: int = None,
|
487
|
+
seed: Optional[int] = None,
|
495
488
|
no_label_sample_selection: Literal[
|
496
489
|
"max_average_difference", "max_nearest_difference"
|
497
490
|
] = "max_average_difference",
|
@@ -500,27 +493,27 @@ class BNSA(BaseNSA):
|
|
500
493
|
self.aff_thresh: float = sanitize_param(aff_thresh, 0.1, lambda x: 0 < x < 1)
|
501
494
|
self.max_discards: float = sanitize_param(max_discards, 1000, lambda x: x > 0)
|
502
495
|
|
503
|
-
self.seed = sanitize_seed(seed)
|
496
|
+
self.seed: Optional[int] = sanitize_seed(seed)
|
504
497
|
|
505
498
|
if self.seed is not None:
|
506
499
|
np.random.seed(seed)
|
507
500
|
|
508
|
-
self.no_label_sample_selection:
|
501
|
+
self.no_label_sample_selection: str = sanitize_param(
|
509
502
|
no_label_sample_selection,
|
510
503
|
"max_average_difference",
|
511
504
|
lambda x: x == "nearest_difference",
|
512
505
|
)
|
513
506
|
|
514
|
-
self.classes: npt.NDArray =
|
507
|
+
self.classes: Union[npt.NDArray, list] = []
|
515
508
|
self._detectors: Optional[dict] = None
|
516
|
-
self._detectors_stack: npt.NDArray = None
|
509
|
+
self._detectors_stack: Optional[npt.NDArray] = None
|
517
510
|
|
518
511
|
@property
|
519
|
-
def detectors(self) -> Dict[str, npt.NDArray[np.bool_]]:
|
512
|
+
def detectors(self) -> Optional[Dict[str, npt.NDArray[np.bool_]]]:
|
520
513
|
"""Returns the trained detectors, organized by class."""
|
521
514
|
return self._detectors
|
522
515
|
|
523
|
-
def fit(self, X: npt.NDArray, y: npt.NDArray, verbose: bool = True):
|
516
|
+
def fit(self, X: npt.NDArray, y: npt.NDArray, verbose: bool = True) -> "BNSA":
|
524
517
|
"""Training according to X and y, using the method negative selection method.
|
525
518
|
|
526
519
|
Parameters
|
@@ -539,7 +532,6 @@ class BNSA(BaseNSA):
|
|
539
532
|
Returns the instance it self.
|
540
533
|
"""
|
541
534
|
super()._check_and_raise_exceptions_fit(X, y, "BNSA")
|
542
|
-
|
543
535
|
# Converts the entire array X to boolean
|
544
536
|
X = X.astype(np.bool_)
|
545
537
|
|
@@ -550,22 +542,22 @@ class BNSA(BaseNSA):
|
|
550
542
|
# Separates the classes for training.
|
551
543
|
sample_index: dict = self._slice_index_list_by_class(y)
|
552
544
|
# Progress bar for generating all detectors.
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
545
|
+
|
546
|
+
progress = tqdm(
|
547
|
+
total=int(self.N * (len(self.classes))),
|
548
|
+
bar_format="{desc} ┇{bar}┇ {n}/{total} detectors",
|
549
|
+
postfix="\n",
|
550
|
+
disable=not verbose
|
551
|
+
)
|
559
552
|
|
560
553
|
for _class_ in self.classes:
|
561
554
|
# Initializes the empty set that will contain the valid detectors.
|
562
555
|
valid_detectors_set: list = []
|
563
556
|
discard_count: int = 0
|
564
557
|
# Updating the progress bar with the current class the algorithm is processing.
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
)
|
558
|
+
progress.set_description_str(
|
559
|
+
f"Generating the detectors for the {_class_} class:"
|
560
|
+
)
|
569
561
|
x_class = X[sample_index[_class_]]
|
570
562
|
while len(valid_detectors_set) < self.N:
|
571
563
|
# Generates a candidate detector vector randomly with values 0 and 1.
|
@@ -574,8 +566,7 @@ class BNSA(BaseNSA):
|
|
574
566
|
if check_detector_bnsa_validity(x_class, vector_x, self.aff_thresh):
|
575
567
|
discard_count = 0
|
576
568
|
valid_detectors_set.append(vector_x)
|
577
|
-
|
578
|
-
progress.update(1)
|
569
|
+
progress.update(1)
|
579
570
|
else:
|
580
571
|
discard_count += 1
|
581
572
|
if discard_count == self.max_discards:
|
@@ -585,11 +576,11 @@ class BNSA(BaseNSA):
|
|
585
576
|
list_detectors_by_class[_class_] = np.array(valid_detectors_set)
|
586
577
|
|
587
578
|
# Notify the completion of detector generation for the classes.
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
579
|
+
progress.set_description(
|
580
|
+
f"\033[92m✔ Non-self detectors for classes ({', '.join(map(str, self.classes))}) "
|
581
|
+
f"successfully generated\033[0m"
|
582
|
+
)
|
583
|
+
progress.close()
|
593
584
|
# Saves the found detectors in the attribute for the class detectors.
|
594
585
|
self._detectors = list_detectors_by_class
|
595
586
|
self._detectors_stack = np.array(
|
@@ -613,7 +604,7 @@ class BNSA(BaseNSA):
|
|
613
604
|
``X``. Returns``None``: If there are no detectors for the prediction.
|
614
605
|
"""
|
615
606
|
# If there are no detectors, Returns None.
|
616
|
-
if self._detectors is None:
|
607
|
+
if self._detectors is None or self._detectors_stack is None:
|
617
608
|
return None
|
618
609
|
|
619
610
|
super()._check_and_raise_exceptions_predict(
|
@@ -664,6 +655,9 @@ class BNSA(BaseNSA):
|
|
664
655
|
c : list
|
665
656
|
List of predictions to be updated with the new classification.
|
666
657
|
"""
|
658
|
+
if self._detectors is None:
|
659
|
+
raise ValueError("Detectors is not initialized.")
|
660
|
+
|
667
661
|
class_differences: dict = {}
|
668
662
|
for _class_ in self.classes:
|
669
663
|
distances = np.sum(line != self._detectors[_class_]) / self.N
|
aisp/utils/distance.py
CHANGED
@@ -5,10 +5,10 @@ import numpy.typing as npt
|
|
5
5
|
from numba import njit, types
|
6
6
|
from numpy import float64
|
7
7
|
|
8
|
-
EUCLIDEAN = 0
|
9
|
-
MANHATTAN = 1
|
10
|
-
MINKOWSKI = 2
|
11
|
-
HAMMING = 3
|
8
|
+
EUCLIDEAN: int = 0
|
9
|
+
MANHATTAN: int = 1
|
10
|
+
MINKOWSKI: int = 2
|
11
|
+
HAMMING: int = 3
|
12
12
|
|
13
13
|
|
14
14
|
@njit([(types.boolean[:], types.boolean[:])], cache=True)
|
aisp/utils/types.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
"""
|
2
|
+
Defines type aliases used throughout the project to improve readability.
|
3
|
+
|
4
|
+
Type Aliases
|
5
|
+
------------
|
6
|
+
FeatureType : Literal["binary-features", "continuous-features", "ranged-features"]
|
7
|
+
Specifies the type of features in the input data. Can be one of:
|
8
|
+
- "binary-features": Features with binary values (e.g., 0 or 1).
|
9
|
+
- "continuous-features": Features with continuous numeric values.
|
10
|
+
- "ranged-features": Features represented by ranges or intervals.
|
11
|
+
|
12
|
+
MetricType : Literal["manhattan", "minkowski", "euclidean"]
|
13
|
+
Specifies the distance metric to use for calculations. Possible values:
|
14
|
+
- "manhattan": The calculation of the distance is given by the expression:
|
15
|
+
√( (x₁ – x₂)² + (y₁ – y₂)² + ... + (yn – yn)²).
|
16
|
+
- "minkowski": The calculation of the distance is given by the expression:
|
17
|
+
( |X₁ – Y₁|p + |X₂ – Y₂|p + ... + |Xn – Yn|p) ¹/ₚ.
|
18
|
+
- "euclidean": The calculation of the distance is given by the expression:
|
19
|
+
( |x₁ – x₂| + |y₁ – y₂| + ... + |yn – yn|).
|
20
|
+
"""
|
21
|
+
|
22
|
+
|
23
|
+
from typing import Literal, TypeAlias
|
24
|
+
|
25
|
+
|
26
|
+
FeatureType: TypeAlias = Literal[
|
27
|
+
"binary-features",
|
28
|
+
"continuous-features",
|
29
|
+
"ranged-features"
|
30
|
+
]
|
31
|
+
MetricType: TypeAlias = Literal["manhattan", "minkowski", "euclidean"]
|
aisp/utils/validation.py
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
"""Contains functions responsible for validating data types."""
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
import numpy.typing as npt
|
5
|
+
|
6
|
+
from .types import FeatureType
|
7
|
+
from ..exceptions import UnsupportedTypeError
|
8
|
+
|
9
|
+
|
10
|
+
def detect_vector_data_type(
|
11
|
+
vector: npt.NDArray
|
12
|
+
) -> FeatureType:
|
13
|
+
"""
|
14
|
+
Detect the type of data in a vector.
|
15
|
+
|
16
|
+
The function detects if the vector contains data of type:
|
17
|
+
- Binary features: boolean values or integers restricted to 0 and 1.
|
18
|
+
- Continuous features: floating-point values in the normalized range [0.0, 1.0].
|
19
|
+
- Ranged features: floating-point values outside the normalized range.
|
20
|
+
|
21
|
+
Parameters
|
22
|
+
----------
|
23
|
+
vector: npt.NDArray
|
24
|
+
An array containing the data to be classified.
|
25
|
+
|
26
|
+
Returns
|
27
|
+
-------
|
28
|
+
str
|
29
|
+
The data type of the vector: "binary-features", "continuous-features", or "ranged-features".
|
30
|
+
|
31
|
+
Raises
|
32
|
+
------
|
33
|
+
UnsupportedDataTypeError
|
34
|
+
If the data type of the vector is not supported by the function.
|
35
|
+
"""
|
36
|
+
if vector.dtype == np.bool_:
|
37
|
+
return "binary-features"
|
38
|
+
|
39
|
+
if np.issubdtype(vector.dtype, np.integer) and np.isin(vector, [0, 1]).all():
|
40
|
+
return "binary-features"
|
41
|
+
|
42
|
+
if np.issubdtype(vector.dtype, np.floating):
|
43
|
+
if np.all(vector >= 0.0) and np.all(vector <= 1.0):
|
44
|
+
return "continuous-features"
|
45
|
+
return "ranged-features"
|
46
|
+
|
47
|
+
raise UnsupportedTypeError()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: aisp
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
4
4
|
Summary: Package with techniques of artificial immune systems.
|
5
5
|
Author-email: João Paulo da Silva Barros <jpsilvabarr@gmail.com>
|
6
6
|
Maintainer-email: Alison Zille Lopes <alisonzille@gmail.com>
|
@@ -26,6 +26,11 @@ Requires-Dist: numpy>=1.22.4
|
|
26
26
|
Requires-Dist: numba>=0.59.0
|
27
27
|
Requires-Dist: scipy>=1.8.1
|
28
28
|
Requires-Dist: tqdm>=4.64.1
|
29
|
+
Provides-Extra: dev
|
30
|
+
Requires-Dist: build>=1.2.2.post1; extra == "dev"
|
31
|
+
Requires-Dist: ipykernel>=6.29.5; extra == "dev"
|
32
|
+
Requires-Dist: twine>=5.1.1; extra == "dev"
|
33
|
+
Requires-Dist: pytest>=8.3.5; extra == "dev"
|
29
34
|
Dynamic: license-file
|
30
35
|
|
31
36
|
<div align = center>
|
@@ -79,10 +84,11 @@ Artificial Immune Systems (AIS) are inspired by the vertebrate immune system, cr
|
|
79
84
|
##### Algorithms implemented:
|
80
85
|
|
81
86
|
> - [x] [**Negative Selection.**](https://ais-package.github.io/docs/aisp-techniques/Negative%20Selection/)
|
82
|
-
> - [x] **Clonal Selection Algorithms.**
|
83
|
-
> * [AIRS - Artificial Immune Recognition System](https://ais-package.github.io/docs/aisp-techniques/Clonal%20Selection%20Algorithms/)
|
84
|
-
> - [ ] *
|
85
|
-
> - [
|
87
|
+
> - [x] [**Clonal Selection Algorithms.**](https://ais-package.github.io/docs/aisp-techniques/Clonal%20Selection%20Algorithms/)
|
88
|
+
> * [AIRS - Artificial Immune Recognition System](https://ais-package.github.io/docs/aisp-techniques/Clonal%20Selection%20Algorithms/airs/)
|
89
|
+
> - [ ] *Danger Theory.*
|
90
|
+
> - [x] [*Immune Network Theory.*](https://ais-package.github.io/docs/aisp-techniques/Immune%20Network%20Theory)
|
91
|
+
> - [AiNet - Artificial Immune Network para Clustering and Compression](https://ais-package.github.io/docs/aisp-techniques/Immune%20Network%20Theory/ainet)
|
86
92
|
|
87
93
|
</section>
|
88
94
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
aisp/__init__.py,sha256=GUbFSuDKAfnn80xxK4giPZxuAakRl5dHC5gdp_WTJU0,111
|
2
|
+
aisp/exceptions.py,sha256=I9JaQx6p8Jo7qjwwcrqnuewQgyBdUnOSSZofPoBeDNE,1954
|
3
|
+
aisp/base/__init__.py,sha256=cDDN6YcYqSU080AvEankhUtIALkSTVmm6XTa48htHjU,211
|
4
|
+
aisp/base/_base.py,sha256=uTVh__hQJGe8RCOzCet4ZV3vQbwgj5fXAt4Jdf0x1r0,1792
|
5
|
+
aisp/base/_classifier.py,sha256=yGxRGhJxN8jIpr6S7_fsaEOCMPFws8rNCF4E-hYs37E,3339
|
6
|
+
aisp/base/_clusterer.py,sha256=VKwhX8oHMc7ylsSu2jnbw3uar3GHc2AMSNPMEmwrPo0,2432
|
7
|
+
aisp/base/mutation.py,sha256=A_AlGp8S4ooFEMW3Jgv0n0Y6tbhfusaMMWFsoH4HmD8,4762
|
8
|
+
aisp/csa/__init__.py,sha256=708jwpqia10bqmh-4-_srwwNuBh7jf2Zix-u8Hfbzmk,348
|
9
|
+
aisp/csa/_ai_recognition_sys.py,sha256=_niEark6HNsu9ognXussura16KeCw4mi3xU4Xm18hQo,18760
|
10
|
+
aisp/csa/_base.py,sha256=jR1IIhGINn7DLo8V5iJinDn-wW-t6etcE39bAZnQylw,3595
|
11
|
+
aisp/csa/_cell.py,sha256=GUxnzvPyIbBm1YYkMhSx0tcV_oyDhJ7wAo5gtr_1CoY,1845
|
12
|
+
aisp/ina/__init__.py,sha256=cOnxGcxrBdg6lLv2w2sdlToMahKMh_Gw57AfUUPQjMo,329
|
13
|
+
aisp/ina/_ai_network.py,sha256=aNXNWdFvgmjqki7-lWApLZWq5w1OVUuZpgxsnluiqNE,21053
|
14
|
+
aisp/ina/_base.py,sha256=x9eFUKiAcXSfwqVyBVmS54FDeIcApEtFPGruZvwQOwQ,4404
|
15
|
+
aisp/nsa/__init__.py,sha256=3cXuBmO-_Dp3-8ZG3Eu8e_bD1JDb-RH4Wu0UDNVD1bs,385
|
16
|
+
aisp/nsa/_base.py,sha256=3YKlZzA3yhP2uQHfhyKswbHUutlxkOR4wn6N10nSO-w,4119
|
17
|
+
aisp/nsa/_negative_selection.py,sha256=4FA0fwGVHpSsParsUUdNnnv0FYtJS4_olZBWWiPODk8,28153
|
18
|
+
aisp/nsa/_ns_core.py,sha256=SXkZL-p2VQygU4Pf6J5AP_yPzU4cR6aU6wx-e_vlm-c,5021
|
19
|
+
aisp/utils/__init__.py,sha256=RzpKhkg8nCZi4G0C4il97f3ESYs7Bbxq6EjTeOQQUGk,195
|
20
|
+
aisp/utils/_multiclass.py,sha256=nWd58ayVfxgdopBQc9b_xywkolJ2fGW3AN-JoD2A9Fw,1134
|
21
|
+
aisp/utils/distance.py,sha256=pY23YGZpu6qVCCkZfhaEpRazUULfVUy2piyzYuAryN0,6576
|
22
|
+
aisp/utils/metrics.py,sha256=zDAScDbHRnfu24alRcZ6fEIUaWNoCD-QCtOCFBWPPo8,1277
|
23
|
+
aisp/utils/sanitizers.py,sha256=u1GizdJ-RKfPWJLnuFiM09lpItZMhDR_EvK8YdVHwDk,1858
|
24
|
+
aisp/utils/types.py,sha256=KELzr1kSBT7hHdsABoIS1xmEBGj6gRSH5A5YNG36I_c,1324
|
25
|
+
aisp/utils/validation.py,sha256=RqcS2VdFXkNcOH_7Y3yPi7FBoGWR_ReLBPDBx0UMCqI,1431
|
26
|
+
aisp-0.3.0.dist-info/licenses/LICENSE,sha256=fTqV5eBpeAZO0_jit8j4Ref9ikBSlHJ8xwj5TLg7gFk,7817
|
27
|
+
aisp-0.3.0.dist-info/METADATA,sha256=hYtREi4OT36M5B0LgIKnnrzdQ1SZKwzYNdpIT-O7Hwg,5173
|
28
|
+
aisp-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
29
|
+
aisp-0.3.0.dist-info/top_level.txt,sha256=Q5aJi_rAVT5UNS1As0ZafoyS5dwNibnoyOYV7RWUB9s,5
|
30
|
+
aisp-0.3.0.dist-info/RECORD,,
|