numpy: эффективное выполнение сложной формы массива - PullRequest
2 голосов
/ 24 марта 2011

Я читаю предоставленный поставщиком большой двоичный массив в двумерный массив с нулевой переменной tempfid (M, N)

# load data
data=numpy.fromfile(file=dirname+'/fid', dtype=numpy.dtype('i4'))

# convert to complex data
fid=data[::2]+1j*data[1::2]

tempfid=fid.reshape(I*J*K, N)

, а затем мне нужно преобразовать его в массив 4D полезным4d (N, I,J, K) использование нетривиальных отображений для индексов.Я делаю это с помощью цикла for в следующих строках:

for idx in range(M):
    i=f1(idx) # f1, f2, and f3 are functions involving / and % as well as some lookups
    j=f2(idx)
    k=f3(idx)
    newfid[:,i,j,k] = tempfid[idx,:] #SLOW! CAN WE IMPROVE THIS?

Преобразование в сложное занимает 33% времени, в то время как копирование этих фрагментов M фрагментов занимает оставшиеся 66%.Вычисление индексов происходит быстро независимо от того, делаю ли я это один за другим в цикле, как показано, или путем numpy.vectorizing операции и применения ее к arange (M).

Есть ли способ ускорить это?Любая помощь по более эффективному нарезке, копированию (или нет) и т. Д. Приветствуется.

РЕДАКТИРОВАТЬ: Как выяснилось в ответе на вопрос "Какой самый быстрый способ преобразовать чередованное число NumPyмассив в комплекс64? " преобразование в комплекс может быть ускорено в 6 раз, если вместо этого используется представление:

 fid = data.astype(numpy.float32).view(numpy.complex64)

Ответы [ 2 ]

2 голосов
/ 24 марта 2011
idx = numpy.arange(M)
i = numpy.vectorize(f1)(idx)
j = numpy.vectorize(f2)(idx)
k = numpy.vectorize(f3)(idx)

# you can index arrays with other arrays
# that lets you specify this operation in one line.    
newfid[:, i,j,k] = tempfid.T

Я никогда не использовал векторизацию numpy.Векторизация просто означает, что numpy будет вызывать вашу функцию Python несколько раз.Чтобы получить скорость, вам нужно использовать операции с массивами, подобные той, что я показал здесь, и вы использовали для получения комплексных чисел.

РЕДАКТИРОВАТЬ

Проблема в том, что измерениеразмером 128 был первым в newfid, но последним в tempfid.Это легко с помощью .T, который принимает транспонирование.

2 голосов
/ 24 марта 2011

Как насчет этого. Задайте нам свои индикаторы, используя векторизованные версии f1, f2, f3 (не обязательно используя np.vectorize, но возможно просто написав функцию, которая принимает массив и возвращает массив), затем используйте np.ix_:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ix_.html

чтобы получить индексные массивы. Затем измените tempfid до той же формы, что и newfid, а затем используйте результаты np.ix_, чтобы установить значения. Например:

tempfid = np.arange(10)
i = f1(idx) # i = [4,3,2,1,0]
j = f2(idx) # j = [1,0]
ii = np.ix_(i,j)
newfid = tempfid.reshape((5,2))[ii]

Отображает элементы tempfid на новую форму с другим порядком.

...