2015-09-14 6 views
4

Учитывая список углов поворота (позволяет говорить о оси X):Что такое правильный способ создать Numpy массив преобразования матриц

import numpy as np 
x_axis_rotations = np.radians([0,10,32,44,165]) 

Я могу создать массив матриц, соответствующие эти углы, делая так:

matrices = [] 
for angle in x_axis_rotations: 
    matrices.append(np.asarray([[1 , 0 , 0],[0, np.cos(angle), -np.sin(angle)], [0, np.sin(angle), np.cos(angle)]])) 
matrices = np.array(matrices) 

Это будет работать, но он не использует сильный Numpy для работы с большими массивами ... так что, если мой массив углов в миллионах, делая это таким образом, не будет очень быстро.

Есть ли лучший (более быстрый) способ создания массива матриц преобразования из массива входов?

+0

Так что, если я правильно понимаю, вы хотите 3D-массив? Откуда поступает вход? Файл или что-то, что вы генерируете во время выполнения? – ventsyv

+1

Не могли бы вы объяснить, почему вы хотите хранить эти матрицы, а не вычислять их при их использовании? – Simpom

+0

@Simpom Я хочу реализовать технику «точка-треугольник», описанную в [этой статье] (http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.479.8237&rep=rep1&type=pdf). Идея состоит в том, что путем предварительной вычисления матрицы преобразования для каждого треугольника сетки становится возможным уменьшить 3D-расстояние от задачи к точкам треугольника до более простой двумерной, которая может быть рассчитана быстрее, чем при выполнении барицентрического вычисления. Если все, что я хочу, это одноточечный запрос, то да, нет необходимости вычислять матрицы. Но если у меня есть миллион точек для запроса, это должно оказаться полезным. – Fnord

ответ

3

Вот прямой и простой подход:

c = np.cos(x_axis_rotations) 
s = np.sin(x_axis_rotations) 
matrices = np.zeros((len(x_axis_rotations), 3, 3)) 
matrices[:, 0, 0] = 1 
matrices[:, 1, 1] = c 
matrices[:, 1, 2] = -s 
matrices[:, 2, 1] = s 
matrices[:, 2, 2] = c 

тайминги, для любопытных:

In [30]: angles = 2 * np.pi * np.random.rand(1000) 

In [31]: timeit OP(angles) 
100 loops, best of 3: 5.46 ms per loop 

In [32]: timeit askewchan(angles) 
10000 loops, best of 3: 39.6 µs per loop 

In [33]: timeit divakar(angles) 
10000 loops, best of 3: 93.8 µs per loop 

In [34]: timeit divakar_oneline(angles) 
10000 loops, best of 3: 56.1 µs per loop 

In [35]: timeit divakar_combine(angles) 
10000 loops, best of 3: 43.9 µs per loop 

Все намного быстрее, чем ваш цикл, так что используйте любые понравившиеся вам нравится больше всего :)

+0

Простой действительно, приятно! – Divakar

+0

Приятный и лаконичный! Благодаря! – Fnord

2

Вы можете использовать linear indexing, чтобы помочь, как так -

# Get cosine and sine values in one-go 
cosv = np.cos(x_axis_rotations) 
sinv = np.sin(x_axis_rotations) 

# Get size parameter 
N = x_axis_rotations.size 

# Initialize output array 
out = np.zeros((N,3,3)) 

# Set the first element in each 3D slice as 1 
out[:,0,0] = 1 

# Calculate the first of positions where cosine valued elements are to be put 
idx1 = 4 + 9*np.arange(N)[:,None] 

# One by one put those 4 values in 2x2 blocks across all 3D slices 
out.ravel()[idx1] = cosv 
out.ravel()[idx1+1] = -sinv 

out.ravel()[idx1+3] = sinv 
out.ravel()[idx1+4] = cosv 

В качестве альтернативы, вы можете установить элементы в одном ходу после того, как вы настроите выходной массив с zeros и установить первый элемент в каждом срезе а 1, как так -

out.reshape(N,-1)[:,[4,5,7,8]] = np.column_stack((cosv,-sinv,sinv,cosv)) 

между вышеназванными двумя подходами, еще два Middleground подходы могут развиваться, снова ставить сразу после инициализации ш Ith нули и установки первого элемента в каждом 3D срез, как 1, как так -

out.reshape(N,-1)[:,[4,8]] = cosv[:,None] 
out.reshape(N,-1)[:,[5,7]] = np.column_stack((-sinv[:,None],sinv[:,None])) 

Последняя будет -

out.reshape(N,-1)[:,[4,8]] = cosv[:,None] 
out.reshape(N,-1)[:,5] = -sinv 
out.reshape(N,-1)[:,7] = sinv 
+0

Мне нравится элегантность этих ответов, но я думаю, что индексирование просто замедляет его. – askewchan

+0

@askewchan Ну, я боюсь, что column_stacks, как известно, медленны. Было бы неплохо, я думаю, что все это время. – Divakar

+0

Ваше последнее решение не должно иметь новых осей для двух последних строк, так как срез на LHS имеет только одно измерение. – askewchan

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