structured_arrays.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. """
  2. =================
  3. Structured Arrays
  4. =================
  5. Introduction
  6. ============
  7. Structured arrays are ndarrays whose datatype is a composition of simpler
  8. datatypes organized as a sequence of named :term:`fields <field>`. For example,
  9. ::
  10. >>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)],
  11. ... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
  12. >>> x
  13. array([('Rex', 9, 81.), ('Fido', 3, 27.)],
  14. dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
  15. Here ``x`` is a one-dimensional array of length two whose datatype is a
  16. structure with three fields: 1. A string of length 10 or less named 'name', 2.
  17. a 32-bit integer named 'age', and 3. a 32-bit float named 'weight'.
  18. If you index ``x`` at position 1 you get a structure::
  19. >>> x[1]
  20. ('Fido', 3, 27.0)
  21. You can access and modify individual fields of a structured array by indexing
  22. with the field name::
  23. >>> x['age']
  24. array([9, 3], dtype=int32)
  25. >>> x['age'] = 5
  26. >>> x
  27. array([('Rex', 5, 81.), ('Fido', 5, 27.)],
  28. dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
  29. Structured datatypes are designed to be able to mimic 'structs' in the C
  30. language, and share a similar memory layout. They are meant for interfacing with
  31. C code and for low-level manipulation of structured buffers, for example for
  32. interpreting binary blobs. For these purposes they support specialized features
  33. such as subarrays, nested datatypes, and unions, and allow control over the
  34. memory layout of the structure.
  35. Users looking to manipulate tabular data, such as stored in csv files, may find
  36. other pydata projects more suitable, such as xarray, pandas, or DataArray.
  37. These provide a high-level interface for tabular data analysis and are better
  38. optimized for that use. For instance, the C-struct-like memory layout of
  39. structured arrays in numpy can lead to poor cache behavior in comparison.
  40. .. _defining-structured-types:
  41. Structured Datatypes
  42. ====================
  43. A structured datatype can be thought of as a sequence of bytes of a certain
  44. length (the structure's :term:`itemsize`) which is interpreted as a collection
  45. of fields. Each field has a name, a datatype, and a byte offset within the
  46. structure. The datatype of a field may be any numpy datatype including other
  47. structured datatypes, and it may also be a :term:`subarray data type` which
  48. behaves like an ndarray of a specified shape. The offsets of the fields are
  49. arbitrary, and fields may even overlap. These offsets are usually determined
  50. automatically by numpy, but can also be specified.
  51. Structured Datatype Creation
  52. ----------------------------
  53. Structured datatypes may be created using the function :func:`numpy.dtype`.
  54. There are 4 alternative forms of specification which vary in flexibility and
  55. conciseness. These are further documented in the
  56. :ref:`Data Type Objects <arrays.dtypes.constructing>` reference page, and in
  57. summary they are:
  58. 1. A list of tuples, one tuple per field
  59. Each tuple has the form ``(fieldname, datatype, shape)`` where shape is
  60. optional. ``fieldname`` is a string (or tuple if titles are used, see
  61. :ref:`Field Titles <titles>` below), ``datatype`` may be any object
  62. convertible to a datatype, and ``shape`` is a tuple of integers specifying
  63. subarray shape.
  64. >>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))])
  65. dtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))])
  66. If ``fieldname`` is the empty string ``''``, the field will be given a
  67. default name of the form ``f#``, where ``#`` is the integer index of the
  68. field, counting from 0 from the left::
  69. >>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')])
  70. dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])
  71. The byte offsets of the fields within the structure and the total
  72. structure itemsize are determined automatically.
  73. 2. A string of comma-separated dtype specifications
  74. In this shorthand notation any of the :ref:`string dtype specifications
  75. <arrays.dtypes.constructing>` may be used in a string and separated by
  76. commas. The itemsize and byte offsets of the fields are determined
  77. automatically, and the field names are given the default names ``f0``,
  78. ``f1``, etc. ::
  79. >>> np.dtype('i8, f4, S3')
  80. dtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')])
  81. >>> np.dtype('3int8, float32, (2, 3)float64')
  82. dtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])
  83. 3. A dictionary of field parameter arrays
  84. This is the most flexible form of specification since it allows control
  85. over the byte-offsets of the fields and the itemsize of the structure.
  86. The dictionary has two required keys, 'names' and 'formats', and four
  87. optional keys, 'offsets', 'itemsize', 'aligned' and 'titles'. The values
  88. for 'names' and 'formats' should respectively be a list of field names and
  89. a list of dtype specifications, of the same length. The optional 'offsets'
  90. value should be a list of integer byte-offsets, one for each field within
  91. the structure. If 'offsets' is not given the offsets are determined
  92. automatically. The optional 'itemsize' value should be an integer
  93. describing the total size in bytes of the dtype, which must be large
  94. enough to contain all the fields.
  95. ::
  96. >>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})
  97. dtype([('col1', '<i4'), ('col2', '<f4')])
  98. >>> np.dtype({'names': ['col1', 'col2'],
  99. ... 'formats': ['i4', 'f4'],
  100. ... 'offsets': [0, 4],
  101. ... 'itemsize': 12})
  102. dtype({'names':['col1','col2'], 'formats':['<i4','<f4'], 'offsets':[0,4], 'itemsize':12})
  103. Offsets may be chosen such that the fields overlap, though this will mean
  104. that assigning to one field may clobber any overlapping field's data. As
  105. an exception, fields of :class:`numpy.object` type cannot overlap with
  106. other fields, because of the risk of clobbering the internal object
  107. pointer and then dereferencing it.
  108. The optional 'aligned' value can be set to ``True`` to make the automatic
  109. offset computation use aligned offsets (see :ref:`offsets-and-alignment`),
  110. as if the 'align' keyword argument of :func:`numpy.dtype` had been set to
  111. True.
  112. The optional 'titles' value should be a list of titles of the same length
  113. as 'names', see :ref:`Field Titles <titles>` below.
  114. 4. A dictionary of field names
  115. The use of this form of specification is discouraged, but documented here
  116. because older numpy code may use it. The keys of the dictionary are the
  117. field names and the values are tuples specifying type and offset::
  118. >>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)})
  119. dtype([('col1', 'i1'), ('col2', '<f4')])
  120. This form is discouraged because Python dictionaries do not preserve order
  121. in Python versions before Python 3.6, and the order of the fields in a
  122. structured dtype has meaning. :ref:`Field Titles <titles>` may be
  123. specified by using a 3-tuple, see below.
  124. Manipulating and Displaying Structured Datatypes
  125. ------------------------------------------------
  126. The list of field names of a structured datatype can be found in the ``names``
  127. attribute of the dtype object::
  128. >>> d = np.dtype([('x', 'i8'), ('y', 'f4')])
  129. >>> d.names
  130. ('x', 'y')
  131. The field names may be modified by assigning to the ``names`` attribute using a
  132. sequence of strings of the same length.
  133. The dtype object also has a dictionary-like attribute, ``fields``, whose keys
  134. are the field names (and :ref:`Field Titles <titles>`, see below) and whose
  135. values are tuples containing the dtype and byte offset of each field. ::
  136. >>> d.fields
  137. mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})
  138. Both the ``names`` and ``fields`` attributes will equal ``None`` for
  139. unstructured arrays. The recommended way to test if a dtype is structured is
  140. with `if dt.names is not None` rather than `if dt.names`, to account for dtypes
  141. with 0 fields.
  142. The string representation of a structured datatype is shown in the "list of
  143. tuples" form if possible, otherwise numpy falls back to using the more general
  144. dictionary form.
  145. .. _offsets-and-alignment:
  146. Automatic Byte Offsets and Alignment
  147. ------------------------------------
  148. Numpy uses one of two methods to automatically determine the field byte offsets
  149. and the overall itemsize of a structured datatype, depending on whether
  150. ``align=True`` was specified as a keyword argument to :func:`numpy.dtype`.
  151. By default (``align=False``), numpy will pack the fields together such that
  152. each field starts at the byte offset the previous field ended, and the fields
  153. are contiguous in memory. ::
  154. >>> def print_offsets(d):
  155. ... print("offsets:", [d.fields[name][1] for name in d.names])
  156. ... print("itemsize:", d.itemsize)
  157. >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2'))
  158. offsets: [0, 1, 2, 6, 7, 15]
  159. itemsize: 17
  160. If ``align=True`` is set, numpy will pad the structure in the same way many C
  161. compilers would pad a C-struct. Aligned structures can give a performance
  162. improvement in some cases, at the cost of increased datatype size. Padding
  163. bytes are inserted between fields such that each field's byte offset will be a
  164. multiple of that field's alignment, which is usually equal to the field's size
  165. in bytes for simple datatypes, see :c:member:`PyArray_Descr.alignment`. The
  166. structure will also have trailing padding added so that its itemsize is a
  167. multiple of the largest field's alignment. ::
  168. >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True))
  169. offsets: [0, 1, 4, 8, 16, 24]
  170. itemsize: 32
  171. Note that although almost all modern C compilers pad in this way by default,
  172. padding in C structs is C-implementation-dependent so this memory layout is not
  173. guaranteed to exactly match that of a corresponding struct in a C program. Some
  174. work may be needed, either on the numpy side or the C side, to obtain exact
  175. correspondence.
  176. If offsets were specified using the optional ``offsets`` key in the
  177. dictionary-based dtype specification, setting ``align=True`` will check that
  178. each field's offset is a multiple of its size and that the itemsize is a
  179. multiple of the largest field size, and raise an exception if not.
  180. If the offsets of the fields and itemsize of a structured array satisfy the
  181. alignment conditions, the array will have the ``ALIGNED`` :attr:`flag
  182. <numpy.ndarray.flags>` set.
  183. A convenience function :func:`numpy.lib.recfunctions.repack_fields` converts an
  184. aligned dtype or array to a packed one and vice versa. It takes either a dtype
  185. or structured ndarray as an argument, and returns a copy with fields re-packed,
  186. with or without padding bytes.
  187. .. _titles:
  188. Field Titles
  189. ------------
  190. In addition to field names, fields may also have an associated :term:`title`,
  191. an alternate name, which is sometimes used as an additional description or
  192. alias for the field. The title may be used to index an array, just like a
  193. field name.
  194. To add titles when using the list-of-tuples form of dtype specification, the
  195. field name may be specified as a tuple of two strings instead of a single
  196. string, which will be the field's title and field name respectively. For
  197. example::
  198. >>> np.dtype([(('my title', 'name'), 'f4')])
  199. dtype([(('my title', 'name'), '<f4')])
  200. When using the first form of dictionary-based specification, the titles may be
  201. supplied as an extra ``'titles'`` key as described above. When using the second
  202. (discouraged) dictionary-based specification, the title can be supplied by
  203. providing a 3-element tuple ``(datatype, offset, title)`` instead of the usual
  204. 2-element tuple::
  205. >>> np.dtype({'name': ('i4', 0, 'my title')})
  206. dtype([(('my title', 'name'), '<i4')])
  207. The ``dtype.fields`` dictionary will contain titles as keys, if any
  208. titles are used. This means effectively that a field with a title will be
  209. represented twice in the fields dictionary. The tuple values for these fields
  210. will also have a third element, the field title. Because of this, and because
  211. the ``names`` attribute preserves the field order while the ``fields``
  212. attribute may not, it is recommended to iterate through the fields of a dtype
  213. using the ``names`` attribute of the dtype, which will not list titles, as
  214. in::
  215. >>> for name in d.names:
  216. ... print(d.fields[name][:2])
  217. (dtype('int64'), 0)
  218. (dtype('float32'), 8)
  219. Union types
  220. -----------
  221. Structured datatypes are implemented in numpy to have base type
  222. :class:`numpy.void` by default, but it is possible to interpret other numpy
  223. types as structured types using the ``(base_dtype, dtype)`` form of dtype
  224. specification described in
  225. :ref:`Data Type Objects <arrays.dtypes.constructing>`. Here, ``base_dtype`` is
  226. the desired underlying dtype, and fields and flags will be copied from
  227. ``dtype``. This dtype is similar to a 'union' in C.
  228. Indexing and Assignment to Structured arrays
  229. ============================================
  230. Assigning data to a Structured Array
  231. ------------------------------------
  232. There are a number of ways to assign values to a structured array: Using python
  233. tuples, using scalar values, or using other structured arrays.
  234. Assignment from Python Native Types (Tuples)
  235. ````````````````````````````````````````````
  236. The simplest way to assign values to a structured array is using python tuples.
  237. Each assigned value should be a tuple of length equal to the number of fields
  238. in the array, and not a list or array as these will trigger numpy's
  239. broadcasting rules. The tuple's elements are assigned to the successive fields
  240. of the array, from left to right::
  241. >>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8')
  242. >>> x[1] = (7, 8, 9)
  243. >>> x
  244. array([(1, 2., 3.), (7, 8., 9.)],
  245. dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')])
  246. Assignment from Scalars
  247. ```````````````````````
  248. A scalar assigned to a structured element will be assigned to all fields. This
  249. happens when a scalar is assigned to a structured array, or when an
  250. unstructured array is assigned to a structured array::
  251. >>> x = np.zeros(2, dtype='i8, f4, ?, S1')
  252. >>> x[:] = 3
  253. >>> x
  254. array([(3, 3., True, b'3'), (3, 3., True, b'3')],
  255. dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
  256. >>> x[:] = np.arange(2)
  257. >>> x
  258. array([(0, 0., False, b'0'), (1, 1., True, b'1')],
  259. dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
  260. Structured arrays can also be assigned to unstructured arrays, but only if the
  261. structured datatype has just a single field::
  262. >>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')])
  263. >>> onefield = np.zeros(2, dtype=[('A', 'i4')])
  264. >>> nostruct = np.zeros(2, dtype='i4')
  265. >>> nostruct[:] = twofield
  266. Traceback (most recent call last):
  267. ...
  268. TypeError: Cannot cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
  269. Assignment from other Structured Arrays
  270. ```````````````````````````````````````
  271. Assignment between two structured arrays occurs as if the source elements had
  272. been converted to tuples and then assigned to the destination elements. That
  273. is, the first field of the source array is assigned to the first field of the
  274. destination array, and the second field likewise, and so on, regardless of
  275. field names. Structured arrays with a different number of fields cannot be
  276. assigned to each other. Bytes of the destination structure which are not
  277. included in any of the fields are unaffected. ::
  278. >>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])
  279. >>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])
  280. >>> b[:] = a
  281. >>> b
  282. array([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')],
  283. dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')])
  284. Assignment involving subarrays
  285. ``````````````````````````````
  286. When assigning to fields which are subarrays, the assigned value will first be
  287. broadcast to the shape of the subarray.
  288. Indexing Structured Arrays
  289. --------------------------
  290. Accessing Individual Fields
  291. ```````````````````````````
  292. Individual fields of a structured array may be accessed and modified by indexing
  293. the array with the field name. ::
  294. >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
  295. >>> x['foo']
  296. array([1, 3])
  297. >>> x['foo'] = 10
  298. >>> x
  299. array([(10, 2.), (10, 4.)],
  300. dtype=[('foo', '<i8'), ('bar', '<f4')])
  301. The resulting array is a view into the original array. It shares the same
  302. memory locations and writing to the view will modify the original array. ::
  303. >>> y = x['bar']
  304. >>> y[:] = 11
  305. >>> x
  306. array([(10, 11.), (10, 11.)],
  307. dtype=[('foo', '<i8'), ('bar', '<f4')])
  308. This view has the same dtype and itemsize as the indexed field, so it is
  309. typically a non-structured array, except in the case of nested structures.
  310. >>> y.dtype, y.shape, y.strides
  311. (dtype('float32'), (2,), (12,))
  312. If the accessed field is a subarray, the dimensions of the subarray
  313. are appended to the shape of the result::
  314. >>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])
  315. >>> x['a'].shape
  316. (2, 2)
  317. >>> x['b'].shape
  318. (2, 2, 3, 3)
  319. Accessing Multiple Fields
  320. ```````````````````````````
  321. One can index and assign to a structured array with a multi-field index, where
  322. the index is a list of field names.
  323. .. warning::
  324. The behavior of multi-field indexes changed from Numpy 1.15 to Numpy 1.16.
  325. The result of indexing with a multi-field index is a view into the original
  326. array, as follows::
  327. >>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])
  328. >>> a[['a', 'c']]
  329. array([(0, 0.), (0, 0.), (0, 0.)],
  330. dtype={'names':['a','c'], 'formats':['<i4','<f4'], 'offsets':[0,8], 'itemsize':12})
  331. Assignment to the view modifies the original array. The view's fields will be
  332. in the order they were indexed. Note that unlike for single-field indexing, the
  333. dtype of the view has the same itemsize as the original array, and has fields
  334. at the same offsets as in the original array, and unindexed fields are merely
  335. missing.
  336. .. warning::
  337. In Numpy 1.15, indexing an array with a multi-field index returned a copy of
  338. the result above, but with fields packed together in memory as if
  339. passed through :func:`numpy.lib.recfunctions.repack_fields`.
  340. The new behavior as of Numpy 1.16 leads to extra "padding" bytes at the
  341. location of unindexed fields compared to 1.15. You will need to update any
  342. code which depends on the data having a "packed" layout. For instance code
  343. such as::
  344. >>> a[['a', 'c']].view('i8') # Fails in Numpy 1.16
  345. Traceback (most recent call last):
  346. File "<stdin>", line 1, in <module>
  347. ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype
  348. will need to be changed. This code has raised a ``FutureWarning`` since
  349. Numpy 1.12, and similar code has raised ``FutureWarning`` since 1.7.
  350. In 1.16 a number of functions have been introduced in the
  351. :mod:`numpy.lib.recfunctions` module to help users account for this
  352. change. These are
  353. :func:`numpy.lib.recfunctions.repack_fields`.
  354. :func:`numpy.lib.recfunctions.structured_to_unstructured`,
  355. :func:`numpy.lib.recfunctions.unstructured_to_structured`,
  356. :func:`numpy.lib.recfunctions.apply_along_fields`,
  357. :func:`numpy.lib.recfunctions.assign_fields_by_name`, and
  358. :func:`numpy.lib.recfunctions.require_fields`.
  359. The function :func:`numpy.lib.recfunctions.repack_fields` can always be
  360. used to reproduce the old behavior, as it will return a packed copy of the
  361. structured array. The code above, for example, can be replaced with:
  362. >>> from numpy.lib.recfunctions import repack_fields
  363. >>> repack_fields(a[['a', 'c']]).view('i8') # supported in 1.16
  364. array([0, 0, 0])
  365. Furthermore, numpy now provides a new function
  366. :func:`numpy.lib.recfunctions.structured_to_unstructured` which is a safer
  367. and more efficient alternative for users who wish to convert structured
  368. arrays to unstructured arrays, as the view above is often indeded to do.
  369. This function allows safe conversion to an unstructured type taking into
  370. account padding, often avoids a copy, and also casts the datatypes
  371. as needed, unlike the view. Code such as:
  372. >>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
  373. >>> b[['x', 'z']].view('f4')
  374. array([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
  375. can be made safer by replacing with:
  376. >>> from numpy.lib.recfunctions import structured_to_unstructured
  377. >>> structured_to_unstructured(b[['x', 'z']])
  378. array([0, 0, 0])
  379. Assignment to an array with a multi-field index modifies the original array::
  380. >>> a[['a', 'c']] = (2, 3)
  381. >>> a
  382. array([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)],
  383. dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])
  384. This obeys the structured array assignment rules described above. For example,
  385. this means that one can swap the values of two fields using appropriate
  386. multi-field indexes::
  387. >>> a[['a', 'c']] = a[['c', 'a']]
  388. Indexing with an Integer to get a Structured Scalar
  389. ```````````````````````````````````````````````````
  390. Indexing a single element of a structured array (with an integer index) returns
  391. a structured scalar::
  392. >>> x = np.array([(1, 2., 3.)], dtype='i, f, f')
  393. >>> scalar = x[0]
  394. >>> scalar
  395. (1, 2., 3.)
  396. >>> type(scalar)
  397. <class 'numpy.void'>
  398. Unlike other numpy scalars, structured scalars are mutable and act like views
  399. into the original array, such that modifying the scalar will modify the
  400. original array. Structured scalars also support access and assignment by field
  401. name::
  402. >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
  403. >>> s = x[0]
  404. >>> s['bar'] = 100
  405. >>> x
  406. array([(1, 100.), (3, 4.)],
  407. dtype=[('foo', '<i8'), ('bar', '<f4')])
  408. Similarly to tuples, structured scalars can also be indexed with an integer::
  409. >>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0]
  410. >>> scalar[0]
  411. 1
  412. >>> scalar[1] = 4
  413. Thus, tuples might be thought of as the native Python equivalent to numpy's
  414. structured types, much like native python integers are the equivalent to
  415. numpy's integer types. Structured scalars may be converted to a tuple by
  416. calling :func:`ndarray.item`::
  417. >>> scalar.item(), type(scalar.item())
  418. ((1, 4.0, 3.0), <class 'tuple'>)
  419. Viewing Structured Arrays Containing Objects
  420. --------------------------------------------
  421. In order to prevent clobbering object pointers in fields of
  422. :class:`numpy.object` type, numpy currently does not allow views of structured
  423. arrays containing objects.
  424. Structure Comparison
  425. --------------------
  426. If the dtypes of two void structured arrays are equal, testing the equality of
  427. the arrays will result in a boolean array with the dimensions of the original
  428. arrays, with elements set to ``True`` where all fields of the corresponding
  429. structures are equal. Structured dtypes are equal if the field names,
  430. dtypes and titles are the same, ignoring endianness, and the fields are in
  431. the same order::
  432. >>> a = np.zeros(2, dtype=[('a', 'i4'), ('b', 'i4')])
  433. >>> b = np.ones(2, dtype=[('a', 'i4'), ('b', 'i4')])
  434. >>> a == b
  435. array([False, False])
  436. Currently, if the dtypes of two void structured arrays are not equivalent the
  437. comparison fails, returning the scalar value ``False``. This behavior is
  438. deprecated as of numpy 1.10 and will raise an error or perform elementwise
  439. comparison in the future.
  440. The ``<`` and ``>`` operators always return ``False`` when comparing void
  441. structured arrays, and arithmetic and bitwise operations are not supported.
  442. Record Arrays
  443. =============
  444. As an optional convenience numpy provides an ndarray subclass,
  445. :class:`numpy.recarray`, and associated helper functions in the
  446. :mod:`numpy.rec` submodule, that allows access to fields of structured arrays
  447. by attribute instead of only by index. Record arrays also use a special
  448. datatype, :class:`numpy.record`, that allows field access by attribute on the
  449. structured scalars obtained from the array.
  450. The simplest way to create a record array is with :func:`numpy.rec.array`::
  451. >>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., "World")],
  452. ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])
  453. >>> recordarr.bar
  454. array([ 2., 3.], dtype=float32)
  455. >>> recordarr[1:2]
  456. rec.array([(2, 3., b'World')],
  457. dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])
  458. >>> recordarr[1:2].foo
  459. array([2], dtype=int32)
  460. >>> recordarr.foo[1:2]
  461. array([2], dtype=int32)
  462. >>> recordarr[1].baz
  463. b'World'
  464. :func:`numpy.rec.array` can convert a wide variety of arguments into record
  465. arrays, including structured arrays::
  466. >>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
  467. ... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])
  468. >>> recordarr = np.rec.array(arr)
  469. The :mod:`numpy.rec` module provides a number of other convenience functions for
  470. creating record arrays, see :ref:`record array creation routines
  471. <routines.array-creation.rec>`.
  472. A record array representation of a structured array can be obtained using the
  473. appropriate `view <numpy-ndarray-view>`_::
  474. >>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
  475. ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'a10')])
  476. >>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)),
  477. ... type=np.recarray)
  478. For convenience, viewing an ndarray as type :class:`np.recarray` will
  479. automatically convert to :class:`np.record` datatype, so the dtype can be left
  480. out of the view::
  481. >>> recordarr = arr.view(np.recarray)
  482. >>> recordarr.dtype
  483. dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))
  484. To get back to a plain ndarray both the dtype and type must be reset. The
  485. following view does so, taking into account the unusual case that the
  486. recordarr was not a structured type::
  487. >>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)
  488. Record array fields accessed by index or by attribute are returned as a record
  489. array if the field has a structured type but as a plain ndarray otherwise. ::
  490. >>> recordarr = np.rec.array([('Hello', (1, 2)), ("World", (3, 4))],
  491. ... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])])
  492. >>> type(recordarr.foo)
  493. <class 'numpy.ndarray'>
  494. >>> type(recordarr.bar)
  495. <class 'numpy.recarray'>
  496. Note that if a field has the same name as an ndarray attribute, the ndarray
  497. attribute takes precedence. Such fields will be inaccessible by attribute but
  498. will still be accessible by index.
  499. """