Структурированный массив Numpy не выполняет основные операции с NumPy

1

Я хочу манипулировать именованными массивами numpy (добавлять, умножать, конкатенатировать,...)

Я определил структурированные массивы:

types=[('name1', int), ('name2', float)]
a = np.array([2, 3.3], dtype=types)
b = np.array([4, 5.35], dtype=types)

a и b создаются таким образом, что

a
array([(2, 2. ), (3, 3.3)], dtype=[('name1', '<i8'), ('name2', '<f8')])

но я действительно хочу, a['name1'] был всего 2, а не array([2, 3])

Точно так же я хочу, a['name2'] был всего 3,3

Таким образом, я мог бы суммировать c=a+b, который, как ожидается, будет массивом длины 2, где c['name1'] равно 6, а c['name2'] - 8.65

Как я могу это сделать?

Теги:
arrays
numpy

2 ответа

1
Лучший ответ

Определите структурированный массив:

In [125]: dt = np.dtype([('f0','U10'),('f1',int),('f2',float)])
In [126]: a = np.array([('one',2,3),('two',4,5.5),('three',6,7)],dt)
In [127]: a
Out[127]: 
array([('one', 2, 3. ), ('two', 4, 5.5), ('three', 6, 7. )],
      dtype=[('f0', '<U10'), ('f1', '<i8'), ('f2', '<f8')])

И массив dtype объекта с теми же данными

In [128]: A = np.array([('one',2,3),('two',4,5.5),('three',6,7)],object)
In [129]: A
Out[129]: 
array([['one', 2, 3],
       ['two', 4, 5.5],
       ['three', 6, 7]], dtype=object)

Дополнение работает, потому что оно (итеративно) делегирует действие всем элементам

In [130]: A+A
Out[130]: 
array([['oneone', 4, 6],
       ['twotwo', 8, 11.0],
       ['threethree', 12, 14]], dtype=object)

структурированное добавление не работает

In [131]: a+a
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-131-6ff992d1ddd5> in <module>()
----> 1 a+a

TypeError: ufunc 'add' did not contain a loop with signature matching types 
dtype([('f0', '<U10'), ('f1', '<i8'), ('f2', '<f8')]) dtype([('f0', '<U10'), ('f1', '<i8'), ('f2', '<f8')]) 
dtype([('f0', '<U10'), ('f1', '<i8'), ('f2', '<f8')])

Давайте попробуем поле для добавления полей:

In [132]: aa = np.zeros_like(a)
In [133]: for n in a.dtype.names: aa[n] = a[n] + a[n]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-133-68476e5d579e> in <module>()
----> 1 for n in a.dtype.names: aa[n] = a[n] + a[n]

TypeError: ufunc 'add' did not contain a loop with signature matching types 
dtype('<U10') dtype('<U10') dtype('<U10')

К сожалению, не совсем работает - строка dtype не добавлена. Но мы можем обрабатывать поле строки отдельно:

In [134]: aa['f0'] = a['f0']
In [135]: for n in a.dtype.names[1:]: aa[n] = a[n] + a[n]
In [136]: aa
Out[136]: 
array([('one',  4,  6.), ('two',  8, 11.), ('three', 12, 14.)],
      dtype=[('f0', '<U10'), ('f1', '<i8'), ('f2', '<f8')])

Или мы можем изменить строку dtype на объект:

In [137]: dt1 = np.dtype([('f0',object),('f1',int),('f2',float)])
In [138]: b = np.array([('one',2,3),('two',4,5.5),('three',6,7)],dt1)
In [139]: b
Out[139]: 
array([('one', 2, 3. ), ('two', 4, 5.5), ('three', 6, 7. )],
      dtype=[('f0', 'O'), ('f1', '<i8'), ('f2', '<f8')])
In [140]: bb = np.zeros_like(b)
In [141]: for n in a.dtype.names: bb[n] = b[n] + b[n]
In [142]: bb
Out[142]: 
array([('oneone',  4,  6.), ('twotwo',  8, 11.), ('threethree', 12, 14.)],
      dtype=[('f0', 'O'), ('f1', '<i8'), ('f2', '<f8')])

Строки Python имеют __add__, определенные как конкатенация. Ненужные строки dtype не имеют этого определения. Строки Python можно умножить на целое число, но в противном случае вызвать ошибку.

Я предполагаю, что pandas прибегают к чему-то вроде того, что я только что сделал. Я сомневаюсь, что он реализует добавление dataframe в скомпилированный код (за исключением некоторых особых случаев). Вероятно, это работает столбцом по столбцу, если разрешен dtype. Он также, похоже, свободно переключается на объект dtype (например, столбец с np.nan и строкой). Сроки могут подтвердить мое предположение (у меня нет pandas установленных на этой ОС).

  • 0
    какой отличный подробный ответ. Большое спасибо. Я не знал о возможности установить параметр dtype для np.array как «объект». Я просто надеюсь, что он не будет таким же медленным, как альтернатива пандам (что эффективно для столбчатых больших таблиц, но не так много для МНОГИХ маленьких 1-рядных объектов)
3

Согласно документации, правильный способ создания ваших массивов:

types=[('name1', int), ('name2', float)]
a = np.array([(2, 3.3)], dtype=types)
b = np.array([(4, 5.35)], dtype=types)

Который дает генерирует a и b как вы хотите:

a['name1']
array([2])

Но суммирование их не так прямо, как обычные массивы numpy, поэтому я также предлагаю использовать панды:

names=['name1','name2']
a=pd.Series([2,3.3],index=names)
b=pd.Series([4,5.35],index=names)
a+b
name1    6.00
name2    8.65
dtype: float64

Ещё вопросы

Сообщество Overcoder
Наверх
Меню