2016-05-06 2 views
0

Предположим, у меня есть матрица n x m и вы хотите вызвать функцию fct на каждый из ее элементов. Я могу сделать это нравится:`vectorize` для каждой строки в Numpy

A = numpy.array(...) 
vec_func = numpy.vectorize(fct) 
A_out = vec_func(A) 

Это будет строго применять функцию на каждом из матричных элементов ГЦТ будет функция:

def fct(a_ij): 
    # do something with matrix element a(i, j) 

Теперь я хотел бы то же самое, но для каждого строка матрицы:

def fct(row_i): 
    # do something with matrix row(i) 

есть ли способ сделать это с numpy.vectorize или похож?

+2

Я просто прочитал: «Функция векторизации предоставляется в основном для удобства, а не для производительности. Реализация по существу является циклом for». Таким образом, функция в любом случае не так полезна. – Michael

+3

Нет никакого «функционально-агностического» метода векторизации, который даст вам значительно лучшую производительность (как вы видели, «np.vectorize» - это просто синтаксический сахар). Вы можете либо переписать 'fct', чтобы принимать массивы в качестве входных аргументов, либо переключиться на скомпилированную реализацию (например, Cython, numba). –

+0

Чтобы добавить к предложению @ ali_m, вы можете попробовать обобщенный ufunc numba http://numba.pydata.org/numba-doc/dev/user/vectorize.html#the-guvectorize-decorator. Помимо любого увеличения скорости, он делает интеллектуальное вещание, которое вы хотите. – DavidW

ответ

1

Редактировать: похоже, np.apply_along_axis делает то, что вы хотите. Например:

import numpy as np 

def f(x): 
    return x * x.sum() 

X = np.arange(12).reshape(2, 2, 3) 
np.apply_along_axis(f, -1, X) 
# array([[[ 0, 3, 6], 
#   [ 36, 48, 60]], 
# 
#  [[126, 147, 168], 
#   [270, 300, 330]]]) 

Заметки об исполнении от моего первоначального ответа ниже по-прежнему применяются. не


Оригинальный ответ:

Там нет встроенной для этого, но Python делает его простым определить таким контекстом менеджеру самостоятельно. Например:

import numpy as np 
from contextlib import wraps 

def row_vectorize(f): 
    @wraps(f) 
    def wrapped_f(X): 
     X = np.asarray(X) 
     rows = X.reshape(-1, X.shape[-1]) 
     return np.reshape([f(row) for row in rows], 
          X.shape[:-1] + (-1,)) 
    return wrapped_f 


@row_vectorize 
def func(row): 
    return row * row.sum() 

Теперь вы можете использовать это на массивы любой ненулевой размерности:

>>> X_1D = np.arange(3) 
>>> func(X_1D) 
array([0, 3, 6]) 

>>> X_2D = np.arange(6).reshape(2, 3) 
>>> func(X_2D) 
array([[ 0, 3, 6], 
     [36, 48, 60]]) 

>>> X_3D = np.arange(12).reshape((2, 2, 3)) 
>>> func(X_3D) 
array([[[ 0, 3, 6], 
     [ 36, 48, 60]], 

     [[126, 147, 168], 
     [270, 300, 330]]]) 

С точки зрения производительности, np.vectorize делает что-то очень похожее.

Если вам нужна более быстрая петля для настраиваемой функции, применяемой к массиву, вы можете часто создавать свой метод в терминах операций с элементами numpy и сводных операций; например, эта функция выполняет то же самое, что и функция рядной векторизовано выше, но будет намного быстрее на больших входах:

def func2(X): 
    return X * X.sum(-1, keepdims=True) 

Если у вас есть более сложные операции, вы хотите применить по строкам массива и производительность петель является узким местом, лучшие варианты, вероятно, должны использовать numba или cython.

Смежные вопросы