Как применить значения функции/карты для каждого элемента в массиве/матрице 2d numpy?

Учитывая следующую матрицу:

import numpy as np
mymatrix = mymatrix = np.matrix('-1 0 1; -2 0 2; -4 0 4')


matrix([[-1,  0,  1],
        [-2,  0,  2],
        [-4,  0,  4]])

и следующая функция (сигмоидальная/логистическая):

import math
def myfunc(z):
    return 1/(1+math.exp(-z))

Я хочу получить новый массив/матрицу numpy, где каждый элемент является результатом применения функции myfunc к соответствующему элементу исходной матрицы.

map(myfunc, mymatrix) терпит неудачу, потому что она пытается применить myfunc к строкам не к каждому элементу. Я попытался использовать numpy.apply_along_axis и numpy.apply_over_axis но они также предназначены для применения функции к строкам или столбцам, а не по элементам.

Итак, как можно применить myfunc(z) к каждому элементу myarray чтобы получить:

matrix([[ 0.26894142,  0.5       ,  0.73105858],
        [ 0.11920292,  0.5       ,  0.88079708],
        [ 0.01798621,  0.5       ,  0.98201379]])

Ответ 1

Видимо, способ применить функцию к элементам - это преобразовать вашу функцию в векторизованную версию, которая принимает массивы в качестве входных данных и возвращает массивы в качестве выходных данных.

Вы можете легко преобразовать свою функцию в векторизованную форму, используя numpy.vectorize следующим образом:

myfunc_vec = np.vectorize(myfunc)
result = myfunc_vec(mymatrix)

или для одноразового использования:

np.vectorize(myfunc)(mymatrix)

Как отмечает @Divakar, было бы лучше (с точки зрения производительности), если вы можете написать уже векторизованную функцию с нуля (используя встроенную ufuncs без использования numpy.vectorize), примерно так:

def my_vectorized_func(m):
    return 1/(1+np.exp(-m))  # np.exp() is a built-in ufunc

myvectorized_func(mymatrix)

Поскольку numpy.exp уже векторизовано (а math.exp нет), все выражение 1/(1+np.exp(-m)) будет векторизовано (и быстрее, чем при применении моей исходной функции к каждому элементу).

В следующем полном примере был получен требуемый результат:

import numpy as np
mymatrix = mymatrix = np.matrix('-1 0 1; -2 0 2; -4 0 4')
import math
def myfunc(z):
    return 1/(1+math.exp(-z))

np.vectorize(myfunc)(mymatrix) # ok, but slow

def my_vectorized_func(m):
    return 1/(1+np.exp(-m))

my_vectorized_func(mymatrix) # faster using numpy built-in ufuncs

Ответ 2

На всякий случай, у scipy есть функция sigmoid, которую вы можете напрямую вызывать в матрице.