Skip to content

Contra

All classes to make a predictions with CONTRA method.

ContraTree(branches, novelty)

Contra decision tree.

Parameters:

Name Type Description Default
branches typing.List[niva.core.contra.tree.Branch]

List of branches in Contra decision tree.

required
novelty niva.core.contra.novelty.NoveltyIndex

Novelty index for this tree.

required

Attributes:

Name Type Description
branches typing.List[niva.core.contra.tree.Branch]

List of branches in Contra decision tree.

novelty niva.core.contra.novelty.NoveltyIndex

Novelty index for this tree.

Source code in niva/core/contra/tree.py
131
132
133
134
135
136
137
138
139
140
141
142
def __init__(self, branches: List[Branch], novelty: NoveltyIndex):
    """
    Args:
        branches (List[Branch]): List of branches in Contra decision tree.
        novelty (NoveltyIndex): Novelty index for this tree.

    Attributes:
        branches (List[Branch]): List of branches in Contra decision tree.
        novelty (NoveltyIndex): Novelty index for this tree.
    """
    self.branches = branches
    self.novelty = novelty

predict(sample)

Output the CONTRA decision tree prediction for a sample.

Parameters:

Name Type Description Default
sample niva.core.sample.Sample

Sample dataclass.

required

Returns:

Type Description
typing.Tuple[float, float, str]

Prediction, Novelty index, nearest_branch.

Source code in niva/core/contra/tree.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
def predict(self, sample: Sample) -> Tuple[float, float, str]:
    """Output the CONTRA decision tree prediction for a sample.

    Args:
        sample (Sample): Sample dataclass.

    Returns:
        Prediction, Novelty index, nearest_branch.
    """
    # TODO type the output with NamedTuple, dataclass or TypedDict
    memberships = [branch.membership(sample) for branch in self.branches]
    branch_memberships = sum(memberships)
    branch_values = sum([branch.evaluate(sample) for branch in self.branches])
    prediction = branch_values / branch_memberships
    novelty_index, rule = self.novelty.evaluate(sample)
    if not rule:
        prediction = None
    nearest_branch = self.branches[np.argmax(memberships)].path

    return prediction, novelty_index, nearest_branch

Branch(nodes, correction=None, operator=prod)

Branch is a succession of Node of Contra decision tree.

Parameters:

Name Type Description Default
nodes typing.List[niva.core.contra.tree.Node]

List of branch nodes.

required
correction float

Correction of branch value.

None
operator typing.Callable

Operator to apply to combine nodes memberships.

math.prod

Attributes:

Name Type Description
nodes typing.List[niva.core.contra.tree.Node]

List of branch nodes.

correction float

Correction of branch value.

operator typing.Callable

Operator to apply to combine nodes memberships.

value float

Branch value according to nodes values and states.

node_dict Dict[str, niva.core.contra.tree.Node]

Dict of node that map Node name to Node instance.

Source code in niva/core/contra/tree.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def __init__(
    self, nodes: List[Node], correction: float = None, operator: Callable = prod
):
    """
    Args:
        nodes (List[Node]): List of branch nodes.
        correction (float): Correction of branch value.
        operator (Callable): Operator to apply to combine nodes memberships.

    Attributes:
        nodes (List[Node]): List of branch nodes.
        correction (float): Correction of branch value.
        operator (Callable): Operator to apply to combine nodes memberships.
        value (float): Branch value according to nodes values and states.
        node_dict (Dict[str, Node]): Dict of node that map Node name to Node instance.
    """

    self.correction = correction
    self.nodes = nodes
    self.operator = operator
    self.value = sum([node.weight for node in self.nodes if node.state == "F"])
    self.node_dict = {node.name: node for node in self.nodes}

path property

Return succession of nodes states in concatenated string.

membership(sample)

Evaluate the membership of a sample.

Parameters:

Name Type Description Default
sample niva.core.sample.Sample

Sample with variables values.

required

Returns:

Type Description
float

Sample's membership to the branch.

Source code in niva/core/contra/tree.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def membership(self, sample: Sample) -> float:
    """Evaluate the membership of a sample.

    Args:
        sample (Sample): Sample with variables values.

    Returns:
        Sample's membership to the branch.
    """

    nodes_membership = [
        node.membership(sample.to_dict()[node_name])
        for node_name, node in self.node_dict.items()
    ]
    return self.operator(nodes_membership)

evaluate(sample)

Return the branch value for this sample.

Parameters:

Name Type Description Default
sample niva.core.sample.Sample

dict of node name : value for this node/variable.

required

Returns:

Type Description
float

Branch value for Sample.

Source code in niva/core/contra/tree.py
115
116
117
118
119
120
121
122
123
124
125
def evaluate(self, sample: Sample) -> float:
    """Return the branch value for this sample.

    Args:
        sample (Sample): dict of node name : value for this node/variable.

    Returns:
        Branch value for Sample.
    """
    membership = self.membership(sample)
    return membership * (self.value + self.correction)

Node(name, favorable_limit, unfavorable_limit, weight, state='F') dataclass

Node of Contra decision tree model. It's associated to a variable of a model.

Parameters:

Name Type Description Default
name str

Name of the corresponding variable.

required
favorable_limit float

Minimal value to consider as favorable.

required
unfavorable_limit float

Minimal value to consider as unfavorable.

required
weight float

Weight associated to the node in final prediction.

required
state typing.Literal['F', 'U']

State of the node.

'F'

membership_function(value)

Return membership of the value for the favorable case.

Parameters:

Name Type Description Default
value float

Value to evaluate.

required

Returns:

Type Description
float

Probability/membership of value to be in favorable case.

Source code in niva/core/contra/tree.py
32
33
34
35
36
37
38
39
40
41
42
43
44
def membership_function(self, value: float) -> float:
    """Return membership of the value for the favorable case.

    Args:
        value (float): Value to evaluate.

    Returns:
        Probability/membership of value to be in favorable case.
    """
    ratio = (value - self.unfavorable_limit) / (
        self.favorable_limit - self.unfavorable_limit
    )
    return ratio

membership(value)

Compute membership of the value to the Node for given node state (Favorable or Unfavorable).

Parameters:

Name Type Description Default
value float

Value to evaluate.

required

Returns:

Type Description
float

Membership given node state (between 0 & 1).

Source code in niva/core/contra/tree.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def membership(self, value: float) -> float:
    """Compute membership of the value to the Node for given node state (Favorable or Unfavorable).

    Args:
        value (float): Value to evaluate.

    Returns:
        Membership given node state (between 0 & 1).
    """

    membership = self.membership_function(value)
    membership = 1 - membership if self.state == "U" else membership

    if membership > 1:
        membership = 1
    elif membership < 0:
        membership = 0

    return membership

ContraTreeFactory

Factory to register tree configs and build tree from config.

Attributes:

Name Type Description
_tree_configs typing.Dict[str, niva.core.contra.configs.TreeConfig]

Dict of tree_name : TreeConfig

register(name, config) classmethod

Register tree config in ContraTreeFactory.

Parameters:

Name Type Description Default
name str

Name of the tree config.

required
config niva.core.contra.configs.TreeConfig

Tree config.

required
Source code in niva/core/contra/tree_factory.py
18
19
20
21
22
23
24
25
26
@classmethod
def register(cls, name: str, config: TreeConfig):
    """Register tree config in ContraTreeFactory.

    Args:
        name (str): Name of the tree config.
        config (TreeConfig): Tree config.
    """
    cls._tree_configs[name] = config

build(name) classmethod

Gather config from ContraTreeFactory and return the corresponding tree.

Parameters:

Name Type Description Default
name str

Name of the config.

required

Returns:

Type Description
niva.core.contra.tree.ContraTree

Contra tree.

Source code in niva/core/contra/tree_factory.py
28
29
30
31
32
33
34
35
36
37
38
39
@classmethod
def build(cls, name: str) -> ContraTree:
    """Gather config from ContraTreeFactory and return the corresponding tree.

    Args:
        name (str): Name of the config.

    Returns:
        Contra tree.
    """
    tree_config = cls._tree_configs[name]
    return cls._build_tree(tree_config)

NoveltyIndex(mean_calibration, inv_cov, max_dist_calibration)

Novelty Index class based on mahalanobis distance.

Parameters:

Name Type Description Default
mean_calibration numpy.ndarray

Array of N variable's means from calibration dataset (N,).

required
inv_cov numpy.ndarray

Inverse of variables covariance matrix from calibration dataset.

required
max_dist_calibration float

Maximum mahalanobis distance from a calibration sample to the mean.

required

Attributes:

Name Type Description
mean_calibration numpy.ndarray

Array of N variable's means from calibration dataset (N,).

inv_cov numpy.ndarray

Inverse of variables covariance matrix from calibration dataset.

max_dist_calibration float

Maximum mahalanobis distance from a calibration sample to the mean.

Source code in niva/core/contra/novelty.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def __init__(
    self,
    mean_calibration: np.ndarray,
    inv_cov: np.ndarray,
    max_dist_calibration: float,
):
    """
    Args:
        mean_calibration (np.ndarray): Array of N variable's means from calibration dataset (N,).
        inv_cov (np.ndarray): Inverse of variables covariance matrix from calibration dataset.
        max_dist_calibration (float): Maximum mahalanobis distance from a calibration sample to the mean.


    Attributes:
        mean_calibration (np.ndarray): Array of N variable's means from calibration dataset (N,).
        inv_cov (np.ndarray): Inverse of variables covariance matrix from calibration dataset.
        max_dist_calibration (float): Maximum mahalanobis distance from a calibration sample to the mean.
    """
    self.mean_calibration = mean_calibration
    self.inv_cov = inv_cov
    self.max_dist_calib = max_dist_calibration

compute_index(sample)

Return Novelty index for a specific sample.

Parameters:

Name Type Description Default
sample niva.core.sample.Sample

Sample dataclass that store sample's variables values.

required

Returns:

Type Description
float

Novelty index.

Source code in niva/core/contra/novelty.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def compute_index(self, sample: Sample) -> float:
    """Return Novelty index for a specific sample.

    Args:
        sample (Sample): Sample dataclass that store sample's variables values.

    Returns:
        Novelty index.
    """
    sample_data = np.array(list(sample.to_dict().values())[3:])
    sample_dist = (
        mahalanobis(sample_data, self.mean_calibration, self.inv_cov) ** 2
    )  # Calibration is done with square mahalanobis distance
    return sample_dist / self.max_dist_calib

rule(novelty_value) abstractmethod

Rule to consider a novelty value as admissible.

Parameters:

Name Type Description Default
novelty_value float

Novelty value.

required

Returns:

Type Description
bool

True for novelty index admissible else False.

Source code in niva/core/contra/novelty.py
48
49
50
51
52
53
54
55
56
57
58
@abstractmethod
def rule(self, novelty_value: float) -> bool:
    """Rule to consider a novelty value as admissible.

    Args:
        novelty_value (float): Novelty value.

    Returns:
        True for novelty index admissible else False.
    """
    pass

evaluate(sample)

Compute novelty index for a sample and apply admission rule.

Parameters:

Name Type Description Default
sample niva.core.sample.Sample

Sample to compute novelty on.

required

Returns:

Type Description
typing.Tuple[float, bool]

Novelty index values, rule decision.

Source code in niva/core/contra/novelty.py
60
61
62
63
64
65
66
67
68
69
70
def evaluate(self, sample: Sample) -> Tuple[float, bool]:
    """Compute novelty index for a sample and apply admission rule.

    Args:
        sample (Sample): Sample to compute novelty on.

    Returns:
        Novelty index values, rule decision.
    """
    index = self.compute_index(sample)
    return index, self.rule(index)

T1NoveltyIndex(mean_calibration, inv_cov, max_dist_calibration)

Bases: niva.core.contra.novelty.NoveltyIndex

Novelty index for Tier 1.

Source code in niva/core/contra/novelty.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def __init__(
    self,
    mean_calibration: np.ndarray,
    inv_cov: np.ndarray,
    max_dist_calibration: float,
):
    """
    Args:
        mean_calibration (np.ndarray): Array of N variable's means from calibration dataset (N,).
        inv_cov (np.ndarray): Inverse of variables covariance matrix from calibration dataset.
        max_dist_calibration (float): Maximum mahalanobis distance from a calibration sample to the mean.


    Attributes:
        mean_calibration (np.ndarray): Array of N variable's means from calibration dataset (N,).
        inv_cov (np.ndarray): Inverse of variables covariance matrix from calibration dataset.
        max_dist_calibration (float): Maximum mahalanobis distance from a calibration sample to the mean.
    """
    self.mean_calibration = mean_calibration
    self.inv_cov = inv_cov
    self.max_dist_calib = max_dist_calibration

rule(novelty_value)

Rule for Novelty index for Tier 1.

Parameters:

Name Type Description Default
novelty_value float

Novelty index value to evaluate.

required

Returns:

Type Description
bool

Rule output.

Source code in niva/core/contra/novelty.py
76
77
78
79
80
81
82
83
84
85
def rule(self, novelty_value: float) -> bool:
    """Rule for Novelty index for Tier 1.

    Args:
        novelty_value (float): Novelty index value to evaluate.

    Returns:
        Rule output.
    """
    return novelty_value < 1.25