aisp 0.1.21__py3-none-any.whl → 0.1.31__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/NSA/__init__.py +4 -4
- aisp/{_base.py → NSA/_base.py} +93 -61
- aisp/NSA/{_negativeSelection.py → _negative_selection.py} +395 -280
- {aisp-0.1.21.dist-info → aisp-0.1.31.dist-info}/METADATA +4 -4
- aisp-0.1.31.dist-info/RECORD +8 -0
- {aisp-0.1.21.dist-info → aisp-0.1.31.dist-info}/WHEEL +1 -1
- aisp-0.1.21.dist-info/RECORD +0 -8
- {aisp-0.1.21.dist-info → aisp-0.1.31.dist-info}/LICENSE +0 -0
- {aisp-0.1.21.dist-info → aisp-0.1.31.dist-info}/top_level.txt +0 -0
@@ -1,52 +1,57 @@
|
|
1
1
|
import numpy as np
|
2
2
|
import numpy.typing as npt
|
3
3
|
from tqdm import tqdm
|
4
|
-
from typing import Dict, Literal, Union
|
4
|
+
from typing import Dict, Literal, Optional, Union
|
5
5
|
from collections import namedtuple
|
6
6
|
from scipy.spatial.distance import hamming
|
7
7
|
|
8
|
-
from
|
8
|
+
from ._base import Base
|
9
9
|
|
10
10
|
|
11
11
|
class RNSA(Base):
|
12
12
|
"""
|
13
|
-
The ``RNSA`` (Real-Valued Negative Selection Algorithm) class is for classification and
|
14
|
-
of anomalies through the self and not self method.
|
13
|
+
The ``RNSA`` (Real-Valued Negative Selection Algorithm) class is for classification and \
|
14
|
+
identification purposes. of anomalies through the self and not self method.
|
15
15
|
|
16
16
|
Attributes:
|
17
17
|
---
|
18
18
|
* N (``int``): Number of detectors.
|
19
19
|
* r (``float``): Radius of the detector.
|
20
20
|
* r_s (``float``): rₛ Radius of the ``X`` own samples.
|
21
|
-
* k (``int``): K number of near neighbors to calculate the average
|
21
|
+
* k (``int``): K number of near neighbors to calculate the average
|
22
|
+
distance of the detectors.
|
22
23
|
* metric (``str``): Way to calculate the distance: ``'euclidean', 'minkowski', or 'manhattan'``.
|
23
|
-
* max_discards (``int``): This parameter indicates the maximum number of consecutive
|
24
|
-
aimed at preventing a possible infinite loop in case a radius is
|
25
|
-
detectors.
|
24
|
+
* max_discards (``int``): This parameter indicates the maximum number of consecutive \
|
25
|
+
detector discards, aimed at preventing a possible infinite loop in case a radius is \
|
26
|
+
defined that cannot generate non-self detectors.
|
26
27
|
* seed (``int``): Seed for the random generation of detector values.
|
27
28
|
* algorithm(``str``), Set the algorithm version:
|
28
29
|
|
29
30
|
* ``'default-NSA'``: Default algorithm with fixed radius.
|
30
|
-
* ``'V-detector'``: This algorithm uses a variable radius for anomaly detection
|
31
|
+
* ``'V-detector'``: This algorithm uses a variable radius for anomaly detection \
|
32
|
+
in feature spaces.
|
31
33
|
|
32
34
|
Defaults to ``'default-NSA'``.
|
33
35
|
|
34
|
-
* non_self_label (``str``): This variable stores the label that will be
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
* non_self_label (``str``): This variable stores the label that will be when the data has \
|
37
|
+
only one output class, and the sample is classified as not belonging to that class. \
|
38
|
+
Defaults to ``'non-self'``.
|
39
|
+
* cell_bounds (``bool``): If set to ``True``, this option limits the generation of \
|
40
|
+
detectors to the space within the plane between 0 and 1. This means that any detector \
|
41
|
+
whose radius exceeds this limit is discarded, this variable is only used in the \
|
42
|
+
``V-detector`` algorithm. Defaults to ``False``.
|
43
|
+
* p (``float``): This parameter stores the value of ``p`` used in the Minkowski distance. \
|
44
|
+
The default is ``2``, which represents normalized Euclidean distance. Different values \
|
45
|
+
of p lead to different variants of the Minkowski distance \
|
46
|
+
[learn more](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.minkowski.html).
|
47
|
+
|
43
48
|
* detectors (``dict``): This variable stores a list of detectors by class.
|
44
49
|
* classes (``npt.NDArray``): list of output classes.
|
45
|
-
|
50
|
+
|
46
51
|
---
|
47
52
|
|
48
|
-
A classe ``RNSA`` (Algoritmo de Seleção Negativa de Valor Real) tem a finalidade de classificação
|
49
|
-
de anomalias através do método self e not self .
|
53
|
+
A classe ``RNSA`` (Algoritmo de Seleção Negativa de Valor Real) tem a finalidade de classificação \
|
54
|
+
e identificação de anomalias através do método self e not self .
|
50
55
|
|
51
56
|
Attributes:
|
52
57
|
---
|
@@ -55,134 +60,154 @@ class RNSA(Base):
|
|
55
60
|
* r_s (``float``): O valor de ``rₛ`` é o raio das amostras próprias da matriz ``X``.
|
56
61
|
* k (``int``): K quantidade de vizinhos próximos para calcular a média da distância dos detectores.
|
57
62
|
* metric (``str``): Forma de calcular a distância: ``'euclidiana', 'minkowski', or 'manhattan'``.
|
58
|
-
* max_discards (``int``): Este parâmetro indica o número máximo de descartes de detectores
|
59
|
-
que tem como objetivo evitar um possível loop infinito caso seja definido
|
60
|
-
gerar detectores do não-próprio.
|
63
|
+
* max_discards (``int``): Este parâmetro indica o número máximo de descartes de detectores \
|
64
|
+
em sequência, que tem como objetivo evitar um possível loop infinito caso seja definido \
|
65
|
+
um raio que não seja possível gerar detectores do não-próprio.
|
61
66
|
* seed (``int``): Semente para a geração randômica dos valores dos detectores.
|
62
67
|
* algorithm (``str``), Definir a versão do algoritmo:
|
63
68
|
|
64
69
|
* ``'default-NSA'``: Algoritmo padrão com raio fixo.
|
65
|
-
* ``'V-detector'``: Este algoritmo utiliza um raio variável para a detecção de
|
66
|
-
de características.
|
70
|
+
* ``'V-detector'``: Este algoritmo utiliza um raio variável para a detecção de \
|
71
|
+
anomalias em espaços de características.
|
67
72
|
|
68
73
|
Defaults to ``'default-NSA'``.
|
69
74
|
|
70
|
-
* non_self_label (``str``): Esta variável armazena o rótulo que será atribuído quando
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
* non_self_label (``str``): Esta variável armazena o rótulo que será atribuído quando \
|
76
|
+
os dados possuírem apenas uma classe de saída, e a amostra for classificada como não \
|
77
|
+
pertencente a essa classe. Defaults to ``'non-self'``.
|
78
|
+
* cell_bounds (``bool``): Se definido como ``True``, esta opção limita a geração dos \
|
79
|
+
detectores ao espaço do plano compreendido entre 0 e 1. Isso significa que qualquer \
|
80
|
+
detector cujo raio ultrapasse esse limite é descartado, e esta variável é usada \
|
81
|
+
exclusivamente no algoritmo ``V-detector``.
|
82
|
+
* p (``float``): Este parâmetro armazena o valor de ``p`` utilizada na distância de \
|
83
|
+
Minkowski. O padrão é ``2``, o que significa distância euclidiana normalizada. \
|
84
|
+
Diferentes valores de p levam a diferentes variantes da distância de Minkowski \
|
85
|
+
[saiba mais](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.minkowski.html).
|
86
|
+
|
79
87
|
* detectors (``dict``): Essa variável armazena uma lista com detectores por classes.
|
80
88
|
* classes (``npt.NDArray``): lista com as classes de saída.
|
81
89
|
"""
|
82
|
-
|
83
|
-
def __init__(
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
r_s: float = 0.0001,
|
88
|
-
k: int = 1,
|
89
|
-
metric: Literal['manhattan', 'minkowski', 'euclidean'] = 'euclidean',
|
90
|
-
max_discards: int = 1000,
|
91
|
-
seed: int = None,
|
92
|
-
algorithm: Literal['default-NSA', 'V-detector'] ='default-NSA',
|
93
|
-
**kwargs: Dict[str, Union[bool, str, float]]
|
94
|
-
):
|
90
|
+
|
91
|
+
def __init__(self, N: int = 100, r: float = 0.05, r_s: float = 0.0001, k: int = 1,
|
92
|
+
metric: Literal["manhattan", "minkowski", "euclidean"] = "euclidean", max_discards: int = 1000,
|
93
|
+
seed: int = None, algorithm: Literal["default-NSA", "V-detector"] = "default-NSA",
|
94
|
+
**kwargs: Dict[str, Union[bool, str, float]]):
|
95
95
|
"""
|
96
96
|
Negative Selection class constructor (``RNSA``).
|
97
97
|
|
98
98
|
Details:
|
99
99
|
---
|
100
|
-
This method initializes the ``detectors``, ``classes``, ``k``, ``metric``, ``N``, ``r``,
|
101
|
-
``max_discards``, ``seed`` and ``algorithm`` attributes.
|
100
|
+
This method initializes the ``detectors``, ``classes``, ``k``, ``metric``, ``N``, ``r``, \
|
101
|
+
``r_S``, ``max_discards``, ``seed`` and ``algorithm`` attributes.
|
102
102
|
|
103
103
|
Parameters:
|
104
104
|
---
|
105
105
|
* N (``int``): Number of detectors. Defaults to ``100``.
|
106
106
|
* r (``float``): Radius of the detector. Defaults to ``0.05``.
|
107
107
|
* r_s (``float``): rₛ Radius of the ``X`` own samples. Defaults to ``0.0001``.
|
108
|
-
* k (``int``): Number of neighbors near the randomly generated detectors to perform the
|
109
|
-
|
108
|
+
* k (``int``): Number of neighbors near the randomly generated detectors to perform the \
|
109
|
+
distance average calculation. Defaults to ``1``.
|
110
110
|
* metric (``str``): Way to calculate the distance between the detector and the sample:
|
111
111
|
|
112
|
-
* ``'Euclidean'`` ➜ The calculation of the distance is given by the expression:
|
113
|
-
|
114
|
-
* ``'
|
112
|
+
* ``'Euclidean'`` ➜ The calculation of the distance is given by the expression: \
|
113
|
+
√( (x₁ – x₂)² + (y₁ – y₂)² + ... + (yn – yn)²).
|
114
|
+
* ``'minkowski'`` ➜ The calculation of the distance is given by the expression: \
|
115
|
+
( |X₁ – Y₁|p + |X₂ – Y₂|p + ... + |Xn – Yn|p) ¹/ₚ.
|
116
|
+
* ``'manhattan'`` ➜ The calculation of the distance is given by the expression: \
|
117
|
+
( |x₁ – x₂| + |y₁ – y₂| + ... + |yn – yn|) .
|
115
118
|
|
116
119
|
Defaults to ``'euclidean'``.
|
117
120
|
|
118
|
-
* max_discards (``int``): This parameter indicates the maximum number of consecutive
|
119
|
-
|
120
|
-
|
121
|
+
* max_discards (``int``): This parameter indicates the maximum number of consecutive \
|
122
|
+
detector discards, aimed at preventing a possible infinite loop in case a radius is \
|
123
|
+
defined that cannot generate non-self detectors. Defaults to ``1000``.
|
124
|
+
* seed (``int``): Seed for the random generation of values in the detectors. Defaults \
|
125
|
+
to ``None``.
|
121
126
|
|
122
127
|
* algorithm(``str``), Set the algorithm version:
|
123
128
|
|
124
129
|
* ``'default-NSA'``: Default algorithm with fixed radius.
|
125
|
-
* ``'V-detector'``: This algorithm is based on the article
|
130
|
+
* ``'V-detector'``: This algorithm is based on the article \
|
131
|
+
"[Real-Valued Negative Selection Algorithm with Variable-Sized Detectors](https://doi.org/10.1007/978-3-540-24854-5_30)", \
|
132
|
+
by Ji, Z., Dasgupta, D. (2004), and uses a variable radius for anomaly \
|
133
|
+
detection in feature spaces.
|
126
134
|
|
127
135
|
Defaults to ``'default-NSA'``.
|
128
136
|
|
129
137
|
- ``**kwargs``:
|
130
|
-
- non_self_label (``str``): This variable stores the label that will be assigned
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
+
- non_self_label (``str``): This variable stores the label that will be assigned \
|
139
|
+
when the data has only one output class, and the sample is classified as not \
|
140
|
+
belonging to that class. Defaults to ``'non-self'``.
|
141
|
+
- cell_bounds (``bool``): If set to ``True``, this option limits the generation \
|
142
|
+
of detectors to the space within the plane between 0 and 1. This means that \
|
143
|
+
any detector whose radius exceeds this limit is discarded, this variable is \
|
144
|
+
only used in the ``V-detector`` algorithm. Defaults to ``False``.
|
145
|
+
- p (``float``): This parameter stores the value of ``p`` used in the Minkowski \
|
146
|
+
distance. The default is ``2``, which represents normalized Euclidean distance. \
|
147
|
+
Different values of p lead to different variants of the Minkowski distance \
|
148
|
+
[learn more](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.minkowski.html).
|
138
149
|
---
|
139
150
|
|
140
151
|
Construtor da classe de Seleção negativa (``RNSA``).
|
141
152
|
|
142
153
|
Details:
|
143
154
|
---
|
144
|
-
Este método inicializa os atributos ``detectors``, ``classes``, ``k``, ``metric``, ``N``,
|
155
|
+
Este método inicializa os atributos ``detectors``, ``classes``, ``k``, ``metric``, ``N``, \
|
156
|
+
``r`` e ``seed``.
|
145
157
|
|
146
158
|
Parameters:
|
147
159
|
---
|
148
160
|
* N (``int``): Quantidade de detectores. Defaults to ``100``.
|
149
161
|
* r (``float``): Raio do detector. Defaults to ``0.05``.
|
150
|
-
* r_s (``float``): O valor de ``rₛ`` é o raio das amostras próprias da matriz ``X``.
|
151
|
-
|
152
|
-
|
162
|
+
* r_s (``float``): O valor de ``rₛ`` é o raio das amostras próprias da matriz ``X``. \
|
163
|
+
Defaults to ``0.0001``.
|
164
|
+
* k (``int``): Quantidade de vizinhos próximos dos detectores gerados aleatoriamente \
|
165
|
+
para efetuar o cálculo da média da distância. Defaults to ``1``.
|
153
166
|
* metric (``str``): Forma para se calcular a distância entre o detector e a amostra:
|
154
167
|
|
155
|
-
* ``'euclidiana'`` ➜ O cálculo da distância dá-se pela expressão:
|
156
|
-
|
157
|
-
* ``'
|
168
|
+
* ``'euclidiana'`` ➜ O cálculo da distância dá-se pela expressão: \
|
169
|
+
√( (x₁ – x₂)² + (y₁ – y₂)² + ... + (yn – yn)²).
|
170
|
+
* ``'minkowski'`` ➜ O cálculo da distância dá-se pela expressão: \
|
171
|
+
( |X₁ – Y₁|p + |X₂ – Y₂|p + ... + |Xn – Yn|p) ¹/ₚ.
|
172
|
+
* ``'manhattan'`` ➜ O cálculo da distância dá-se pela expressão: \
|
173
|
+
( |x₁ – x₂| + |y₁ – y₂| + ... + |yn – yn|).
|
158
174
|
|
159
175
|
Defaults to ``'euclidean'``.
|
160
176
|
|
161
|
-
* max_discards (``int``): Este parâmetro indica o número máximo de descartes de detectores
|
162
|
-
|
163
|
-
|
177
|
+
* max_discards (``int``): Este parâmetro indica o número máximo de descartes de detectores \
|
178
|
+
em sequência, que tem como objetivo evitar um possível loop infinito caso seja definido \
|
179
|
+
um raio que não seja possível gerar detectores do não-próprio. Defaults to ``1000``.
|
180
|
+
* seed (``int``): Semente para a geração randômica dos valores nos detectores. \
|
181
|
+
Defaults to ``None``.
|
164
182
|
* algorithm (``str``), Definir a versão do algoritmo:
|
165
183
|
|
166
184
|
* ``'default-NSA'``: Algoritmo padrão com raio fixo.
|
167
|
-
* ``'V-detector'``: Este algoritmo é baseado no artigo
|
185
|
+
* ``'V-detector'``: Este algoritmo é baseado no artigo \
|
186
|
+
"[Real-Valued Negative Selection Algorithm with Variable-Sized Detectors](https://doi.org/10.1007/978-3-540-24854-5_30)", \
|
187
|
+
de autoria de Ji, Z., Dasgupta, D. (2004), e utiliza um raio variável para a \
|
188
|
+
detecção de anomalias em espaços de características.
|
168
189
|
|
169
190
|
Defaults to ``'default-NSA'``.
|
170
191
|
|
171
192
|
- ``**kwargs``:
|
172
|
-
- non_self_label (``str``): Esta variável armazena o rótulo que será atribuído
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
193
|
+
- non_self_label (``str``): Esta variável armazena o rótulo que será atribuído \
|
194
|
+
quando os dados possuírem apenas uma classe de saída, e a amostra for \
|
195
|
+
classificada como não pertencente a essa classe. Defaults to ``'non-self'``.
|
196
|
+
- cell_bounds (``bool``): Se definido como ``True``, esta opção limita a \
|
197
|
+
geração dos detectores ao espaço do plano compreendido entre 0 e 1. Isso \
|
198
|
+
significa que qualquer detector cujo raio ultrapasse esse limite é descartado, \
|
199
|
+
e esta variável é usada exclusivamente no algoritmo ``V-detector``.
|
200
|
+
- p (``float``): Este parâmetro armazena o valor de ``p`` utilizada na distância \
|
201
|
+
de Minkowski. O padrão é ``2``, o que significa distância euclidiana normalizada. \
|
202
|
+
Diferentes valores de p levam a diferentes variantes da distância de Minkowski \
|
203
|
+
[saiba mais](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.minkowski.html).
|
180
204
|
"""
|
181
|
-
|
182
|
-
|
205
|
+
|
206
|
+
super().__init__(metric)
|
207
|
+
if metric == "manhattan" or metric == "minkowski":
|
183
208
|
self.metric = metric
|
184
209
|
else:
|
185
|
-
self.metric =
|
210
|
+
self.metric = "euclidean"
|
186
211
|
|
187
212
|
if seed is not None and isinstance(seed, int):
|
188
213
|
np.random.seed(seed)
|
@@ -204,18 +229,18 @@ class RNSA(Base):
|
|
204
229
|
self.r: float = 0.05
|
205
230
|
else:
|
206
231
|
self.r: float = r
|
207
|
-
|
232
|
+
|
208
233
|
if r_s > 0:
|
209
234
|
self.r_s: float = r_s
|
210
235
|
else:
|
211
236
|
self.r_s: float = 0
|
212
237
|
|
213
|
-
if algorithm ==
|
238
|
+
if algorithm == "V-detector":
|
214
239
|
self._Detector = namedtuple("Detector", "position radius")
|
215
240
|
self._algorithm: str = algorithm
|
216
241
|
else:
|
217
242
|
self._Detector = namedtuple("Detector", "position")
|
218
|
-
self._algorithm: str =
|
243
|
+
self._algorithm: str = "default-NSA"
|
219
244
|
|
220
245
|
if max_discards > 0:
|
221
246
|
self.max_discards: int = max_discards
|
@@ -223,10 +248,11 @@ class RNSA(Base):
|
|
223
248
|
self.max_discards: int = 1000
|
224
249
|
|
225
250
|
# Obtém as variáveis do kwargs.
|
226
|
-
self.p: float = kwargs.get(
|
227
|
-
self._cell_bounds: bool = kwargs.get(
|
228
|
-
self.non_self_label: str = kwargs.get(
|
229
|
-
|
251
|
+
self.p: float = kwargs.get("p", 2)
|
252
|
+
self._cell_bounds: bool = kwargs.get("cell_bounds", False)
|
253
|
+
self.non_self_label: str = kwargs.get("non_self_label", "non-self")
|
254
|
+
|
255
|
+
# Inicializa as demais variáveis da classe como None
|
230
256
|
self.detectors: Union[dict, None] = None
|
231
257
|
self.classes: npt.NDArray = None
|
232
258
|
|
@@ -237,8 +263,8 @@ class RNSA(Base):
|
|
237
263
|
|
238
264
|
Parameters:
|
239
265
|
---
|
240
|
-
* X (``npt.NDArray``): Training array, containing the samples and their characteristics,
|
241
|
-
|
266
|
+
* X (``npt.NDArray``): Training array, containing the samples and their characteristics, \
|
267
|
+
[``N samples`` (rows)][``N features`` (columns)].
|
242
268
|
* y (``npt.NDArray``): Array of target classes of ``X`` with [``N samples`` (lines)].
|
243
269
|
* verbose (``bool``): Feedback from detector generation to the user.
|
244
270
|
returns:
|
@@ -247,13 +273,13 @@ class RNSA(Base):
|
|
247
273
|
|
248
274
|
----
|
249
275
|
|
250
|
-
A função ``fit(...)``, realiza o treinamento de acordo com ``X`` e ``y``, usando o método
|
276
|
+
A função ``fit(...)``, realiza o treinamento de acordo com ``X`` e ``y``, usando o método
|
251
277
|
de seleção negativa(``NegativeSelect``).
|
252
278
|
|
253
279
|
Parameters:
|
254
280
|
---
|
255
|
-
* X (``npt.NDArray``): Array de treinamento, contendo as amostras é suas características,
|
256
|
-
|
281
|
+
* X (``npt.NDArray``): Array de treinamento, contendo as amostras é suas características, \
|
282
|
+
[``N amostras`` (linhas)][``N características`` (colunas)].
|
257
283
|
* y (``npt.NDArray``): Array com as classes alvos de ``X`` com [``N amostras`` (linhas)].
|
258
284
|
* verbose (``bool``): Feedback da geração de detectores para o usuário.
|
259
285
|
Returns:
|
@@ -261,7 +287,7 @@ class RNSA(Base):
|
|
261
287
|
(``self``): Retorna a própria instância.
|
262
288
|
"""
|
263
289
|
super()._check_and_raise_exceptions_fit(X, y)
|
264
|
-
|
290
|
+
|
265
291
|
# Identificando as classes possíveis, dentro do array de saídas ``y``.
|
266
292
|
self.classes = np.unique(y)
|
267
293
|
# Dict que armazenará os detectores com as classes como key.
|
@@ -271,7 +297,7 @@ class RNSA(Base):
|
|
271
297
|
# Barra de progresso para a geração de todos os detectores.
|
272
298
|
if verbose:
|
273
299
|
progress = tqdm(total=int(self.N * (len(self.classes))),
|
274
|
-
bar_format=
|
300
|
+
bar_format="{desc} ┇{bar}┇ {n}/{total} detectors", postfix="\n",)
|
275
301
|
for _class_ in self.classes:
|
276
302
|
# Inicia o conjunto vazio que conterá os detectores válidos.
|
277
303
|
valid_detectors_set = []
|
@@ -279,19 +305,22 @@ class RNSA(Base):
|
|
279
305
|
# Informando em qual classe o algoritmo está para a barra de progresso.
|
280
306
|
if verbose:
|
281
307
|
progress.set_description_str(
|
282
|
-
f
|
308
|
+
f"Generating the detectors for the {_class_} class:"
|
309
|
+
)
|
283
310
|
while len(valid_detectors_set) < self.N:
|
284
311
|
# Gera um vetor candidato a detector aleatoriamente com valores entre 0 e 1.
|
285
312
|
vector_x = np.random.random_sample(size=X.shape[1])
|
286
313
|
# Verifica a validade do detector para o não-próprio com relação às amostras da classe.
|
287
314
|
valid_detector = self.__checks_valid_detector(
|
288
|
-
X=X, vector_x=vector_x, samples_index_class=sample_index[_class_]
|
289
|
-
|
315
|
+
X=X, vector_x=vector_x, samples_index_class=sample_index[_class_]
|
316
|
+
)
|
317
|
+
|
290
318
|
# Se o detector for válido, adicione a lista dos válidos.
|
291
|
-
if self._algorithm ==
|
319
|
+
if self._algorithm == "V-detector" and valid_detector is not False:
|
292
320
|
discard_count = 0
|
293
321
|
valid_detectors_set.append(
|
294
|
-
self._Detector(vector_x, valid_detector[1])
|
322
|
+
self._Detector(vector_x, valid_detector[1])
|
323
|
+
)
|
295
324
|
if verbose:
|
296
325
|
progress.update(1)
|
297
326
|
elif valid_detector:
|
@@ -302,21 +331,26 @@ class RNSA(Base):
|
|
302
331
|
else:
|
303
332
|
discard_count += 1
|
304
333
|
if discard_count == self.max_discards:
|
305
|
-
raise Exception(
|
306
|
-
|
307
|
-
|
308
|
-
|
334
|
+
raise Exception(
|
335
|
+
"An error has been identified:\n"
|
336
|
+
f"the maximum number of discards of detectors for the {_class_} class "
|
337
|
+
"has been reached.\nIt is recommended to check the defined radius and "
|
338
|
+
"consider reducing its value."
|
339
|
+
)
|
340
|
+
|
309
341
|
# Adicionar detectores, com as classes como chave na dict.
|
310
342
|
list_detectors_by_class[_class_] = valid_detectors_set
|
311
343
|
# Informar a finalização da geração dos detectores para as classes.
|
312
344
|
if verbose:
|
313
345
|
progress.set_description(
|
314
|
-
f'\033[92m✔ Non-self detectors for classes ({", ".join(map(str, self.classes))})
|
346
|
+
f'\033[92m✔ Non-self detectors for classes ({", ".join(map(str, self.classes))}) '
|
347
|
+
f'successfully generated\033[0m'
|
348
|
+
)
|
315
349
|
# Armazena os detectores encontrados no atributo, para os detectores da classe.
|
316
350
|
self.detectors = list_detectors_by_class
|
317
351
|
return self
|
318
352
|
|
319
|
-
def predict(self, X: npt.NDArray) -> npt.NDArray:
|
353
|
+
def predict(self, X: npt.NDArray) -> Optional[npt.NDArray]:
|
320
354
|
"""
|
321
355
|
Function to perform the prediction of classes based on detectors
|
322
356
|
created after training.
|
@@ -334,31 +368,34 @@ class RNSA(Base):
|
|
334
368
|
|
335
369
|
---
|
336
370
|
|
337
|
-
Função para efetuar a previsão das classes com base nos detectores
|
371
|
+
Função para efetuar a previsão das classes com base nos detectores
|
338
372
|
criados após o treinamento.
|
339
373
|
|
340
374
|
Parameters:
|
341
375
|
---
|
342
|
-
* X (``npt.NDArray``): Array com as amostras de entradas com [``N amostras`` (Linhas)] e
|
376
|
+
* X (``npt.NDArray``): Array com as amostras de entradas com [``N amostras`` (Linhas)] e
|
343
377
|
[``N características``(Colunas)]
|
344
378
|
|
345
379
|
Returns:
|
346
380
|
---
|
347
|
-
* C – (``npt.NDArray``): um ndarray de forma ``C`` [``N amostras``],
|
381
|
+
* C – (``npt.NDArray``): um ndarray de forma ``C`` [``N amostras``],
|
348
382
|
contendo as classes previstas para ``X``.
|
349
383
|
* ``None``: Se não existir detectores para a previsão.
|
350
384
|
"""
|
351
385
|
# se não houver detectores retorna None.
|
352
386
|
if self.detectors is None:
|
353
387
|
return None
|
354
|
-
elif not isinstance(X,
|
388
|
+
elif not isinstance(X, (np.ndarray, list)):
|
355
389
|
raise TypeError("X is not an ndarray or list")
|
356
390
|
elif len(self.detectors[self.classes[0]][0].position) != len(X[0]):
|
357
|
-
raise Exception(
|
358
|
-
|
391
|
+
raise Exception(
|
392
|
+
"X does not have {} features to make the prediction".format(
|
393
|
+
len(self.detectors[self.classes[0]][0])
|
394
|
+
)
|
395
|
+
)
|
359
396
|
|
360
397
|
# Inicia um array vazio.
|
361
|
-
C = np.empty(shape=
|
398
|
+
C = np.empty(shape=0)
|
362
399
|
# Para cada linha de amostra em X.
|
363
400
|
for line in X:
|
364
401
|
class_found: bool
|
@@ -372,26 +409,32 @@ class RNSA(Base):
|
|
372
409
|
# Se possuir apenas uma classe e não classificar a amostra define a saída como não-própria.
|
373
410
|
if not class_found and len(self.classes) == 1:
|
374
411
|
C = np.append(C, [self.non_self_label])
|
375
|
-
# Se não identificar a classe com os detectores, coloca a classe com a maior distância
|
412
|
+
# Se não identificar a classe com os detectores, coloca a classe com a maior distância
|
413
|
+
# da média dos seus detectores.
|
376
414
|
elif not class_found:
|
377
|
-
average_distance =
|
415
|
+
average_distance: dict = {}
|
378
416
|
for _class_ in self.classes:
|
379
417
|
detectores = list(
|
380
|
-
map(lambda x: x.position, self.detectors[_class_])
|
381
|
-
|
382
|
-
|
418
|
+
map(lambda x: x.position, self.detectors[_class_])
|
419
|
+
)
|
420
|
+
average_distance[_class_] = np.average(
|
421
|
+
[self.__distance(detector, line)
|
422
|
+
for detector in detectores]
|
423
|
+
)
|
383
424
|
C = np.append(
|
384
425
|
C, [max(average_distance, key=average_distance.get)])
|
385
426
|
return C
|
386
427
|
|
387
|
-
def __checks_valid_detector(self, X: npt.NDArray = None, vector_x: npt.NDArray = None,
|
428
|
+
def __checks_valid_detector(self, X: npt.NDArray = None, vector_x: npt.NDArray = None,
|
429
|
+
samples_index_class: npt.NDArray = None):
|
388
430
|
"""
|
389
431
|
Function to check if the detector has a valid non-proper ``r`` radius for the class.
|
390
432
|
|
391
433
|
Parameters:
|
392
434
|
---
|
393
435
|
* X (``npt.NDArray``): Array ``X`` with the samples.
|
394
|
-
* vector_x (``npt.NDArray``): Randomly generated vector x candidate detector with values
|
436
|
+
* vector_x (``npt.NDArray``): Randomly generated vector x candidate detector with values \
|
437
|
+
between [0, 1].
|
395
438
|
* samples_index_class (``npt.NDArray``): Sample positions of a class in ``X``.
|
396
439
|
|
397
440
|
returns:
|
@@ -405,7 +448,8 @@ class RNSA(Base):
|
|
405
448
|
Parameters:
|
406
449
|
---
|
407
450
|
* X (``npt.NDArray``): Array ``X`` com as amostras.
|
408
|
-
* vector_x (``npt.NDArray``): Vetor x candidato a detector gerado aleatoriamente com valores
|
451
|
+
* vector_x (``npt.NDArray``): Vetor x candidato a detector gerado aleatoriamente com valores \
|
452
|
+
entre [0, 1].
|
409
453
|
* samples_index_class (``npt.NDArray``): Posições das amostras de uma classe em ``X``.
|
410
454
|
|
411
455
|
Returns:
|
@@ -414,37 +458,41 @@ class RNSA(Base):
|
|
414
458
|
|
415
459
|
"""
|
416
460
|
# Se um ou mais array de entrada possuir zero dados, retorna falso.
|
417
|
-
if np.size(samples_index_class) == 0 or np.size(X) == 0 or np.size(vector_x) == 0:
|
461
|
+
if (np.size(samples_index_class) == 0 or np.size(X) == 0 or np.size(vector_x) == 0):
|
418
462
|
return False
|
419
|
-
# se self.k > 1 utiliza os k vizinhos mais próximos (knn), se não verifica o detector sem
|
463
|
+
# se self.k > 1 utiliza os k vizinhos mais próximos (knn), se não verifica o detector sem
|
464
|
+
# considerar os knn.
|
420
465
|
if self.k > 1:
|
421
466
|
# Iniciar a lista dos knn vazia.
|
422
|
-
knn_list = np.empty(shape=
|
467
|
+
knn_list = np.empty(shape=0)
|
423
468
|
for i in samples_index_class:
|
424
|
-
# Calcula a distância entre os dois vetores e adiciona a lista dos knn, se a
|
469
|
+
# Calcula a distância entre os dois vetores e adiciona a lista dos knn, se a
|
470
|
+
# distância for menor que a maior da lista.
|
425
471
|
knn_list = self.__compare_KnearestNeighbors_List(
|
426
|
-
knn_list, self.__distance(X[i], vector_x)
|
472
|
+
knn_list, self.__distance(X[i], vector_x)
|
473
|
+
)
|
427
474
|
# Se a média das distâncias na lista dos knn, for menor que o raio, retorna verdadeiro.
|
428
475
|
distance_mean = np.mean(knn_list)
|
429
|
-
if self._algorithm ==
|
476
|
+
if self._algorithm == "V-detector":
|
430
477
|
return self.__detector_is_valid_to_Vdetector(distance_mean, vector_x)
|
431
478
|
elif distance_mean > (self.r + self.r_s):
|
432
479
|
return True # Detector é valido!
|
433
480
|
else:
|
434
481
|
distance: Union[float, None] = None
|
435
482
|
for i in samples_index_class:
|
436
|
-
if self._algorithm ==
|
483
|
+
if self._algorithm == "V-detector":
|
437
484
|
new_distance = self.__distance(X[i], vector_x)
|
438
485
|
if distance is None:
|
439
486
|
distance = new_distance
|
440
487
|
elif distance > new_distance:
|
441
488
|
distance = new_distance
|
442
489
|
else:
|
443
|
-
# Calcula a distância entre os vetores, se menor ou igual ao raio + raio da
|
490
|
+
# Calcula a distância entre os vetores, se menor ou igual ao raio + raio da
|
491
|
+
# amostra define a validade do detector como falso.
|
444
492
|
if (self.r + self.r_s) >= self.__distance(X[i], vector_x):
|
445
493
|
return False # Detector não é valido!
|
446
|
-
|
447
|
-
if self._algorithm ==
|
494
|
+
|
495
|
+
if self._algorithm == "V-detector":
|
448
496
|
return self.__detector_is_valid_to_Vdetector(distance, vector_x)
|
449
497
|
return True # Detector é valido!
|
450
498
|
|
@@ -467,26 +515,26 @@ class RNSA(Base):
|
|
467
515
|
|
468
516
|
---
|
469
517
|
|
470
|
-
Compara a distância do k-vizinho mais próximo na posição ``k-1``da lista ``knn``,
|
518
|
+
Compara a distância do k-vizinho mais próximo na posição ``k-1``da lista ``knn``,
|
471
519
|
se a distância da nova amostra for menor, substitui ela e ordena em ordem crescente.
|
472
520
|
|
473
521
|
|
474
522
|
Parameters:
|
475
523
|
---
|
476
524
|
knn (npt.NDArray): Lista de distâncias dos k-vizinhos mais próximos.
|
477
|
-
distance (float): Distância a ser verificada.
|
525
|
+
distance (float): Distância a ser verificada.
|
478
526
|
|
479
527
|
Returns:
|
480
528
|
---
|
481
529
|
npt.NDArray: Lista de vizinhos mais próximos atualizada e ordenada.
|
482
530
|
"""
|
483
531
|
# Se a quantidade de distâncias em knn, for menor que k, adiciona a distância.
|
484
|
-
if
|
532
|
+
if len(knn) < self.k:
|
485
533
|
knn = np.append(knn, distance)
|
486
534
|
knn.sort()
|
487
535
|
else:
|
488
536
|
# Se não, adicione a distância, se a nova distancia for menor que a maior distância da lista.
|
489
|
-
if
|
537
|
+
if knn[self.k - 1] > distance:
|
490
538
|
knn[self.k - 1] = distance
|
491
539
|
knn.sort()
|
492
540
|
|
@@ -498,7 +546,7 @@ class RNSA(Base):
|
|
498
546
|
|
499
547
|
Details:
|
500
548
|
---
|
501
|
-
In this function, when there is class ambiguity, it returns the class that has the greatest
|
549
|
+
In this function, when there is class ambiguity, it returns the class that has the greatest
|
502
550
|
average distance between the detectors.
|
503
551
|
|
504
552
|
Parameters:
|
@@ -507,7 +555,8 @@ class RNSA(Base):
|
|
507
555
|
|
508
556
|
returns:
|
509
557
|
---
|
510
|
-
* Returns the predicted class with the detectors or None if the sample does not qualify
|
558
|
+
* Returns the predicted class with the detectors or None if the sample does not qualify \
|
559
|
+
for any class.
|
511
560
|
|
512
561
|
---
|
513
562
|
|
@@ -515,8 +564,8 @@ class RNSA(Base):
|
|
515
564
|
|
516
565
|
Details:
|
517
566
|
---
|
518
|
-
Nesta função, quando possui ambiguidade de classes, retorna a classe que possuir a média de
|
519
|
-
maior entre os detectores.
|
567
|
+
Nesta função, quando possui ambiguidade de classes, retorna a classe que possuir a média de \
|
568
|
+
distância maior entre os detectores.
|
520
569
|
|
521
570
|
Parameters:
|
522
571
|
---
|
@@ -524,7 +573,8 @@ class RNSA(Base):
|
|
524
573
|
|
525
574
|
Returns:
|
526
575
|
---
|
527
|
-
* Retorna a classe prevista com os detectores ou None se a amostra não se qualificar
|
576
|
+
* Retorna a classe prevista com os detectores ou None se a amostra não se qualificar \
|
577
|
+
a nenhuma classe.
|
528
578
|
"""
|
529
579
|
|
530
580
|
# Lista para armazenar as classes e a distância média entre os detectores e a amostra.
|
@@ -538,7 +588,7 @@ class RNSA(Base):
|
|
538
588
|
distance = self.__distance(detector.position, line)
|
539
589
|
# Soma as distâncias para calcular a média.
|
540
590
|
sum_distance += distance
|
541
|
-
if self._algorithm ==
|
591
|
+
if self._algorithm == "V-detector":
|
542
592
|
if distance <= detector.radius:
|
543
593
|
class_found = False
|
544
594
|
break
|
@@ -546,9 +596,10 @@ class RNSA(Base):
|
|
546
596
|
class_found = False
|
547
597
|
break
|
548
598
|
|
549
|
-
# Se a amostra passar por todos os detectores de uma classe, adiciona a classe como
|
599
|
+
# Se a amostra passar por todos os detectores de uma classe, adiciona a classe como
|
600
|
+
# possível previsão.
|
550
601
|
if class_found:
|
551
|
-
possible_classes.append([_class_, sum_distance/self.N])
|
602
|
+
possible_classes.append([_class_, sum_distance / self.N])
|
552
603
|
# Se classificar como pertencentes a apenas uma classe, retorna a classe.
|
553
604
|
if len(possible_classes) == 1:
|
554
605
|
return possible_classes[0][0]
|
@@ -588,33 +639,37 @@ class RNSA(Base):
|
|
588
639
|
|
589
640
|
def __detector_is_valid_to_Vdetector(self, distance: float, vector_x: npt.NDArray):
|
590
641
|
"""
|
591
|
-
Check if the distance between the detector and the samples, minus the radius of the samples,
|
642
|
+
Check if the distance between the detector and the samples, minus the radius of the samples,
|
592
643
|
is greater than the minimum radius.
|
593
644
|
|
594
645
|
Parameters:
|
595
646
|
---
|
596
647
|
distance (``float``): minimum distance calculated between all samples.
|
597
|
-
vector_x (``numpy.ndarray``): randomly generated candidate detector vector x with values
|
648
|
+
vector_x (``numpy.ndarray``): randomly generated candidate detector vector x with values \
|
649
|
+
between 0 and 1.
|
650
|
+
|
598
651
|
Returns:
|
599
652
|
---
|
600
|
-
* ``False``: if the calculated radius is smaller than the minimum distance or exceeds the
|
601
|
-
|
653
|
+
* ``False``: if the calculated radius is smaller than the minimum distance or exceeds the \
|
654
|
+
edge of the space, if this option is enabled.
|
602
655
|
* ``True`` and the distance minus the radius of the samples, if the radius is valid.`
|
603
656
|
|
604
657
|
----
|
605
658
|
|
606
|
-
Verifique se a distância entre o detector e as amostras, descontando o raio das amostras,
|
659
|
+
Verifique se a distância entre o detector e as amostras, descontando o raio das amostras, \
|
660
|
+
é maior do que o raio mínimo.
|
607
661
|
|
608
662
|
Parameters:
|
609
663
|
---
|
610
664
|
distance (``float``): distância mínima calculada entre todas as amostras.
|
611
|
-
vector_x (``numpy.ndarray``): vetor x candidato do detector gerado aleatoriamente, com
|
612
|
-
|
665
|
+
vector_x (``numpy.ndarray``): vetor x candidato do detector gerado aleatoriamente, com \
|
666
|
+
valores entre 0 e 1.
|
667
|
+
|
613
668
|
Returns:
|
614
669
|
---
|
615
670
|
|
616
|
-
* ``False``: caso o raio calculado seja menor do que a distância mínima ou ultrapasse a
|
617
|
-
|
671
|
+
* ``False``: caso o raio calculado seja menor do que a distância mínima ou ultrapasse a \
|
672
|
+
borda do espaço, caso essa opção esteja habilitada.
|
618
673
|
* ``True`` e a distância menos o raio das amostras, caso o raio seja válido.
|
619
674
|
"""
|
620
675
|
new_detector_r = float(distance - self.r_s)
|
@@ -630,12 +685,14 @@ class RNSA(Base):
|
|
630
685
|
|
631
686
|
def __slice_index_list_by_class(self, y: npt.NDArray) -> dict:
|
632
687
|
"""
|
633
|
-
The function ``__slice_index_list_by_class(...)``, separates the indices of the lines
|
634
|
-
to loop through the sample array, only in positions where
|
688
|
+
The function ``__slice_index_list_by_class(...)``, separates the indices of the lines \
|
689
|
+
according to the output class, to loop through the sample array, only in positions where \
|
690
|
+
the output is the class being trained.
|
635
691
|
|
636
692
|
Parameters:
|
637
693
|
---
|
638
|
-
* y (npt.NDArray): Receives a ``y``[``N sample``] array with the output classes of the
|
694
|
+
* y (npt.NDArray): Receives a ``y``[``N sample``] array with the output classes of the \
|
695
|
+
``X`` sample array.
|
639
696
|
|
640
697
|
returns:
|
641
698
|
---
|
@@ -643,35 +700,36 @@ class RNSA(Base):
|
|
643
700
|
|
644
701
|
---
|
645
702
|
|
646
|
-
A função ``__slice_index_list_by_class(...)``, separa os índices das linhas conforme a classe
|
647
|
-
para percorrer o array de amostra, apenas nas posições que a saída for a classe que
|
703
|
+
A função ``__slice_index_list_by_class(...)``, separa os índices das linhas conforme a classe \
|
704
|
+
de saída, para percorrer o array de amostra, apenas nas posições que a saída for a classe que \
|
705
|
+
está sendo treinada.
|
648
706
|
|
649
707
|
Parameters:
|
650
708
|
---
|
651
|
-
* y (npt.NDArray): Recebe um array ``y``[``N amostra``] com as classes de
|
709
|
+
* y (npt.NDArray): Recebe um array ``y``[``N amostra``] com as classes de saída do array \
|
710
|
+
de amostra ``X``.
|
652
711
|
|
653
712
|
Returns:
|
654
713
|
---
|
655
714
|
* dict: Um dicionário com a lista de posições do array(``y``), com as classes como chave.
|
656
715
|
"""
|
657
716
|
return super()._slice_index_list_by_class(y)
|
658
|
-
|
717
|
+
|
659
718
|
def score(self, X: npt.NDArray, y: list) -> float:
|
660
719
|
"""
|
661
720
|
Score function calculates forecast accuracy.
|
662
721
|
|
663
722
|
Details:
|
664
723
|
---
|
665
|
-
This function performs the prediction of X and checks how many elements are equal between
|
666
|
-
This function was added for compatibility with some scikit-learn
|
724
|
+
This function performs the prediction of X and checks how many elements are equal between \
|
725
|
+
vector y and y_predicted. This function was added for compatibility with some scikit-learn \
|
726
|
+
functions.
|
667
727
|
|
668
728
|
Parameters:
|
669
729
|
-----------
|
670
730
|
|
671
|
-
X
|
672
|
-
|
673
|
-
y: np.ndarray
|
674
|
-
True values with shape (n_samples,).
|
731
|
+
* X (np.ndarray): Feature set with shape (n_samples, n_features).
|
732
|
+
* y (np.ndarray): True values with shape (n_samples,).
|
675
733
|
|
676
734
|
Returns:
|
677
735
|
-------
|
@@ -685,83 +743,88 @@ class RNSA(Base):
|
|
685
743
|
|
686
744
|
Details:
|
687
745
|
---
|
688
|
-
Esta função realiza a previsão de X e verifica quantos elementos são iguais entre o vetor
|
689
|
-
Essa função foi adicionada para oferecer compatibilidade com algumas
|
746
|
+
Esta função realiza a previsão de X e verifica quantos elementos são iguais entre o vetor \
|
747
|
+
y e y_previsto. Essa função foi adicionada para oferecer compatibilidade com algumas \
|
748
|
+
funções do scikit-learn.
|
690
749
|
|
691
750
|
Parameters:
|
692
751
|
---
|
693
752
|
|
694
|
-
* X :
|
695
|
-
|
696
|
-
* y : np.ndarray
|
697
|
-
Valores verdadeiros com shape (n_samples,).
|
753
|
+
* X (np.ndarray): Conjunto de características com shape (n_samples, n_features).
|
754
|
+
* y (np.ndarray): Valores verdadeiros com shape (n_samples,).
|
698
755
|
|
699
756
|
returns:
|
700
757
|
---
|
701
758
|
|
702
|
-
accuracy :
|
703
|
-
|
759
|
+
* accuracy (float): A acurácia do modelo.
|
760
|
+
|
704
761
|
"""
|
705
762
|
return super()._score(X, y)
|
706
763
|
|
707
764
|
def get_params(self, deep: bool = True) -> dict:
|
708
765
|
return {
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
766
|
+
"N": self.N,
|
767
|
+
"r": self.r,
|
768
|
+
"k": self.k,
|
769
|
+
"metric": self.metric,
|
770
|
+
"seed": self.seed,
|
771
|
+
"algorithm": self._algorithm,
|
772
|
+
"r_s": self.r_s,
|
773
|
+
"cell_bounds": self._cell_bounds,
|
774
|
+
"p": self.p,
|
717
775
|
}
|
718
776
|
|
777
|
+
|
719
778
|
class BNSA(Base):
|
720
779
|
"""
|
721
|
-
The ``BNSA`` (Binary Negative Selection Algorithm) class is for classification and identification
|
722
|
-
of anomalies through the self and not self method.
|
780
|
+
The ``BNSA`` (Binary Negative Selection Algorithm) class is for classification and identification \
|
781
|
+
purposes of anomalies through the self and not self method.
|
723
782
|
|
724
783
|
Attributes:
|
725
784
|
---
|
726
|
-
|
785
|
+
|
727
786
|
* N (``int``): Number of detectors.
|
728
|
-
* aff_thresh (``float``): The variable represents the percentage of similarity between the
|
729
|
-
|
730
|
-
|
787
|
+
* aff_thresh (``float``): The variable represents the percentage of similarity between the \
|
788
|
+
T cell and the own samples.
|
789
|
+
* max_discards (``int``): This parameter indicates the maximum number of detector discards \
|
790
|
+
in sequence, which aims to avoid a possible infinite loop if a radius is defined that \
|
791
|
+
it is not possible to generate non-self detectors.
|
731
792
|
* seed (``int``): Seed for the random generation of values in the detectors.
|
732
|
-
|
793
|
+
|
733
794
|
* detectors (``dict``): This variable stores a list of detectors by class.
|
734
795
|
* classes (``npt.NDArray``): list of output classes.
|
735
|
-
|
796
|
+
|
736
797
|
|
737
798
|
---
|
738
799
|
|
739
|
-
A classe ``BNSA`` (Algoritmo de Seleção Negativa Binária) tem a finalidade de classificação e
|
740
|
-
de anomalias através do método self e not self .
|
800
|
+
A classe ``BNSA`` (Algoritmo de Seleção Negativa Binária) tem a finalidade de classificação e \
|
801
|
+
identificação de anomalias através do método self e not self .
|
741
802
|
|
742
803
|
Attributes:
|
743
804
|
---
|
744
805
|
* N (``int``): Quantidade de detectores. Defaults to ``100``.
|
745
|
-
* aff_thresh (``float``): A variável representa a porcentagem de similaridade entre a célula
|
746
|
-
|
747
|
-
|
748
|
-
|
806
|
+
* aff_thresh (``float``): A variável representa a porcentagem de similaridade entre a célula \
|
807
|
+
T e as amostras próprias. O valor padrão é de 10% (0,1), enquanto que o valor de 1,0 \
|
808
|
+
representa 100% de similaridade.
|
809
|
+
* max_discards (``int``): Este parâmetro indica o número máximo de descartes de detectores \
|
810
|
+
em sequência, que tem como objetivo evitar um possível loop infinito caso seja definido \
|
811
|
+
um raio que não seja possível gerar detectores do não-próprio. Defaults to ``100``.
|
749
812
|
* seed (``int``): Semente para a geração randômica dos valores nos detectores. Defaults to ``None``.
|
813
|
+
* no_label_sample_selection (``str``): Method for selecting labels for samples designated as \
|
814
|
+
non-members by all non-member detectors. Defaults to ``max_average_difference``.
|
815
|
+
|
750
816
|
|
751
817
|
* detectors (``dict``): Essa variável armazena uma lista com detectores por classes.
|
752
818
|
* classes (``npt.NDArray``): lista com as classes de saída.
|
753
819
|
|
754
820
|
"""
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
max_discards: int = 1000,
|
760
|
-
seed: int = None
|
761
|
-
):
|
821
|
+
|
822
|
+
def __init__(self, N: int = 100, aff_thresh: float = 0.1, max_discards: int = 1000, seed: int = None,
|
823
|
+
no_label_sample_selection: Literal["max_average_difference", "max_nearest_difference"] =
|
824
|
+
"max_average_difference"):
|
762
825
|
"""
|
763
826
|
Constructor of the Negative Selection class (``BNSA``).
|
764
|
-
|
827
|
+
|
765
828
|
Details:
|
766
829
|
---
|
767
830
|
This method initializes the ``detectors``, ``classes``, ``N``, ``t`` and ``seed`` attributes.
|
@@ -769,16 +832,23 @@ class BNSA(Base):
|
|
769
832
|
Parameters:
|
770
833
|
---
|
771
834
|
* N (``int``): Number of detectors. Defaults to ``100``.
|
772
|
-
* aff_thresh (``float``): The variable represents the percentage of similarity between
|
773
|
-
|
774
|
-
|
775
|
-
|
835
|
+
* aff_thresh (``float``): The variable represents the percentage of similarity between \
|
836
|
+
the T cell and the own samples. The default value is 10% (0.1), while a value of 1.0 \
|
837
|
+
represents 100% similarity.
|
838
|
+
* max_discards (``int``): This parameter indicates the maximum number of detector \
|
839
|
+
discards in sequence, which aims to avoid a possible infinite loop if a radius is \
|
840
|
+
defined that it is not possible to generate non-self detectors. Defaults to ``1000``.
|
776
841
|
* seed (``int``): Seed for the random generation of values in the detectors. Defaults to ``None``.
|
777
|
-
|
842
|
+
* no_label_sample_selection (``str``): Method for selecting labels for samples designated as \
|
843
|
+
non-members by all non-member detectors. Available method types:
|
844
|
+
- (``max_average_difference``): Selects the class with the highest average difference \
|
845
|
+
among the detectors.
|
846
|
+
- (``max_nearest_difference``): Selects the class with the highest difference between \
|
847
|
+
the nearest and farthest detector from the sample.
|
778
848
|
---
|
779
849
|
|
780
850
|
Construtor da classe de Seleção negativa (``BNSA``).
|
781
|
-
|
851
|
+
|
782
852
|
Details:
|
783
853
|
---
|
784
854
|
Este método inicializa os atributos ``detectors``, ``classes``, ``N``, ``t`` e ``seed``.
|
@@ -786,31 +856,47 @@ class BNSA(Base):
|
|
786
856
|
Parameters:
|
787
857
|
---
|
788
858
|
* N (``int``): Quantidade de detectores. Defaults to ``100``.
|
789
|
-
* aff_thresh (``float``): A variável representa a porcentagem de similaridade entre a
|
790
|
-
|
791
|
-
|
792
|
-
|
859
|
+
* aff_thresh (``float``): A variável representa a porcentagem de similaridade entre a \
|
860
|
+
célula T e as amostras próprias. O valor padrão é de 10% (0,1), enquanto que o valor \
|
861
|
+
de 1,0 representa 100% de similaridade.
|
862
|
+
* max_discards (``int``): Este parâmetro indica o número máximo de descartes de detectores \
|
863
|
+
em sequência, que tem como objetivo evitar um possível loop infinito caso seja definido \
|
864
|
+
um raio que não seja possível gerar detectores do não-próprio. Defaults to ``1000``.
|
793
865
|
* seed (``int``): Semente para a geração randômica dos valores nos detectores. Defaults to ``None``.
|
866
|
+
* no_label_sample_selection (``str``): Método para a seleção de rótulos para amostras designadas \
|
867
|
+
como não pertencentes por todos os detectores não pertencentes. Tipos de métodos disponíveis:
|
868
|
+
- (``max_average_difference``): Seleciona a classe com a maior diferença média entre os \
|
869
|
+
detectores.
|
870
|
+
- (``max_nearest_difference``): Seleciona a classe com a maior diferença entre o detector \
|
871
|
+
mais próximo e mais distante da amostra.
|
872
|
+
|
794
873
|
"""
|
874
|
+
super().__init__()
|
795
875
|
if N > 0:
|
796
876
|
self.N: int = N
|
797
877
|
else:
|
798
878
|
self.N: int = 100
|
799
879
|
|
800
|
-
if
|
880
|
+
if 0 < aff_thresh < 1:
|
801
881
|
self.aff_thresh: float = aff_thresh
|
802
882
|
else:
|
803
883
|
self.aff_thresh: float = 0.1
|
804
884
|
if max_discards > 0:
|
805
885
|
self.max_discards: int = max_discards
|
806
886
|
else:
|
807
|
-
self.max_discards: int =
|
808
|
-
|
887
|
+
self.max_discards: int = 1000
|
888
|
+
|
809
889
|
if seed is not None and isinstance(seed, int):
|
810
890
|
np.random.seed(seed)
|
811
891
|
self.seed: int = seed
|
812
892
|
else:
|
813
893
|
self.seed = None
|
894
|
+
|
895
|
+
if no_label_sample_selection == 'nearest_difference':
|
896
|
+
self.no_label_sample_selection = 'nearest_difference'
|
897
|
+
else:
|
898
|
+
self.no_label_sample_selection = 'max_average_difference'
|
899
|
+
|
814
900
|
self.classes: npt.NDArray = None
|
815
901
|
self.detectors: npt.NDArray = None
|
816
902
|
|
@@ -831,24 +917,26 @@ class BNSA(Base):
|
|
831
917
|
|
832
918
|
----
|
833
919
|
|
834
|
-
A função ``fit(...)``, realiza o treinamento de acordo com ``X`` e ``y``, usando o método
|
920
|
+
A função ``fit(...)``, realiza o treinamento de acordo com ``X`` e ``y``, usando o método
|
835
921
|
de seleção negativa(``NegativeSelect``).
|
836
922
|
|
837
923
|
Parameters:
|
838
924
|
---
|
839
|
-
* X (``npt.NDArray``): Array de treinamento, contendo as amostras é suas características,
|
840
|
-
|
925
|
+
* X (``npt.NDArray``): Array de treinamento, contendo as amostras é suas características, \
|
926
|
+
[``N amostras`` (linhas)][``N características`` (colunas)].
|
841
927
|
* y (``npt.NDArray``): Array com as classes alvos de ``X`` com [``N amostras`` (linhas)].
|
842
928
|
* verbose (``bool``): Feedback da geração de detectores para o usuário.
|
843
929
|
Returns:
|
844
930
|
---
|
845
931
|
(``self``): Retorna a própria instância.
|
846
932
|
"""
|
847
|
-
super()._check_and_raise_exceptions_fit(X, y,
|
933
|
+
super()._check_and_raise_exceptions_fit(X, y, "BNSA")
|
848
934
|
|
935
|
+
# Converte todo o array X para boolean
|
849
936
|
if X.dtype != bool:
|
850
937
|
X = X.astype(bool)
|
851
938
|
|
939
|
+
# Identificando as classes possíveis, dentro do array de saídas ``y``.
|
852
940
|
self.classes = np.unique(y)
|
853
941
|
# Dict que armazenará os detectores com as classes como key.
|
854
942
|
list_detectors_by_class = dict()
|
@@ -858,7 +946,7 @@ class BNSA(Base):
|
|
858
946
|
if verbose:
|
859
947
|
progress = tqdm(total=int(self.N * (len(self.classes))),
|
860
948
|
bar_format='{desc} ┇{bar}┇ {n}/{total} detectors', postfix='\n')
|
861
|
-
|
949
|
+
|
862
950
|
for _class_ in self.classes:
|
863
951
|
# Inicia o conjunto vazio que conterá os detectores válidos.
|
864
952
|
valid_detectors_set: list = []
|
@@ -866,12 +954,12 @@ class BNSA(Base):
|
|
866
954
|
# Informando em qual classe o algoritmo está para a barra de progresso.
|
867
955
|
if verbose:
|
868
956
|
progress.set_description_str(
|
869
|
-
f
|
957
|
+
f"Generating the detectors for the {_class_} class:")
|
870
958
|
while len(valid_detectors_set) < self.N:
|
871
|
-
|
959
|
+
|
872
960
|
is_valid_detector: bool = True
|
873
961
|
# Gera um vetor candidato a detector aleatoriamente com valores 0 e 1.
|
874
|
-
vector_x = np.random.
|
962
|
+
vector_x = np.random.choice([False, True], size=X.shape[1])
|
875
963
|
for i in sample_index[_class_]:
|
876
964
|
# Verifica a validade do detector para o não-próprio com relação às amostras da classe.
|
877
965
|
if hamming(X[i], vector_x) <= self.aff_thresh:
|
@@ -886,22 +974,26 @@ class BNSA(Base):
|
|
886
974
|
else:
|
887
975
|
discard_count += 1
|
888
976
|
if discard_count == self.max_discards:
|
889
|
-
raise Exception(
|
890
|
-
|
891
|
-
|
892
|
-
|
977
|
+
raise Exception(
|
978
|
+
"An error has been identified:\n"
|
979
|
+
f"the maximum number of discards of detectors for the {_class_} "
|
980
|
+
"class has been reached.\nIt is recommended to check the defined "
|
981
|
+
"radius and consider reducing its value."
|
982
|
+
)
|
983
|
+
|
893
984
|
# Adicionar detectores, com as classes como chave na dict.
|
894
985
|
list_detectors_by_class[_class_] = valid_detectors_set
|
895
986
|
|
896
987
|
# Informar a finalização da geração dos detectores para as classes.
|
897
988
|
if verbose:
|
898
989
|
progress.set_description(
|
899
|
-
f'\033[92m✔ Non-self detectors for classes ({", ".join(map(str, self.classes))})
|
990
|
+
f'\033[92m✔ Non-self detectors for classes ({", ".join(map(str, self.classes))}) '
|
991
|
+
f'successfully generated\033[0m')
|
900
992
|
# Armazena os detectores encontrados no atributo, para os detectores da classe.
|
901
993
|
self.detectors = list_detectors_by_class
|
902
994
|
return self
|
903
995
|
|
904
|
-
def predict(self, X: npt.NDArray) -> npt.NDArray:
|
996
|
+
def predict(self, X: npt.NDArray) -> Optional[npt.NDArray]:
|
905
997
|
"""
|
906
998
|
Function to perform the prediction of classes based on detectors
|
907
999
|
created after training.
|
@@ -919,87 +1011,107 @@ class BNSA(Base):
|
|
919
1011
|
|
920
1012
|
---
|
921
1013
|
|
922
|
-
Função para efetuar a previsão das classes com base nos detectores
|
1014
|
+
Função para efetuar a previsão das classes com base nos detectores
|
923
1015
|
criados após o treinamento.
|
924
1016
|
|
925
1017
|
Parameters:
|
926
1018
|
---
|
927
|
-
* X (``npt.NDArray``): Array com as amostras de entradas com [``N amostras`` (Linhas)] e
|
1019
|
+
* X (``npt.NDArray``): Array com as amostras de entradas com [``N amostras`` (Linhas)] e
|
928
1020
|
[``N características``(Colunas)]
|
929
1021
|
|
930
1022
|
Returns:
|
931
1023
|
---
|
932
|
-
* C – (``npt.NDArray``): um ndarray de forma ``C`` [``N amostras``],
|
1024
|
+
* C – (``npt.NDArray``): um ndarray de forma ``C`` [``N amostras``],
|
933
1025
|
contendo as classes previstas para ``X``.
|
934
1026
|
* ``None``: Se não existir detectores para a previsão.
|
935
1027
|
"""
|
936
1028
|
# se não houver detectores retorna None.
|
937
1029
|
if self.detectors is None:
|
938
1030
|
return None
|
939
|
-
elif not isinstance(X,
|
1031
|
+
elif not isinstance(X, (np.ndarray, list)):
|
940
1032
|
raise TypeError("X is not an ndarray or list")
|
941
1033
|
elif len(self.detectors[self.classes[0]][0]) != len(X[0]):
|
942
|
-
raise Exception(
|
943
|
-
|
1034
|
+
raise Exception(
|
1035
|
+
"X does not have {} features to make the prediction".format(
|
1036
|
+
len(self.detectors[self.classes[0]][0])
|
1037
|
+
)
|
1038
|
+
)
|
944
1039
|
# Verifica se a matriz X contém apenas amostras binárias. Caso contrário, lança uma exceção.
|
945
1040
|
if not np.isin(X, [0, 1]).all():
|
946
1041
|
raise ValueError(
|
947
|
-
"The array X contains values that are not composed only of 0 and 1."
|
1042
|
+
"The array X contains values that are not composed only of 0 and 1."
|
1043
|
+
)
|
948
1044
|
|
1045
|
+
# Converte todo o array X para boolean
|
949
1046
|
if X.dtype != bool:
|
950
1047
|
X = X.astype(bool)
|
951
|
-
|
1048
|
+
|
952
1049
|
# Inicia um array vazio.
|
953
|
-
C = np.empty(shape=
|
1050
|
+
C = np.empty(shape=0)
|
954
1051
|
# Para cada linha de amostra em X.
|
955
1052
|
for line in X:
|
956
1053
|
class_found: bool = True
|
957
|
-
# Lista para armazenar as possíveis classes às quais a amostra se adequou ao self na
|
958
|
-
|
1054
|
+
# Lista para armazenar as possíveis classes às quais a amostra se adequou ao self na
|
1055
|
+
# comparação com os detectores non-self.
|
1056
|
+
possible_classes: list = []
|
959
1057
|
for _class_ in self.classes:
|
960
|
-
# Lista para
|
961
|
-
|
1058
|
+
# Lista para armazenar as taxas de similaridade entre a amostra e os detectores.
|
1059
|
+
similarity_sum: float = 0
|
962
1060
|
for detector in self.detectors[_class_]:
|
963
1061
|
similarity = hamming(line, detector)
|
964
1062
|
if similarity <= self.aff_thresh:
|
965
1063
|
class_found = False
|
966
1064
|
break
|
967
1065
|
else:
|
968
|
-
|
969
|
-
# Se a amostra passar por todos os detectores de uma classe, adiciona a classe como
|
1066
|
+
similarity_sum += similarity
|
1067
|
+
# Se a amostra passar por todos os detectores de uma classe, adiciona a classe como
|
1068
|
+
# possível previsão e sua media de similaridade.
|
970
1069
|
if class_found:
|
971
|
-
possible_classes.append([_class_,
|
972
|
-
|
1070
|
+
possible_classes.append([_class_, similarity_sum / self.N])
|
1071
|
+
|
973
1072
|
# Se, pertencer a uma ou mais classes, adiciona a classe com a distância média mais distante.
|
974
|
-
if len(possible_classes) > 0
|
975
|
-
C = np.append(
|
1073
|
+
if len(possible_classes) > 0:
|
1074
|
+
C = np.append(
|
1075
|
+
C, [max(possible_classes, key=lambda x: x[1])[0]])
|
976
1076
|
class_found = True
|
977
1077
|
else:
|
978
1078
|
class_found = False
|
979
1079
|
|
980
1080
|
# Se possuir apenas uma classe e não classificar a amostra define a saída como não-própria.
|
981
1081
|
if not class_found and len(self.classes) == 1:
|
982
|
-
C = np.append(C, [
|
983
|
-
# Se
|
1082
|
+
C = np.append(C, ["non-self"])
|
1083
|
+
# Se a classe não puder ser identificada pelos detectores
|
984
1084
|
elif not class_found:
|
985
|
-
class_differences =
|
1085
|
+
class_differences: dict = {}
|
986
1086
|
for _class_ in self.classes:
|
987
|
-
|
988
|
-
|
989
|
-
differences
|
990
|
-
|
991
|
-
|
992
|
-
|
1087
|
+
# Atribua-a o rotulo a classe com à maior distância em relação ao detector mais próximo.
|
1088
|
+
if self.no_label_sample_selection == 'nearest_difference':
|
1089
|
+
differences: list = []
|
1090
|
+
for detector in self.detectors[_class_]:
|
1091
|
+
differences.append(hamming(line, detector))
|
1092
|
+
class_differences[_class_] = min(differences)
|
1093
|
+
# Ou com base na maior distância com relação à média da distancias dos detectores
|
1094
|
+
else:
|
1095
|
+
difference_sum: float = 0
|
1096
|
+
for detector in self.detectors[_class_]:
|
1097
|
+
difference_sum += hamming(line, detector)
|
1098
|
+
class_differences[_class_] = difference_sum / self.N
|
1099
|
+
|
1100
|
+
C = np.append(
|
1101
|
+
C, [max(class_differences, key=class_differences.get)])
|
1102
|
+
|
993
1103
|
return C
|
994
1104
|
|
995
1105
|
def __slice_index_list_by_class(self, y: npt.NDArray) -> dict:
|
996
1106
|
"""
|
997
|
-
The function ``__slice_index_list_by_class(...)``, separates the indices of the lines according
|
998
|
-
to loop through the sample array, only in positions where the output is
|
1107
|
+
The function ``__slice_index_list_by_class(...)``, separates the indices of the lines according \
|
1108
|
+
to the output class, to loop through the sample array, only in positions where the output is \
|
1109
|
+
the class being trained.
|
999
1110
|
|
1000
1111
|
Parameters:
|
1001
1112
|
---
|
1002
|
-
* y (npt.NDArray): Receives a ``y``[``N sample``] array with the output classes of the
|
1113
|
+
* y (npt.NDArray): Receives a ``y``[``N sample``] array with the output classes of the \
|
1114
|
+
``X`` sample array.
|
1003
1115
|
|
1004
1116
|
returns:
|
1005
1117
|
---
|
@@ -1007,12 +1119,14 @@ class BNSA(Base):
|
|
1007
1119
|
|
1008
1120
|
---
|
1009
1121
|
|
1010
|
-
A função ``__slice_index_list_by_class(...)``, separa os índices das linhas conforme a classe
|
1011
|
-
para percorrer o array de amostra, apenas nas posições que a saída for a classe que
|
1122
|
+
A função ``__slice_index_list_by_class(...)``, separa os índices das linhas conforme a classe \
|
1123
|
+
de saída, para percorrer o array de amostra, apenas nas posições que a saída for a classe que \
|
1124
|
+
está sendo treinada.
|
1012
1125
|
|
1013
1126
|
Parameters:
|
1014
1127
|
---
|
1015
|
-
* y (npt.NDArray): Recebe um array ``y``[``N amostra``] com as classes de
|
1128
|
+
* y (npt.NDArray): Recebe um array ``y``[``N amostra``] com as classes de saída do array \
|
1129
|
+
de amostra ``X``.
|
1016
1130
|
|
1017
1131
|
Returns:
|
1018
1132
|
---
|
@@ -1026,8 +1140,8 @@ class BNSA(Base):
|
|
1026
1140
|
|
1027
1141
|
Details:
|
1028
1142
|
---
|
1029
|
-
This function performs the prediction of X and checks how many elements are equal between vector
|
1030
|
-
This function was added for compatibility with some scikit-learn functions.
|
1143
|
+
This function performs the prediction of X and checks how many elements are equal between vector \
|
1144
|
+
y and y_predicted. This function was added for compatibility with some scikit-learn functions.
|
1031
1145
|
|
1032
1146
|
Parameters:
|
1033
1147
|
-----------
|
@@ -1049,7 +1163,8 @@ class BNSA(Base):
|
|
1049
1163
|
|
1050
1164
|
Details:
|
1051
1165
|
---
|
1052
|
-
Esta função realiza a previsão de X e verifica quantos elementos são iguais entre o vetor y
|
1166
|
+
Esta função realiza a previsão de X e verifica quantos elementos são iguais entre o vetor y \
|
1167
|
+
e y_previsto.
|
1053
1168
|
Essa função foi adicionada para oferecer compatibilidade com algumas funções do scikit-learn.
|
1054
1169
|
|
1055
1170
|
Parameters:
|
@@ -1070,8 +1185,8 @@ class BNSA(Base):
|
|
1070
1185
|
|
1071
1186
|
def get_params(self, deep: bool = True) -> dict:
|
1072
1187
|
return {
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
}
|
1188
|
+
"N": self.N,
|
1189
|
+
"aff_thresh": self.aff_thresh,
|
1190
|
+
"max_discards": self.max_discards,
|
1191
|
+
"seed": self.seed,
|
1192
|
+
}
|