помогите мне устранить цикл for в python - PullRequest
0 голосов
/ 31 июля 2009

Должен быть более быстрый способ сделать это.

Здесь много чего происходит, но распаковать довольно просто.

Вот соответствующий код Python (из импорта scipy *)

for i in arange(len(wav)):
    result[i] = sum(laser_flux * exp(-(wav[i] - laser_wav)**2) )

Есть множество массивов.

  • результат - массив длины (wav)
  • laser_flux - массив длины (лазер)
  • wav - массив длины (wav)
  • laser_wav - массив длины (лазер)

Да, в пределах экспоненты я возводю в квадрат (элемент за элементом) разницу между скалярным значением и массивом laser_wav.

Все работает, как и ожидалось (включая МЕДЛЕННО), любая помощь, которую вы можете дать мне, чтобы устранить этот цикл for, будет принята с благодарностью!

Ответы [ 4 ]

13 голосов
/ 31 июля 2009

Вы захотите использовать массивы Numpy (если вы этого еще не сделали) для хранения ваших данных. Затем вы можете воспользоваться вещанием массива с np.newaxis. Для каждого значения в wav вы хотите вычислить разницу между этим значением и каждым значением в laser_wav. Это говорит о том, что вам понадобится двумерный массив с двумя измерениями: wav и laser.

В приведенном ниже примере я выберу первый индекс как индекс laser, а второй индекс как индекс wav. С примерами данных это становится:

import numpy as np

LASER_LEN  = 5
WAV_LEN    = 10
laser_flux = np.arange(LASER_LEN)
wav        = np.arange(WAV_LEN)
laser_wav  = np.array(LASER_LEN)

# Tile wav into LASER_LEN rows and tile laser_wav into WAV_LEN columns
diff    = wav[np.newaxis,:] - laser_wav[:,np.newaxis]
exp_arg = -diff ** 2
sum_arg = laser_flux[:,np.newaxis] * np.exp(exp_arg)

# Now, the resulting array sum_arg should be of size (LASER_LEN,WAV_LEN)
# Since your original sum was along each element of laser_flux/laser_wav, 
# you'll need to sum along the first axis.
result = np.sum(sum_arg, axis=0)

Конечно, вы можете просто сжать это в одно утверждение:

result = np.sum(laser_flux[:,np.newaxis] * 
                np.exp(-(wav[np.newaxis,:]-laser_wav[:,np.newaxis])**2),axis=0)

Edit:

Как отмечено в комментариях к вопросу, вы можете воспользоваться «суммой умножений», присущей определению умножений в стиле линейной алгебры. Это становится:

result = np.dot(laser_flux, 
    np.exp(-(wav[np.newaxis,:] - laser_wav[:,np.newaxis])**2))
2 голосов
/ 31 июля 2009

Я новичок в Python, поэтому, возможно, это не самый оптимальный в Python , но я бы использовал ту же технику для Perl, Scheme и т. Д.

def func(x):
    delta = x - laser_wav
    return sum(laser_flux * exp(-delta * delta))
result = map(func, wav)
1 голос
/ 31 июля 2009

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

from multiprocessing import Pool
p = Pool(5) # about the number of cores you have

def f(i):
    delta = wav[i] - laser_wav
    return sum(laser_flux * exp(-delta*delta) )

result = p.map(f, arange(len(wav)) )
0 голосов
/ 31 июля 2009

Во-первых, кажется, что умножить переменную на себя немного быстрее, чем использовать оператор мощности **:

~$ python -m timeit -n 100000 -v "x = 4.1; x * x"
raw times: 0.0904 0.0513 0.0493
100000 loops, best of 3: 0.493 usec per loop
~$ python -m timeit -n 100000 -v "x = 4.1; x**2"
raw times: 0.101 0.147 0.118
100000 loops, best of 3: 1.01 usec per loop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...