2015-11-07 2 views
0

Я не уверен, было ли это задано раньше. Я не смог найти много релевантных результатов в SO или Google. Во всяком случае, вот что я пытаюсь сделать. У меня есть функция, которая создается во время выполнения, которая принимает 4 параметра.Векторизация/ускорение функции numpy с двумя аргументами разных размеров

My_function (т, х, р, а)

т является скаляром с плавающей точкой
Х представляет собой 1D Numpy массив поплавки
р и словари

У меня есть Numpy массив T и массив 2D numpy X. Я хочу вызвать функцию с каждым элементом из T и каждым столбцом X и сохранить результат в другом массиве numpy. Функция возвращает массив numpy, который формирует столбец решения. Мой текущий, наивный, очень unpythonic реализация выглядит следующим образом:

for i in range(len(T)): 
    _u = my_func(T[i],X[:,i],p,a) 
    sol.u[:,i] = _u # The length of u is unrelated to the other variables 

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

f = np.vectorize(my_func) 
f.excluded.add(2) 
f.excluded.add(3) 
f(T,X,p,a) 

Это дает мне ошибку «IndexError: неверный индекс к скалярной переменной» где-то внутри функции. Я, очевидно, не понимаю, как работает бесчисленное вещание.

Возможно ли это, используя np.vectorize?
Или есть способ использования np.apply_along_axis?

Другая возможность, которую я вижу, - это нарезка массивов заранее и формирование списка кортежей с правильными аргументами и использование их с некоторой формой функциональности «карты».

Update: Еще одно решение я нашел:

f = lambda _t, _X: my_func(_t,_X,p,a) 
u = np.array(list(map(f, T, list(X.T)))).T 

Это похоже на работу. Но это самый эффективный способ сделать это?

Обновление 2: Вот пример функции:

def my_func(_t,_X,_p,_aux): 
    [x,y,v,lamX,lamY,lamV,tf,] = _X[:7] 

    g = _aux['const']['g'] 

    theta = -2*atan((lamX*v + sqrt(g**2*lamV**2 - 2*g*lamV*lamY*v + lamX**2*v**2 + lamY**2*v**2))/(g*lamV - lamY*v)) 
    return theta 

, где приведен пример _aux будет:

_aux = {'const': {'g':-9.81} } 

_t и _p не используются в данном случае. Он ожидает, что _X будет 7-элементным вектором. В этом случае функция возвращает только одно значение. Но могут быть случаи, когда он возвращает список. В этом случае возвращаемое значение формирует столбец на выходе. Надеюсь, что немного прояснит ситуацию.

+1

Покажите нам свою функцию. Есть хорошая вероятность, что его можно изменить, чтобы принять 2D-массив как параметр «X» и транслировать по столбцам. –

+0

Добавлена ​​функция выборки –

ответ

0

Ваш цикл for не является беспризорным. Python любит петли. :) Вы имеете в виду, скорее, что это, вероятно, не оптимальное использование numpy. Это бесполезно?

Я не уверен, что бросание его в черные ящики, такие как numexpr, vectorize или даже apply_along_axis, более бесчисленное. Идеальным является понимание проблемы и работа вокруг/внутри этой структуры, чтобы она справлялась с более крупными структурами.

Давайте попробуем образец функции (как вы должны были дать нам?):

In [77]: def myfunction(t,x,p,a): 
    print(t.shape) 
    print(x.shape) 
    print(p,a) 
    return t*x 

In [78]: f=np.vectorize(myfunction) 
In [79]: f.excluded.add(2) # so you can pass p,a 
In [80]: f.excluded.add(3) 
In [81]: T=np.arange(5) 
In [83]: X=np.ones((4,5)) 
In [85]: for i in range(T.shape[0]): 
    print(myfunction(T[i],X[:,i],{},{})) 
    ....:  
() 
(4,) 
{} {} 
[ 0. 0. 0. 0.] 
() 
(4,) 
{} {} 
[ 1. 1. 1. 1.] 
... 

In [87]: f(T,X,{},{}) 
() 
() 
{} {} 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-87-b585bb8fb6bc> in <module>() 
----> 1 f(T,X,{},{}) 
... 
/usr/lib/python3/dist-packages/numpy/lib/function_base.py in func(*vargs) 
    1566      the_args[_i] = vargs[_n] 
    1567     kwargs.update(zip(names, vargs[len(inds):])) 
-> 1568     return self.pyfunc(*the_args, **kwargs) 
    1569 
    1570    vargs = [args[_i] for _i in inds] 

<ipython-input-77-a72fc1b2ad5e> in myfunction(t, x, p, a) 
     1 def myfunction(t,x,p,a): 
----> 2  print(t.shape) 
     3  print(x.shape) 
     4  print(p,a) 
     5  return t*x 

AttributeError: 'int' object has no attribute 'shape' 

So t - это скаляр. У меня другая ошибка, но я думаю, что она согласуется с той, которую вы получили. Использует ли ваша функция t[0] где-нибудь?


Коррекция - ваш t может быть скаляром, то x, который должен быть вектором. Ваш criptic This gives me the error "IndexError: invalid index to scalar variable" from somewhere inside the function. не помог.


Это T и X вещания вместе просто отлично, например T*X работы.

Проблема с vectorize заключается в том, что она передает вашей функции кортеж скалярных значений, взятый из ваших T и X. Он предназначен для векторизации функции, которая принимает скаляры, а не скаляр и вектор.

Позволяет переопределить функцию, так что не заботится о форме или типе входов:

In [101]: def myfunction(t,x): 
    print(t) 
    print(x) 
    return t*x 
    .....: 
In [102]: f=np.vectorize(myfunction) 
In [103]: f(T,X) 
0 
1.0 
0 
1.0 
1 
... 
1.0 
Out[103]: 
array([[ 0., 1., 2., 3., 4.], 
     [ 0., 1., 2., 3., 4.], 
     [ 0., 1., 2., 3., 4.], 
     [ 0., 1., 2., 3., 4.]]) 

Даже если T является 1d и X является 2d, его прохождении 2 скаляры функции на каждой итерации ,


Но сначала позвольте мне немного отступить.

vectorize может упростить «трансляцию» значений, но это не ускоряет многое. Он по-прежнему перебирает значения, вызывая вашу функцию для каждого набора. Он не изменяет вашу функцию вообще. Это просто оболочка, точно так же как ваш цикл for.

appply_along/over_axis - также итерационная обертка. Опять не ускоряется.

Dito для выражения карты.

...

Для функции, которая принимает скаляр и вектор, и не может быть изменен внутри, ваш цикл примерно так же хорошо, как он получает. Большинство альтернатив будет сложнее получить право, быть более неясным и, вероятно, не намного быстрее.

+0

Возможно, я могу нарезать ее на кортежи и использовать что-то вроде Pool.starmap Python 3.5? Я не уверен, что это будет быстрее. Но это что-то. Спасибо за понимание. –

+1

Вот один из нескольких вопросов «многопроцессорности» (или «пула») SO: http://stackoverflow.com/questions/25888255/how-to-use-python-multiprocessing-pool-map-to-fill- NumPy-массив-в-в-петле. Я внесла свой ответ, но не эксперт по многопроцессорности. – hpaulj

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