pythonundefinedformulanameerrordefined

Creating a Python class for the distance metric general formula and getting the error "NameError: name 'p' is not defined"


I'm creating a class in Python for the distance metric general formula and I'm getting the error: "NameError: name 'p' is not defined". The code for the class and test and the error("NameError: name 'p' is not defined") are below as well as inline comments describing the problem.

Here is the code for the class:

class Lp_distance_metric_general_formula(object):
"""
This class takes the Lp distance metric general formula and sets p equal to a value provided by the user. 
This has the effect of deriving a distance metric for a specific metric space and calculating the distance 
of a vector in that metric space.

Example
-------
If the user sets p = 2, then the euclidean distance formula is derived.
If the user sets p = 1, then the taxicab distance formula is derived. 

Note
----
It is possible to use p values less than 1 but those are special cases that we will ignore. 
These special values are interesting for academic purposes but in practice you very likely won't need to know 
about them.
"""

def __init__(self, p=2, reg_strength = 1.0):
    
    """
    Parameters
    ----------
    
    p: int or float
        p value used for calculating the distance of a vector in a certain metric space
        
    reg_strength: int or float
        usually set to a value less than 1.0 to decrease the strength of the distance metric when used as a model regularizer
        keep this value at 1.0 when measureing vector norms (i.e. vector lengths)
    """
    
    assert p >=1 , "p value must be greater than or equal to 1"
    
    self.p = p
    self.reg_strength = reg_strength
            
def calc_squared_vector_comps(self):
    
    # raise each vector component in self.x to the power of p
    # save result to self.squared_vector_comps
    # YOUR CODE HERE
    self.squared_vector_comps = (self.x)**p
    
    # raise NotImplementedError()
    
def calc_sum_of_squared_comp(self):
    # take the sum of the squared components in self.squared_vector_comps
    # save to self.sum_of_squared_comp
    # hint: use tf.reduce_sum
    # YOUR CODE HERE
    self.sum_of_squared_comp = tf.reduce_sum(self.squared_vector_comps)
    
    #raise NotImplementedError()
    
def calc_vector_norm(self):
    
    # take the 1/p root of the self.sum_of_squared_comp in order to calculate the norm, i.e. ||x||
    
    # save result to self.vector_norm
    # YOUR CODE HERE
    self.vector_norm = (self.sum_of_squared_comp)**(1/p)
    
    # raise NotImplementedError()
    
    
def __call__(self, x):
    """
    This method calcualtes the distance (i.e. norm) for vector x in Lp space for a value p given by the use
    
    ‖𝑥‖𝑝 = (|𝑥_1|^𝑝 + |𝑥_2|^𝑝 + ⋯ +|𝑥_𝑛|^𝑝 )^1/𝑝
    
    Parameters
    ----------
    x: N-dimsional numpy array or tensorflow tensor of floats 
        x is our vector, could be a weight vector but any vector is valid 
        
        
    HINT
    -----
    You must use self.p when calculating squared_vector_comps and vector_norm
    """
    
    self.x = x
    

    
    # calculate these parts |𝑥_i|^𝑝
    self.calc_squared_vector_comps()
    
    # calcualte this |𝑥_1|^𝑝 + |𝑥_2|^𝑝 + ⋯ +|𝑥_𝑛|^𝑝
    self.calc_sum_of_squared_comp()
    
    # calculate this (|𝑥_1|^𝑝 + |𝑥_2|^𝑝 + ⋯ +|𝑥_𝑛|^𝑝 )^1/𝑝
    self.calc_vector_norm()
    
    # return the vector norm scaled by a regularization penality
    # we say penality because the value is usually less than 1.0 thereby scaling down the norm
    return self.reg_strength * self.vector_norm

Here is the code for the test:

# instantiate the unit test class that will check the calculates of Lp_distance_metric_general_formula's methods
tests = Test_distance_metric_solution()

# instantiate Lp_distance_metric_general_formula, set p = 2 in order to derive the euclidean distance metric

lp = Lp_distance_metric_general_formula(p=2, reg_strength = 1.0)

# don't change this test_vector
# Test_distance_metric_solution assumes that you're using ths exact test_vector
test_vector = np.array([1., 2.])
lp(test_vector)


# test the calculations that are perform in each of the following lp class methods 
tests.test_squared_vector_comps(lp.squared_vector_comps)
tests.test_sum_of_squared_comp(lp.sum_of_squared_comp)
tests.test_vector_norm(lp.vector_norm.numpy())

This is the entire error below:(The last line being the most relevant.)

NameError                                 Traceback (most recent call last)
<ipython-input-60-99f65ee9445b> in <module>
      9 # Test_distance_metric_solution assumes that you're using ths exact test_vector
     10 test_vector = np.array([1., 2.])
---> 11 lp(test_vector)
     12 
     13 '''

<ipython-input-59-68f0851b282b> in __call__(self, x)
     87 
     88         # calculate these parts |𝑥_i|^𝑝
---> 89         self.calc_squared_vector_comps()
     90 
     91         # calcualte this |𝑥_1|^𝑝 + |𝑥_2|^𝑝 + ⋯ +|𝑥_𝑛|^𝑝

<ipython-input-59-68f0851b282b> in calc_squared_vector_comps(self)
     41         # save result to self.squared_vector_comps
     42         # YOUR CODE HERE
---> 43         self.squared_vector_comps = (self.x)**p
     44 
     45         # raise NotImplementedError()

NameError: name 'p' is not defined

Solution

  • Your code fails because when you call your init you assign self.p = p. When the init-method finishes, the p value disappears from the scope, but self.p remains.

    Hence, when you need to refer to your p-value you need to refer to self.p.

    Specifically:

    def calc_vector_norm(self):
        # take the 1/p root of the self.sum_of_squared_comp in order to calculate the norm, i.e. ||x||
    
        # save result to self.vector_norm
        # YOUR CODE HERE
        self.vector_norm = (self.sum_of_squared_comp) ** (1 / self.p)
    
    def calc_squared_vector_comps(self):
        # raise each vector component in self.x to the power of p
        # save result to self.squared_vector_comps
        # YOUR CODE HERE
        self.squared_vector_comps = (self.x) ** self.p