Skip to content

Commit

Permalink
Improved the importance() function, adding another method to compute …
Browse files Browse the repository at this point in the history
…it. Added an input variable: method = '1class' (for the previous method) or 'comb_classes' (for the new method). The default method is '1class'. Created a little function (subtract_from_index()) in the standard.py script to be used in the computation of the new method.
  • Loading branch information
jongari7 committed Sep 20, 2024
1 parent b4e089b commit 937f525
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 18 deletions.
4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/pudu_jon.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 58 additions & 17 deletions pudu/pudu.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ def __init__(self, x, y, pf, model=None):

# Some error handling
error_handler.for_constructor(model, x, y)


def importance(self, window=1, scope=None, evolution=None, padding='center', bias=0,
absolute=False, perturbation=ptn.Bidirectional(), mask=msk.All()):

def importance(self, window=1, scope=None, evolution=None,
padding='center', bias=0, absolute=False,
perturbation=ptn.Bidirectional(), method='1class',
mask=msk.All()):
"""
Calculates the importance vector for the input feature.
Expand All @@ -80,21 +82,33 @@ def importance(self, window=1, scope=None, evolution=None, padding='center', bia
:type scope: tupple(int, int)
:param scope: Starting and ending point of the analysis for each feature.
If `None`, the all the vector is analysed.
If `None`, the all the vector is analysed.
:type evolution: int
:param evolution: feature width to be changeg each time.
:type padding: string
:param padding: Type of padding. If the legnth of `x` is not divisible
by `window` then padding is applyed. If `center`, then equal padding
to each side is applyed. If `right`, then paading to the right is
:type padding: string
:param padding: Type of padding. If the legnth of `x` is not divisible
by `window` then padding is applyed. If `center`, then equal padding
to each side is applyed. If `right`, then paading to the right is
added and `window`starts from `0`. If `left`, padding to the left
is applyied and `window` ends at length `x`. If perfet `center` is
not possible, then ipadding left is added `1`.
:type absolute: bool
:param absolute: Weather or not the result is in absolute value or not. Default is `False`.
:param absolute: Weather or not the result is in absolute value or not.
Default is `False`.
:type method: string
:param method: Method to compute the importance, there are 2
posibilities: '1class': only is used the evolution class or the
currect class (if evolution=None) to compute the difference in the
probabilities.
And 'comb_classes': is used all the probabilities
classes to see how is the change between the different classes
(looking at probability ratio changes) to compute the importance,
and only taking into account the dominant term (If evolution=None,
the method always is the '1class'). Default is `1class`.
"""
error_handler.for_params(window, scope, padding, absolute, 0, None, None)

Expand All @@ -105,6 +119,7 @@ def importance(self, window=1, scope=None, evolution=None, padding='center', bia

scope, window, padd, evolution, total = standards.params_std(self.y, sh, scope, window, padding, evolution)

initial_class = int(self.y)
p0 = self.pf(self.x)
section = 1
row = padd[0][0] + scope[0][0]
Expand All @@ -121,10 +136,33 @@ def importance(self, window=1, scope=None, evolution=None, padding='center', bia

temp, temp2 = perturbation.apply(x_copy, row, col, window, bias)

if temp2 is None:
val = self.pf(temp) - p0
else:
val = (self.pf(temp2) + self.pf(temp) - 2*p0) / 2
if (method == '1class' or evolution == initial_class or
temp2 is not None):
if temp2 is None:
val = self.pf(temp) - p0
else:
val = (self.pf(temp2) + self.pf(temp) - 2*p0) / 2

elif method == 'comb_classes':
# The importance is computed by the change in the
# difference between classes
p1 = self.pf(temp)
# Compute the difference between the class probs
dif_p0 = standards.subtract_from_index(p0,
initial_class)
dif_p1 = standards.subtract_from_index(p1,
initial_class)

dif_probs = dif_p0 - dif_p1

# Only keeps the dominate value
# Find the index of the maximum absolute value
max_index = np.argmax(np.abs(dif_probs))
# Create a new array filled with zeros
val = np.zeros_like(dif_probs)
# Set the value at max_index to the original value
# (not absolute)
val[max_index] = dif_probs[max_index]

if absolute:
val = abs(val)
Expand All @@ -133,7 +171,7 @@ def importance(self, window=1, scope=None, evolution=None, padding='center', bia
self.imp[0, row:row+window[0], col:col+window[1], 0] = val[evolution]
else:
self.imp[0, row:row+window[0], col:col+window[1], 0] = val

del x_copy, temp, temp2
else:
pass
Expand All @@ -142,10 +180,13 @@ def importance(self, window=1, scope=None, evolution=None, padding='center', bia

col += window[1]
row += window[0]

max_val, min_val = self.imp.max(), self.imp.min()
self.imp_rel = (self.imp - min_val) / (max_val - min_val)

if max_val == min_val:
self.imp_rel = np.zeros_like(self.imp)
else:
self.imp_rel = (self.imp - min_val) / (max_val - min_val)


def speed(self, window=1, scope=None, evolution=None, padding='center',
Expand Down
29 changes: 29 additions & 0 deletions pudu/standards.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,32 @@ def params_std(y, sh, scope, window, padding, evolution):
total = sec_row*sec_col

return scope, window, padding, evolution, total


def subtract_from_index(vector, index):
"""
This function substract the value of the index to all the vector values.
:type vector: numpy array
:param vector: Vector (or array 1d)
:type index: int
:param index: Index of the substracted value
:rtype: numpy array
:returns: Vector (or array 1d) with the substracted result
"""
# Convert p0 to a numpy array of floats (in case it's not already)
vector = np.array(vector, dtype=float)

# Check that the index is within the valid range
if index < 0 or index >= len(vector):
raise IndexError("The index is out of bounds")

# Get the value at the selected index
value = vector[index]

# Subtract the value at the selected index from all other elements
result = vector - value

return result

0 comments on commit 937f525

Please sign in to comment.