2012-06-13 2 views
2

Мне нужно создать 2D-массив numpy из значений x, y из функции return to plot с использованием contourf из matplotlib, и до сих пор я использую «C», как структура, что это, кажется, очень неэффективен в Python:Учет списка для двух переменных цикла в Python и numpy

dim_x = np.linspace(self.min_x, self.max_x, self.step) 
    dim_y = np.linspace(self.min_y, self.max_y, self.step) 
    X, Y = np.meshgrid(dim_x, dim_y) 

    len_x = len(dim_x) 
    len_y = len(dim_y) 


    a = np.zeros([len_x, len_y], dtype=complex) 

    for i, y in enumerate(dim_y): 
     for j, x in enumerate(dim_x): 
      a[i][j] = aux_functions.final_potential(complex(x, y), element_list) 

cs = plt.contourf(X, Y, (a.real), 100) 

Как это может быть сделано в более вещий образом?

Спасибо!

+0

Что делает функция 'final_potential'? То, что вы хотите сделать, это «векторизация» этой функции, а не запись вложенных циклов. 'fromfunction' или' vectorize' хороши, но они так же неэффективны, как и ваш цикл. –

+0

Можете ли вы указать мне документацию о «векторизации» моей функции? – Ivan

+0

Прочитайте различные учебники 'numpy'. (например, http://www.tramy.us/numpybook.pdf Также см. http://scipy-lectures.github.com/) Основная идея - применить операции ко всему массиву вместо отдельных элементов. Если вы приведете пример своей функции «final_potential», мы сможем помочь вам в этом. Это обычно довольно просто, но это может быть не сразу очевидным, если вы этого еще не сделали. В некоторых случаях (например, методы с разностными разностями) это просто невозможно, но они относительно редки. –

ответ

2

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

>>> dim_x = np.linspace(0, 2, 5) 
>>> dim_y = np.linspace(0, 2, 5) 
>>> X * Y 
array([[ 0. , 0. , 0. , 0. , 0. ], 
     [ 0. , 0.25, 0.5 , 0.75, 1. ], 
     [ 0. , 0.5 , 1. , 1.5 , 2. ], 
     [ 0. , 0.75, 1.5 , 2.25, 3. ], 
     [ 0. , 1. , 2. , 3. , 4. ]]) 

Но если вы действительно не сделать это, вы могли бы также vectorize:

>>> np.vectorize(lambda x, y: x * y + 2)(X, Y) 
array([[ 2. , 2. , 2. , 2. , 2. ], 
     [ 2. , 2.25, 2.5 , 2.75, 3. ], 
     [ 2. , 2.5 , 3. , 3.5 , 4. ], 
     [ 2. , 2.75, 3.5 , 4.25, 5. ], 
     [ 2. , 3. , 4. , 5. , 6. ]]) 

В вашем случае, вероятно, будет выглядеть что-то вроде этого:

def wrapper(x, y): 
    return aux_functions.final_potential(complex(x, y), element_list) 

a = np.vectorize(wrapper)(X, Y) 

Это, вероятно, будет немного быстрее, чем вложенными for петель, хотя накладных расходов pytho n вызов функции отрицает много эффективности numpy. В тестах, которые я делал в прошлом, использование vectorize обеспечило скромный 5-кратный ускорение. (Это сравнивается с 100x или 1000x ускорением для операций с чистыми numpy, как в примере X * Y.)

1

Я не знаю, увеличит ли это производительность вообще, но есть numpy.fromfunction, который может быть использован для построения вашего массива a. Без хорошего самодостаточного примера, будет немного сложно понять, насколько отличается производительность. например сколько времени требуется для запуска aux_functions.final_potential? Если эта функция стоит дорого, неважно, насколько вы оптимизируете вокруг нее петли.

Кроме того, я бы предположил, что a[i,j] немного более эффективен, чем a[i][j], но я его не тестировал.

+0

+1 для использования от функции. Это не увеличило бы производительность, но это был не вопрос – jterrace

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