поэлементная сумма структурированных массивов в numpy - PullRequest
0 голосов
/ 04 февраля 2019

Интересно, можно ли вообще выполнять поэлементную сумму (или другие операции) двух структурированных числовых массивов одинаковой формы.

arr1 = np.array([[1,2,3],[2,3,4]], dtype=[("x", "f8"),("y", "f8")])
arr2 = np.array([[5,4,3],[9,6,4]], dtype=[("x", "f8"),("y", "f8")])
arr3 = np.sum(arr1, arr2)

говорит, что "ufunc 'add' не содержалцикл с типами совпадения сигнатур dtype ([('x', '

Если это невозможно, будет здорово понять, почему это невозможно или нецелесообразно реализовать в numpy.

1 Ответ

0 голосов
/ 04 февраля 2019

С вашим массивом:

In [236]: arr1 = np.array([[1,2,3],[2,3,4]], dtype=[("x", "f8"),("y", "f8")])
In [237]: arr1
Out[237]: 
array([[(1., 1.), (2., 2.), (3., 3.)],
       [(2., 2.), (3., 3.), (4., 4.)]], dtype=[('x', '<f8'), ('y', '<f8')])
In [238]: arr1['x']
Out[238]: 
array([[1., 2., 3.],
       [2., 3., 4.]])

Обычно данные для структурированного массива предоставляются в виде списка (списков) кортежей. Как и в Out[237].Без кортежей np.array присваивает одинаковые значения обоим полям.

Вы должны выполнять математику для каждого поля в отдельности:

In [239]: arr1['y'] *= 10
In [240]: arr1
Out[240]: 
array([[(1., 10.), (2., 20.), (3., 30.)],
       [(2., 20.), (3., 30.), (4., 40.)]],
      dtype=[('x', '<f8'), ('y', '<f8')])

Математические операции определены для простых dtypes, таких как intи float и использует, где это возможно, скомпилированный код.

Эта ошибка означает, что add ufunc не был определен для этого составного dtype.И я думаю, что это верно для всех составных dtypes.

In [242]: arr1 + arr1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-242-345397c600ce> in <module>()
----> 1 arr1 + arr1

TypeError: ufunc 'add' did not contain a loop with signature matching types dtype([('x', '<f8'), ('y', '<f8')]) dtype([('x', '<f8'), ('y', '<f8')]) dtype([('x', '<f8'), ('y', '<f8')])

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

In [243]: dt2 = np.dtype([('xy', 'f8', 2)])
In [244]: arr2 = arr1.view(dt2)
In [245]: arr2
Out[245]: 
array([[([ 1., 10.],), ([ 2., 20.],), ([ 3., 30.],)],
       [([ 2., 20.],), ([ 3., 30.],), ([ 4., 40.],)]],
      dtype=[('xy', '<f8', (2,))])
In [246]: arr2['xy']
Out[246]: 
array([[[ 1., 10.],
        [ 2., 20.],
        [ 3., 30.]],

       [[ 2., 20.],
        [ 3., 30.],
        [ 4., 40.]]])

Математика для этого поля будет видна в исходном массиве:

In [247]: arr2['xy'] += .1
In [248]: arr2
Out[248]: 
array([[([ 1.1, 10.1],), ([ 2.1, 20.1],), ([ 3.1, 30.1],)],
       [([ 2.1, 20.1],), ([ 3.1, 30.1],), ([ 4.1, 40.1],)]],
      dtype=[('xy', '<f8', (2,))])
In [249]: arr1
Out[249]: 
array([[(1.1, 10.1), (2.1, 20.1), (3.1, 30.1)],
       [(2.1, 20.1), (3.1, 30.1), (4.1, 40.1)]],
      dtype=[('x', '<f8'), ('y', '<f8')])

Мы также можем view это как простой dtype, но нам нужно будет изменить форму:

In [250]: arr3 = arr1.view('f8')
In [251]: arr3
Out[251]: 
array([[ 1.1, 10.1,  2.1, 20.1,  3.1, 30.1],
       [ 2.1, 20.1,  3.1, 30.1,  4.1, 40.1]])
In [252]: arr3.reshape(2,3,2)
Out[252]: 
array([[[ 1.1, 10.1],
        [ 2.1, 20.1],
        [ 3.1, 30.1]],

       [[ 2.1, 20.1],
        [ 3.1, 30.1],
        [ 4.1, 40.1]]])
...