4

Мне нужно создать 2D-массив, в котором каждая строка может начинаться и заканчиваться другим числом. Предположим, что первый и последний элемент каждой строки заданы, а все остальные элементы просто интерполируются в соответствии с длиной строк. В простом случае предположим, что я хочу создать массив 3X3 с тем же стартом в 0, но с другим концом, заданным W ниже:Векторизованное пространство NumPy для нескольких значений начала и остановки

array([[ 0., 1., 2.], 
     [ 0., 2., 4.], 
     [ 0., 3., 6.]]) 

есть ли лучший способ сделать это, чем следующее:

D=np.ones((3,3))*np.arange(0,3) 
D=D/D[:,-1] 
W=np.array([2,4,6]) # last element of each row assumed given 
Res= (D.T*W).T 
+1

Если вы хотите использовать pandas: 'pd.Series (W) .apply (lambda e: np.linspace (0, e, 3))' – Boud

+0

В принципе у вас есть два вектора (первый и последний столбцы вашей матрицы) , верный? И тогда вы хотели бы интерполировать некоторые значения для каждой строки. – Kartik

+1

@dayum, если вы хотите изменить начальные позиции, это тот же подход, но вы создаете df с двумя векторами, начинаете и останавливаетесь в нем, и вы вызываете снова применение с аргументом лямбда: df.start, df.end, 3 – Boud

ответ

4

Вот подход, использующий broadcasting -

def create_ranges(start, stop, N, endpoint=True): 
    if endpoint==1: 
     divisor = N-1 
    else: 
     divisor = N 
    steps = (1.0/divisor) * (stop - start) 
    return steps[:,None]*np.arange(N) + start[:,None] 

SAMPL е пробег -

In [22]: # Setup start, stop for each row and no. of elems in each row 
    ...: start = np.array([1,4,2]) 
    ...: stop = np.array([6,7,6]) 
    ...: N = 5 
    ...: 

In [23]: create_ranges(start, stop, 5) 
Out[23]: 
array([[ 1. , 2.25, 3.5 , 4.75, 6. ], 
     [ 4. , 4.75, 5.5 , 6.25, 7. ], 
     [ 2. , 3. , 4. , 5. , 6. ]]) 

In [24]: create_ranges(start, stop, 5, endpoint=False) 
Out[24]: 
array([[ 1. , 2. , 3. , 4. , 5. ], 
     [ 4. , 4.6, 5.2, 5.8, 6.4], 
     [ 2. , 2.8, 3.6, 4.4, 5.2]]) 
+0

Почему бы не использовать 'linspace'? – Boud

+0

@Boud Я не уверен, это работает на '2D'? – Divakar

+0

@Divakar Я имел в виду что-то вроде [этого] (http://stackoverflow.com/a/16887295/624829) – Boud

1

Как это использование Ора о linspace предполагает старт 0 для всех строк.

x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2) 

(редактирование - это транспонированная то, что я должен получить, либо перенести его или переключить использование [:,None])

Для N = 3000, это заметно быстрее, чем @Divaker's решения. Я не совсем понимаю, почему.

In [132]: timeit N=3000;x=np.linspace(0,1,N)[:,None]*np.arange(0,2*N,2) 
10 loops, best of 3: 91.7 ms per loop 
In [133]: timeit create_ranges(np.zeros(N),np.arange(0,2*N,2),N) 
1 loop, best of 3: 197 ms per loop 
In [134]: def foo(N): 
    ...:  D=np.ones((N,N))*np.arange(N) 
    ...:  D=D/D[:,-1] 
    ...:  W=np.arange(0,2*N,2) 
    ...:  return (D.T*W).T 
    ...: 
In [135]: timeit foo(3000) 
1 loop, best of 3: 454 ms per loop 

============

С начала и остановки я мог бы использовать:

In [201]: starts=np.array([1,4,2]); stops=np.array([6,7,8]) 
In [202]: x=(np.linspace(0,1,5)[:,None]*(stops-starts)+starts).T 
In [203]: x 
Out[203]: 
array([[ 1. , 2.25, 3.5 , 4.75, 6. ], 
     [ 4. , 4.75, 5.5 , 6.25, 7. ], 
     [ 2. , 3.5 , 5. , 6.5 , 8. ]]) 

С дополнительных вычислений, что делает его немного медленнее, чем create_ranges ,

In [208]: timeit N=3000;starts=np.zeros(N);stops=np.arange(0,2*N,2);x=(np.linspace(0,1,N)[:,None]*(stops-starts)+starts).T 
1 loop, best of 3: 227 ms per loop 

Все эти решения являются лишь вариации идея сделать линейной интерполяции между starts и stops.

+0

Поскольку в вопросе говорится, что «первый и последний элемент каждой строки задан», как бы вы включали значения начала и завершения для каждой строки в «основанное на linspace» решение? – Divakar

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