Понимание разницы между numpy .log и numpy .sum для контейнеров пользовательских массивов - PullRequest
2 голосов
/ 16 февраля 2020

Я создаю пользовательский контейнер для массива NumPy, следуя инструкциям на веб-сайте SciPy . Я написал следующий код, который:

  • создает класс, NpContainer
  • определяет пользовательское поведение для функций np.sum и np.log для вывода строки.
import numpy as np

HANDLED_FUNCTIONS = {}

class NpContainer:
    def __init__(self, val):
        self.val = val

    def __array__(self):
        return np.array(self.val)

    def __array_function__(self, func, types, args, kwargs):
        if func not in HANDLED_FUNCTIONS:
            raise NotImplementedError()

        return HANDLED_FUNCTIONS[func](*args, **kwargs)

def implements(np_function):
    def decorator(func):
        HANDLED_FUNCTIONS[np_function] = func
        return func
    return decorator

@implements(np.sum)
def sum(a, **kwargs):
    return 'Sum Val: {}'.format(np.sum(a.val, **kwargs))

@implements(np.log)
def log(a, **kwargs):
    return 'Log Val: {}'.format(np.log(a, **kwargs))

Я тестирую код, используя:

if __name__ == "__main__":
    container1 = NpContainer(val=np.array([1., 2.]))

    sum_result = np.sum(container1)
    print(sum_result)
    print(type(sum_result))

    log_result = np.log(container1)
    print(log_result)
    print(type(log_result))

Сумма дает ожидаемый результат.

Sum Val: 3.0
<class 'str'>

Однако np.log возвращает NumPy массив вместо строки.

[0.         0.69314718]
<class 'numpy.ndarray'>

Кто-нибудь знает, почему np.log пропускает мою пользовательскую функцию? Любая помощь приветствуется!

1 Ответ

2 голосов
/ 16 февраля 2020

Хорошо, я думаю - я знаю, что происходит. Вы реализовали функцию __array_function__, которая должна соответствовать np.sum, но для np.log вы должны сделать __array_ufunc__, так как это универсальная функция (https://docs.scipy.org/doc/numpy/reference/arrays.classes.html#numpy .class. array_ufun c).

Есть еще немного аромата, который я рекомендую вам проверить здесь:

https://numpy.org/neps/nep-0018-array-function-protocol.html

Сейчас как ни странно - после реализации __array_ufunc__ четное np.sum будет обработано как ufunc, что спутано с

.

*1024*ufunc функцией автоматического приведения для np.sum is np.add, так что нижеприведенное вам подойдет - , хотя я бы скорее рекомендовал реализовать sum() как функцию для NpContainer - чтобы вы могли сделать container1.sum() вместо

import numpy as np

HANDLED_FUNCTIONS = {}

class NpContainer:
    def __init__(self, val):
        self.val = val

    def __array__(self):
        return np.array(self.val)

    def __array_function__(self, func, types, args, kwargs):
        if func not in HANDLED_FUNCTIONS:
            raise NotImplementedError()

        return HANDLED_FUNCTIONS[func](*args, **kwargs)

    def __array_ufunc__(self, ufunc, method, *args, **kwargs):
        if ufunc not in HANDLED_FUNCTIONS:
            raise NotImplementedError()

        return HANDLED_FUNCTIONS[ufunc](*args, **kwargs)        

def implements(np_function):
    def decorator(func):
        HANDLED_FUNCTIONS[np_function] = func
        return func
    return decorator

@implements(np.add)
def sum(a, **kwargs):
    return 'Sum Val: {}'.format(np.sum(a.val, **kwargs))

@implements(np.log)
def log(a, **kwargs):
    return 'Log Val: {}'.format(np.log(a.val, **kwargs))

if __name__ == "__main__":
    container1 = NpContainer(val=np.array([1., 2.]))

    log_result = np.log(container1)
    print(log_result)
    print(type(log_result))

    sum_result = np.sum(container1)
    print(sum_result)
    print(type(sum_result))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...