Skip to content Skip to sidebar Skip to footer

Is It Possible To Numpy.vectorize An Instance Method?

I've found that the numpy.vectorize allows one to convert 'ordinary' functions which expect a single number as input to a function which can also convert a list of inputs into a li

Solution 1:

Simple solution without modifying the class

You can use np.vectorize directly on the method on the instance:

class Dummy(object):

    def __init__(self, val=1):
        self.val = val

    def f(self, x):
        if x == 0:
            return self.val
        else:
            return 2


vec_f = np.vectorize(Dummy().f) 


def test_3():
    assert list(vec_f([0, 1, 2])) == [1, 2, 2]

test_3()

You can also create a vectorized function vec_f in your __init__:

Adding a vectorized version to the instance

class Dummy(object):

    def __init__(self, val=1):
        self.val = val
        self.vec_f = np.vectorize(self.f) 

    def f(self, x):
        if x == 0:
            return self.val
        else:
            return 2


def test_3():
    assert list(Dummy().vec_f([0, 1, 2])) == [1, 2, 2]

or with a different naming scheme:

class Dummy(object):

    def __init__(self, val=1):
        self.val = val
        self.f = np.vectorize(self.scalar_f) 

    def scalar_f(self, x):
        if x == 0:
            return self.val
        else:
            return 2


def test_3():
    assert list(Dummy().f([0, 1, 2])) == [1, 2, 2]

test_3()

    test_3()

Solution 2:

If you want to use vectorized implementation of your method you can use excluded parameter like following:

class MyClass:
    def __init__(self, data):
        self.data = data
        self.my_vectorized_func = np.vectorize(self.my_func, excluded='self')

    def my_func(self, x):
        return pow(x, self.data)

With this, you can use your method like the non-vectorized one:

 In[1]: myclass = MyClass(3) # '3' will be the power factor of our function
 In[2]: myclass.my_vectorized_func([1, 2, 3, 4, 5])
Out[3]: array([  1,   8,  27,  64, 125])

Solution 3:

Remembering a technique I saw in the memoized decorator, I managed to get the decorator to also work for instance methods by subclassing numpy.vectorize as follows:

import numpy as np
import functools


class vectorize(np.vectorize):
    def __get__(self, obj, objtype):
        return functools.partial(self.__call__, obj)

Now if I decorate the Dummy class' f method with vectorize instead of np.vectorize, the test passes:

class Dummy(object):
    def __init__(self, val=1):
        self.val = val

    @vectorize
    def f(self, x):
        if x == 0:
            return self.val
        else:
            return 2


def test_3():
    assert list(Dummy().f([0, 1, 2])) == [1, 2, 2]

if __name__ == "__main__":
    pytest.main([__file__])

with output

test_numpy_vectorize.py .

=========================== 1 passed in 0.01 seconds ===========================
[Finished in 0.7s]

Solution 4:

Here's a generic decorator that works with instance methods as well as functions (refer to Numpy's documentation for otypes and signature):

from functools import wraps

import numpy as np

def vectorize(otypes=None, signature=None):
    """Numpy vectorization wrapper that works with instance methods."""
    def decorator(fn):
        vectorized = np.vectorize(fn, otypes=otypes, signature=signature)
        @wraps(fn)
        def wrapper(*args):
            return vectorized(*args)
        return wrapper
    return decorator

You may use it to vectorize your method as follows:

class Dummy(object):
    def __init__(self, val=1):
        self.val = val

    @vectorize(signature="(),()->()")
    def f(self, x):
        if x == 0:
            return self.val
        else:
            return 2


def test_3():
    assert list(Dummy().f([0, 1, 2])) == [1, 2, 2]

The key is to make use of the signature kwarg. Parenthesized values to the left of -> specify input parameters and values to the right specify output values. () represents a scalar (0-dimensional vector); (n) represents a 1-dimensional vector; (m,n) represents a 2-dimensional vector; (m,n,p) represents a 3-dimensional vector; etc. Here, signature="(),()->()" specifies to Numpy that the first parameter (self) is a scalar, the second (x) is also a scalar, and the method returns a scalar (either self.val or 2, depending on x).

$ pytest /tmp/instance_vectorize.py
======================= test session starts ========================
platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /tmp, inifile:
collected 1 item

../../tmp/instance_vectorize.py .                                                                                                                                                     [100%]

==================== 1 passed in 0.08 seconds ======================

Post a Comment for "Is It Possible To Numpy.vectorize An Instance Method?"