In [161]: a = np.zeros(3, dtype={'names':['A','B','C'], 'formats':['int','int','
...: float']})
...: for i in range(len(a)):
...: a[i] = i
...:
In [162]: a
Out[162]:
array([(0, 0, 0.), (1, 1, 1.), (2, 2, 2.)],
dtype=[('A', '<i8'), ('B', '<i8'), ('C', '<f8')])
определить новый тип dtype:
In [164]: a.dtype.descr
Out[164]: [('A', '<i8'), ('B', '<i8'), ('C', '<f8')]
In [165]: a.dtype.descr+[('test','O')]
Out[165]: [('A', '<i8'), ('B', '<i8'), ('C', '<f8'), ('test', 'O')]
In [166]: dt= a.dtype.descr+[('test','O')]
новый массив нужного размера и dtype:
In [167]: b = np.empty(a.shape, dt)
копировать значения из a
в b
по имени поля:
In [168]: for name in a.dtype.names:
...: b[name] = a[name]
...:
In [169]: b
Out[169]:
array([(0, 0, 0., None), (1, 1, 1., None), (2, 2, 2., None)],
dtype=[('A', '<i8'), ('B', '<i8'), ('C', '<f8'), ('test', 'O')])
Многие из функций rf
делают это поле копией поля:
rf.recursive_fill_fields(a,b)
rf.append_fields
использует это после инициализации массива output
.
В более ранних версиях мультипольный индекс создавал копию, поэтому выражения вроде b[list(a.dtype.names)] = a
не работали бы.
Я не знаю, стоит ли пытаться выяснить, что делает rf.append_fields
. Эти функции несколько устарели и мало используются (обратите внимание на специальный импорт). Поэтому вполне вероятно, что у них есть ошибки или крайние случаи, которые не работают. Функции, которые я исследовал, работают так же, как я продемонстрировал, - создают новый тип d, массив результатов и копируют данные по имени поля.
В последних выпусках произошли изменения в доступе к нескольким полям. В recfunctions
появилось несколько новых функций, облегчающих работу со структурированными массивами, таких как repack_fields
.
.
https://docs.scipy.org/doc/numpy/user/basics.rec.html#accessing-multiple-fields
Я не знаю, относится ли это к проблеме append_fields
. Я также вижу раздел о структурированных массивах с объектами, но я этого не изучал:
https://docs.scipy.org/doc/numpy/user/basics.rec.html#viewing-structured-arrays-containing-objects
В целях предотвращения удушения указателей объектов в полях типа numpy.object, в настоящее время numpy не позволяет просматривать структурированные массивы, содержащие объекты.
Эта строка, по-видимому, относится к использованию метода view
. Представления, созданные с помощью индексации полей, будь то одно имя или несколько полей, не затрагиваются.
Ошибка в append_fields
исходит из этой операции:
In [183]: data = np.array([None,None,None])
In [184]: data
Out[184]: array([None, None, None], dtype=object)
In [185]: data.view([('test',object)])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-185-c46c4464b53c> in <module>
----> 1 data.view([('test',object)])
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
Нет проблем при создании составного dtype с объектными dtypes:
In [186]: np.array([None,None,None], dtype=[('test',object)])
Out[186]: array([(None,), (None,), (None,)], dtype=[('test', 'O')])
Но я не вижу ни одного recfunctions
, способного объединить a
и data
.
view
может использоваться для изменения имен полей a
:
In [219]: a.view([('AA',int),('BB',int),('cc',float)])
Out[219]:
array([(0, 0, 0.), (1, 1, 1.), (2, 2, 2.)],
dtype=[('AA', '<i8'), ('BB', '<i8'), ('cc', '<f8')])
, но попытка сделать это для b
не удалась по той же причине:
In [220]: b.view([('AA',int),('BB',int),('cc',float),('d',object)])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-220-ab0a6e4dd57f> in <module>
----> 1 b.view([('AA',int),('BB',int),('cc',float),('d',object)])
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
Я начинаю с массива dtype объекта и пытаюсь view
с i8
(dtype того же размера), я получаю ту же ошибку. Таким образом, ограничение на view
объекта dtype не ограничивается структурированными массивами. Необходимость такого ограничения в случае указателя объекта на i8
имеет смысл. Необходимость такого ограничения в случае встраивания указателя объекта в составной тип d не может быть столь убедительной. Это может быть даже излишним, или просто случай, когда вы играете безопасно и просто.
In [267]: x.dtype
Out[267]: dtype('O')
In [268]: x.shape
Out[268]: (3,)
In [269]: x.dtype.itemsize
Out[269]: 8
In [270]: x.view('i8')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-270-30c78b13cd10> in <module>
----> 1 x.view('i8')
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
Обратите внимание, что тест в строке 493 проверяет свойство hasobject
как нового, так и старого dtypes. Более детальный тест может проверить, оба ли hasobject
, но я подозреваю, что логика может быть довольно сложной. Иногда простой запрет безопаснее (и проще) сложного набора тестов.
В дальнейшем тестировании
In [283]: rf.structured_to_unstructured(a)
Out[283]:
array([[ 3., 3., 0.],
[12., 10., 1.],
[ 2., 2., 2.]])
, но попытка сделать то же самое на b
, или даже на подмножестве его полей, приводит к знакомой ошибке:
rf.structured_to_unstructured(b)
rf.structured_to_unstructured(b[['A','B','C']])
Сначала я должен использовать repack
, чтобы сделать копию без объекта:
rf.structured_to_unstructured(rf.repack_fields(b[['A','B','C']]))