Массив 1d конвертируется с view
:
In [270]: arr = np.array([(105.0, 34.0, 145.0, 217.0)], dtype=[('a', 'f4'), ('b','f4'), ('c', 'f4'), ('d', 'f4')])
In [271]: arr
Out[271]:
array([(105., 34., 145., 217.)],
dtype=[('a', '<f4'), ('b', '<f4'), ('c', '<f4'), ('d', '<f4')])
In [272]: arr.view('<f4')
Out[272]: array([105., 34., 145., 217.], dtype=float32)
Когда мы пытаемся преобразовать отдельный элемент, мы получаем эту ошибку:
In [273]: arr[0].view('<f4')
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-273-70fbab8f61ba> in <module>()
----> 1 arr[0].view('<f4')
ValueError: Changing the dtype of a 0d array is only supported if the itemsize is unchanged
Ранее view
часто требуется настройка размеров.Я подозреваю, что с недавними изменениями в обработке структурированных массивов (наиболее очевидно при индексировании нескольких полей одновременно), эта ошибка является результатом, преднамеренно или нет.
Во всем случае массива это изменило 1d, 4массив полей в массив из 1d, 4 элементов, (1,) - (4,).Но при изменении элемента происходит переход от () к (4,).
В прошлом я рекомендовал tolist
в качестве надежного способа решения проблемы с view
(и astype
):
In [274]: arr[0].tolist()
Out[274]: (105.0, 34.0, 145.0, 217.0)
In [279]: list(arr[0].tolist())
Out[279]: [105.0, 34.0, 145.0, 217.0]
In [280]: np.array(arr[0].tolist())
Out[280]: array([105., 34., 145., 217.])
item
также является хорошим способом вытащить элемент из его крошечной структуры:
In [281]: arr[0].item()
Out[281]: (105.0, 34.0, 145.0, 217.0)
Результат от tolost
и item
- это кортеж.
Вы беспокоитесь о скорости.Но вы просто конвертируете один элемент.Одно дело беспокоиться о скорости при использовании tolist
в массиве из 1000 элементов, совсем другое - при работе с 1 элементом.
In [283]: timeit arr[0]
131 ns ± 1.31 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [284]: timeit arr[0].tolist()
1.25 µs ± 11.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [285]: timeit arr[0].item()
1.27 µs ± 2.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [286]: timeit arr.tolist()
493 ns ± 17.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [287]: timeit arr.view('f4')
1.74 µs ± 18.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Вы можете индексировать элемент способом, который не '• уменьшить размер до 0 (не то, чтобы это сильно помогало со скоростью):
In [288]: arr[[0]].view('f4')
Out[288]: array([105., 34., 145., 217.], dtype=float32)
In [289]: timeit arr[[0]].view('f4')
6.54 µs ± 15.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [290]: timeit arr[0:1].view('f4')
2.63 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [298]: timeit arr[0][None].view('f4')
4.28 µs ± 160 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
view
все еще требует изменения формы;рассмотрим большой массив:
In [299]: arrs = np.repeat(arr, 10000)
In [301]: arrs.view('f4')
Out[301]: array([105., 34., 145., ..., 34., 145., 217.], dtype=float32)
In [303]: arrs.shape
Out[303]: (10000,)
In [304]: arrs.view('f4').shape
Out[304]: (40000,)
Представление по-прежнему 1d, где, как мы, вероятно, хотели бы получить (10000,4) -образный двухмерный массив.
Лучшее изменение представления:
In [306]: arrs.view(('f4',4))
Out[306]:
array([[105., 34., 145., 217.],
[105., 34., 145., 217.],
[105., 34., 145., 217.],
...,
[105., 34., 145., 217.],
[105., 34., 145., 217.],
[105., 34., 145., 217.]], dtype=float32)
In [307]: _.shape
Out[307]: (10000, 4)
Это работает с массивом из 1 элемента, 1d или 0d:
In [308]: arr.view(('f4',4))
Out[308]: array([[105., 34., 145., 217.]], dtype=float32)
In [309]: _.shape
Out[309]: (1, 4)
In [310]: arr[0].view(('f4',4))
Out[310]: array([105., 34., 145., 217.], dtype=float32)
In [311]: _.shape
Out[311]: (4,)
Это было предложено в одном из ответов в вашей ссылке: https://stackoverflow.com/a/10171321/901925
Вопреки вашему комментарию, он работает для меня:
In [312]: arr[0].view((np.float32, len(arr.dtype.names)))
Out[312]: array([105., 34., 145., 217.], dtype=float32)
In [313]: np.__version__
Out[313]: '1.14.0'
С правкой:
In [84]: arr = np.array([(105.0, 34.0, 145.0, 217.0)], dtype=[('a', 'f4'), ('b','f4'), ('c', 'f4'), ('d', 'f4')])
In [85]: arr2 = arr[['a', 'b']]
In [86]: arr2
Out[86]:
array([(105., 34.)],
dtype={'names':['a','b'], 'formats':['<f4','<f4'], 'offsets':[0,4], 'itemsize':16})
In [87]: arr2.view(('f4',2))
...
ValueError: Changing the dtype to a subarray type is only supported if the total itemsize is unchanged
Обратите внимание, что arr2
dtype
включает offsets
значение.В последней версии NumPy изменился выбор нескольких полей.Теперь это истинное представление, сохраняющее исходные данные - все это, а не только выбранные поля.Размер элементов не изменяется:
In [93]: arr.itemsize
Out[93]: 16
In [94]: arr2.itemsize
Out[94]: 16
arr.view(('f4',4)
и arr2.view(('f4',4))
производят одно и то же.
Таким образом, вы не можете view
(изменить dtype) частичный набор полей,Вы должны сначала взять view
всего массива, а затем выбрать строки / столбцы или работать с tolist
.
Я использую 1.14.0
.В примечаниях к выпуску 1.14.1
говорится:
Изменение в 1.14.0 того, что многополевая индексация структурированных массивов возвращает представление вместо копии, было возвращено, но остается на пути к NumPy 1.15.Затронутые пользователи должны прочитать раздел «Основы / структурированные массивы / доступ к нескольким полям» в руководстве пользователя Numpy 1.14.1, чтобы узнать, как управлять этим переходом.
https://docs.scipy.org/doc/numpy-1.14.2/user/basics.rec.html#accessing-multiple-fields
Thisнаходится в стадии разработки.В этом документе упоминается функция repack_fields
, но ее пока нет.