CoolFace
Datasetpublic

enigmare/v2-crawler

sourceHugging Faceupdated 28d agoView on Hugging Face
1likes889downloads
numpy_org.jsonl20 linesDownload Raw Back to documentation
1{"id":"doc-numpy_user_guide_numpy_v2_5_manual-64e32ea9","source":"documentation","title":"NumPy user guide — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy user guide# This guide is an overview and explains the important features; details are found in NumPy reference. Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs previous NumPy documentation next What is NumPy?\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.943Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":353}}2{"id":"doc-what_is_numpy_numpy_v2_5_manual-da7a8631","source":"documentation","title":"What is NumPy? — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/whatisnumpy.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide What is NumPy? What is NumPy?# NumPy is the fundamental package for scientific computing in Python. It is a Python library that provides a multidimensional array object, various derived objects (such as masked arrays and matrices), and an assortment of routines for fast operations on arrays, including mathematical, logical, shape manipulation, sorting, selecting, I/O, discrete Fourier transforms, basic linear algebra, basic statistical operations, random simulation and much more. At the core of the NumPy package, is the ndarray object. This encapsulates n-dimensional arrays of homogeneous data types, with many operations being performed in compiled code for performance. There are several important differences between NumPy arrays and the standard Python arrays have a fixed size at creation, unlike Python lists (which can grow dynamically). Changing the size of an ndarray will create a new array and delete the original. The elements in a NumPy array are all required to be of the same data type, and thus will be the same size in memory. The can have arrays of (Python, including NumPy) objects, thereby allowing for arrays of different sized elements. NumPy arrays facilitate advanced mathematical and other types of operations on large numbers of data. Typically, such operations are executed more efficiently and with less code than is possible using Python’s built-in sequences. A growing plethora of scientific and mathematical Python-based packages are using NumPy arrays; though these typically support Python-sequence input, they convert such input to NumPy arrays prior to processing, and they often output NumPy arrays. In other words, in order to efficiently use much (perhaps even most) of today’s scientific/mathematical Python-based software, just knowing how to use Python’s built-in sequence types is insufficient - one also needs to know how to use NumPy arrays. The points about sequence size and speed are particularly important in scientific computing. As a simple example, consider the case of multiplying each element in a 1-D sequence with the corresponding element in another sequence of the same length. If the data are stored in two Python lists, a and b, we could iterate over each = [] for i in range(len(a)): c.append(a[i]*b[i]) This produces the correct answer, but if a and b each contain millions of numbers, we will pay the price for the inefficiencies of looping in Python. We could accomplish the same task much more quickly in C by writing (for clarity we neglect variable declarations and initializations, memory allocation, etc.) for (i = 0; i < rows; i++) { c[i] = a[i]*b[i]; } This saves all the overhead involved in interpreting the Python code and manipulating Python objects, but at the expense of the benefits gained from coding in Python. Furthermore, the coding work required increases with the dimensionality of our data. In the case of a 2-D array, for example, the C code (abridged as before) expands to for (i = 0; i < rows; i++) { for (j = 0; j < columns; j++) { c[i][j] = a[i][j]*b[i][j]; } } NumPy gives us the best of both operations are the “default mode” when an ndarray is involved, but the element-by-element operation is speedily executed by pre-compiled C code. In NumPy c = a * b does what the earlier examples do, at near-C speeds, but with the code simplicity we expect from something based on Python. Indeed, the NumPy idiom is even simpler! This last example illustrates two of NumPy’s features which are the basis of much of its and broadcasting. Why is NumPy fast?# Vectorization describes the absence of any explicit looping, indexing, etc., in the code - these things are taking place, of course, just “behind the scenes” in optimized, pre-compiled C code. Vectorized code has many advantages, among which code is more concise and easier to read fewer lines of code generally means fewer bugs the code more closely resembles standard mathematical notation (making it easier, typically, to correctly code mathematical constructs) vectorization results in more “Pythonic” code. Without vectorization, our code would be littered with inefficient and difficult to read for loops. Broadcasting is the term used to describe the implicit element-by-element behavior of operations; generally speaking, in NumPy all operations, not just arithmetic operations, but logical, bit-wise, functional, etc., behave in this implicit element-by-element fashion, i.e., they broadcast. Moreover, in the example above, a and b could be multidimensional arrays of the same shape, or a scalar and an array, or even two arrays with different shapes, provided that the smaller array is “expandable” to the shape of the larger in such a way that the resulting broadcast is unambiguous. For detailed “rules” of broadcasting see Broadcasting. Who else uses NumPy?# NumPy fully supports an object-oriented approach, starting, once again, with ndarray. For example, ndarray is a class, possessing numerous methods and attributes. Many of its methods are mirrored by functions in the outer-most NumPy namespace, allowing the programmer to code in whichever paradigm they prefer. This flexibility has allowed the NumPy array dialect and NumPy ndarray class to become the de-facto language of multi-dimensional data interchange used in Python. previous NumPy user guide next NumPy quickstart On this page Why is NumPy fast? Who else uses NumPy?\n\nExample:\n```text\nc = []\nfor i in range(len(a)):\n    c.append(a[i]*b[i])\n```\n\nExample:\n```text\nfor (i = 0; i < rows; i++) {\n  c[i] = a[i]*b[i];\n}\n```\n\nExample:\n```text\nfor (i = 0; i < rows; i++) {\n  for (j = 0; j < columns; j++) {\n    c[i][j] = a[i][j]*b[i][j];\n  }\n}\n```\n\nExample:\n```text\nc = a * b\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.944Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":31,"estimatedTokens":1589}}3{"id":"doc-i_o_with_numpy_numpy_v2_5_manual-ed17fba5","source":"documentation","title":"I/O with NumPy — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.io.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Importing data with genfromtxt Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals I/O with NumPy I/O with NumPy# Importing data with genfromtxt Defining the input Splitting the lines into columns Skipping lines and choosing columns Choosing the data type Setting the names Tweaking the conversion previous Indexing on ndarrays next Importing data with genfromtxt\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.944Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":294}}4{"id":"doc-using_numpy_c_api_numpy_v2_5_manual-e48da0ce","source":"documentation","title":"Using NumPy C-API — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/c-info.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API How to extend NumPy Using Python as glue Writing your own ufunc Beyond the basics F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide Using NumPy C-API Using NumPy C-API# How to extend NumPy Writing an extension module Required subroutine Defining functions Functions without keyword arguments Functions with keyword arguments Reference counting Dealing with array objects Converting an arbitrary sequence object Creating a brand-new ndarray Getting at ndarray memory and accessing elements of the ndarray Example Using Python as glue Calling other compiled libraries from Python Hand-generated wrappers F2PY Cython Complex addition in Cython Image filter in Cython Conclusion ctypes Having a shared library Loading the shared library Converting arguments Calling the function ndpointer Complete example Conclusion Additional tools you may find useful SWIG SIP Boost Python Pyfort Writing your own ufunc Creating a new universal function Example non-ufunc extension Example NumPy ufunc for one dtype Example NumPy ufunc with multiple dtypes Example NumPy ufunc with multiple arguments/return values Example NumPy ufunc with structured array dtype arguments Beyond the basics Iterating over elements in the array Basic iteration Iterating over all but one axis Iterating over multiple arrays Broadcasting over multiple arrays User-defined data-types Adding the new data-type Registering a casting function Registering coercion rules Registering a ufunc loop Subtyping the ndarray in C Creating sub-types Specific features of ndarray sub-typing The __array_finalize__ method ndarray.__array_finalize__ The __array_priority__ attribute ndarray.__array_priority__ The __array_wrap__ method ndarray.__array_wrap__ previous Printing NumPy Arrays next How to extend NumPy\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.944Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":593}}5{"id":"doc-numpy_fundamentals_numpy_v2_5_manual-5d748b62","source":"documentation","title":"NumPy fundamentals — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals NumPy fundamentals# These documents clarify concepts, design decisions, and technical constraints in NumPy. This is a great place to understand the fundamental NumPy ideas and philosophy. Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics previous absolute basics for beginners next Array creation\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.945Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":324}}6{"id":"doc-numpy_how_tos_numpy_v2_5_manual-9fbeed16","source":"documentation","title":"NumPy how-tos — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/howtos_index.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos How to write a NumPy how-to Reading and writing files How to index ndarrays Verifying bugs and bug fixes in NumPy How to create arrays with regularly-spaced values Printing NumPy Arrays Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy how-tos NumPy how-tos# These documents are intended as recipes to common tasks using NumPy. For detailed reference documentation of the functions and classes contained in the package, see the API reference. How to write a NumPy how-to Reading and writing files How to index ndarrays Verifying bugs and bug fixes in NumPy How to create arrays with regularly-spaced values Printing NumPy Arrays previous NumPy for MATLAB users next How to write a NumPy how-to\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.945Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":327}}7{"id":"doc-copies_and_views_numpy_v2_5_manual-473d0b16","source":"documentation","title":"Copies and views — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.copies.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Copies and views Copies and views# When operating on NumPy arrays, it is possible to access the internal data buffer directly using a view without copying data around. This ensures good performance but can also cause unwanted problems if the user is not aware of how this works. Hence, it is important to know the difference between these two terms and to know which operations return copies and which return views. The NumPy array is a data structure consisting of two contiguous data buffer with the actual data elements and the metadata that contains information about the data buffer. The metadata includes data type, strides, and other important information that helps manipulate the ndarray easily. See the Internal organization of NumPy arrays section for a detailed look. View# It is possible to access the array differently by just changing certain metadata like stride and dtype without changing the data buffer. This creates a new way of looking at the data and these new arrays are called views. The data buffer remains the same, so any changes made to a view reflects in the original copy. A view can be forced through the ndarray.view method. Copy# When a new array is created by duplicating the data buffer as well as the metadata, it is called a copy. Changes made to the copy do not reflect on the original array. Making a copy is slower and memory-consuming but sometimes necessary. A copy can be forced by using ndarray.copy. Indexing operations# See also Indexing on ndarrays Views are created when elements can be addressed with offsets and strides in the original array. Hence, basic indexing always creates views. For example: >>> import numpy as np >>> x = np.arange(10) >>> x array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> y = x[1:3] # creates a view >>> y array([1, 2]) >>> x[1:3] = [10, 11] >>> x array([ 0, 10, 11, 3, 4, 5, 6, 7, 8, 9]) >>> y array([10, 11]) Here, y gets changed when x is changed because it is a view. Advanced indexing, on the other hand, always creates copies. For example: >>> import numpy as np >>> x = np.arange(9).reshape(3, 3) >>> x array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> y = x[[1, 2]] >>> y array([[3, 4, 5], [6, 7, 8]]) >>> y.base is None True Here, y is a copy, as signified by the base attribute. We can also confirm this by assigning new values to x[[1, 2]] which in turn will not affect y at all: >>> x[[1, 2]] = [[10, 11, 12], [13, 14, 15]] >>> x array([[ 0, 1, 2], [10, 11, 12], [13, 14, 15]]) >>> y array([[3, 4, 5], [6, 7, 8]]) It must be noted here that during the assignment of x[[1, 2]] no view or copy is created as the assignment happens in-place. Other operations# The numpy.reshape function creates a view where possible or a copy otherwise. In most cases, the strides can be modified to reshape the array with a view. However, in some cases where the array becomes non-contiguous (perhaps after a ndarray.transpose operation), the reshaping cannot be done by modifying strides and requires a copy. Taking the example of another operation, numpy.ravel returns a contiguous flattened view of the array wherever possible. On the other hand, ndarray.flatten always returns a flattened copy of the array. However, to guarantee a view in most cases, x.reshape(-1) may be preferable. How to tell if the array is a view or a copy# The base attribute of the ndarray makes it easy to tell if an array is a view or a copy. The base attribute of a view returns the original array while it returns None for a copy. >>> import numpy as np >>> x = np.arange(9) >>> x array([0, 1, 2, 3, 4, 5, 6, 7, 8]) >>> y = x.reshape(3, 3) >>> y array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> y.base # .reshape() creates a view array([0, 1, 2, 3, 4, 5, 6, 7, 8]) >>> z = y[[2, 1]] >>> z array([[6, 7, 8], [3, 4, 5]]) >>> z.base is None # advanced indexing creates a copy True Note that the base attribute should not be used to determine if an ndarray object is new; only if it is a view or a copy of another ndarray. previous Broadcasting next Working with Arrays of Strings And Bytes On this page View Copy Indexing operations Other operations How to tell if the array is a view or a copy\n\nExample:\n```text\n>>> import numpy as np\n>>> x = np.arange(10)\n>>> x\narray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n>>> y = x[1:3]  # creates a view\n>>> y\narray([1, 2])\n>>> x[1:3] = [10, 11]\n>>> x\narray([ 0, 10, 11,  3,  4,  5,  6,  7,  8,  9])\n>>> y\narray([10, 11])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> x = np.arange(9).reshape(3, 3)\n>>> x\narray([[0, 1, 2],\n       [3, 4, 5],\n       [6, 7, 8]])\n>>> y = x[[1, 2]]\n>>> y\narray([[3, 4, 5],\n       [6, 7, 8]])\n>>> y.base is None\nTrue\n```\n\nExample:\n```text\n>>> x[[1, 2]] = [[10, 11, 12], [13, 14, 15]]\n>>> x\narray([[ 0,  1,  2],\n       [10, 11, 12],\n       [13, 14, 15]])\n>>> y\narray([[3, 4, 5],\n       [6, 7, 8]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> x = np.arange(9)\n>>> x\narray([0, 1, 2, 3, 4, 5, 6, 7, 8])\n>>> y = x.reshape(3, 3)\n>>> y\narray([[0, 1, 2],\n       [3, 4, 5],\n       [6, 7, 8]])\n>>> y.base  # .reshape() creates a view\narray([0, 1, 2, 3, 4, 5, 6, 7, 8])\n>>> z = y[[2, 1]]\n>>> z\narray([[6, 7, 8],\n       [3, 4, 5]])\n>>> z.base is None  # advanced indexing creates a copy\nTrue\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.945Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":68,"estimatedTokens":1512}}8{"id":"doc-working_with_arrays_of_strings_and_bytes_numpy_v-5349dfdc","source":"documentation","title":"Working with Arrays of Strings And Bytes — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.strings.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Working with Arrays of Strings And Bytes Working with Arrays of Strings And Bytes# While NumPy is primarily a numerical library, it is often convenient to work with NumPy arrays of strings or bytes. The two most common use cases with data loaded or memory-mapped from a data file, where one or more of the fields in the data is a string or bytestring, and the maximum length of the field is known ahead of time. This often is used for a name or label field. Using NumPy indexing and broadcasting with arrays of Python strings of unknown length, which may or may not have data defined for every value. For the first use case, NumPy provides the fixed-width numpy.void, numpy.str_ and numpy.bytes_ data types. For the second use case, numpy provides numpy.dtypes.StringDType. Below we describe how to work with both fixed-width and variable-width string arrays, how to convert between the two representations, and provide some advice for most efficiently working with string data in NumPy. Fixed-width data types# Before NumPy 2.0, the fixed-width numpy.str_, numpy.bytes_, and numpy.void data types were the only types available for working with strings and bytestrings in NumPy. For this reason, they are used as the default dtype for strings and bytestrings, respectively: >>> np.array([\"hello\", \"world\"]) array(['hello', 'world'], dtype='<U5') Here the detected data type is '<U5', or little-endian unicode string data, with a maximum length of 5 unicode code points. Similarly for bytestrings: >>> np.array([b\"hello\", b\"world\"]) array([b'hello', b'world'], dtype='|S5') Since this is a one-byte encoding, the byteorder is ‘|’ (not applicable), and the data type detected is a maximum 5 character bytestring. You can also use numpy.void to represent bytestrings: >>> np.array([b\"hello\", b\"world\"]).astype(np.void) array([b'\\x68\\x65\\x6C\\x6C\\x6F', b'\\x77\\x6F\\x72\\x6C\\x64'], dtype='|V5') This is most useful when working with byte streams that are not well represented as bytestrings, and instead are better thought of as collections of 8-bit integers. Variable-width strings# New in version 2.0. Note numpy.dtypes.StringDType is a new addition to NumPy, implemented using the new support in NumPy for flexible user-defined data types and is not as extensively tested in production workflows as the older NumPy data types. Often, real-world string data does not have a predictable length. In these cases it is awkward to use fixed-width strings, since storing all the data without truncation requires knowing the length of the longest string one would like to store in the array before the array is created. To support situations like this, NumPy provides numpy.dtypes.StringDType, which stores variable-width string data in a UTF-8 encoding in a NumPy array: >>> from numpy.dtypes import StringDType >>> data = [\"this is a longer string\", \"short string\"] >>> arr = np.array(data, dtype=StringDType()) >>> arr array(['this is a longer string', 'short string'], dtype=StringDType()) Note that unlike fixed-width strings, StringDType is not parameterized by the maximum length of an array element, arbitrarily long or short strings can live in the same array without needing to reserve storage for padding bytes in the short strings. Also note that unlike fixed-width strings and most other NumPy data types, StringDType does not store the string data in the “main” ndarray data buffer. Instead, the array buffer is used to store metadata about where the string data are stored in memory. This difference means that code expecting the array buffer to contain string data will not function correctly, and will need to be updated to support StringDType. Missing data support# Often string datasets are not complete, and a special label is needed to indicate that a value is missing. By default StringDType does not have any special support for missing values, besides the fact that empty strings are used to populate empty arrays: >>> np.empty(3, dtype=StringDType()) array(['', '', ''], dtype=StringDType()) Optionally, you can create an instance of StringDType with support for missing values by passing na_object as a keyword argument for the initializer: >>> dt = StringDType(na_object=None) >>> arr = np.array([\"this array has\", None, \"as an entry\"], dtype=dt) >>> arr array(['this array has', None, 'as an entry'], dtype=StringDType(na_object=None)) >>> arr[1] is None True The na_object can be any arbitrary python object. Common choices are numpy.nan, float('nan'), None, an object specifically intended to represent missing data like pandas.NA, or a (hopefully) unique string like \"__placeholder__\". NumPy has special handling for NaN-like sentinels and string sentinels. NaN-like Missing Data Sentinels# A NaN-like sentinel returns itself as the result of arithmetic operations. This includes the python nan float and the Pandas missing data sentinel pd.NA. NaN-like sentinels inherit these behaviors in string operations. This means that, for example, the result of addition with any other string is the sentinel: >>> dt = StringDType(na_object=np.nan) >>> arr = np.array([\"hello\", np.nan, \"world\"], dtype=dt) >>> arr + arr array(['hellohello', nan, 'worldworld'], dtype=StringDType(na_object=nan)) Following the behavior of nan in float arrays, NaN-like sentinels sort to the end of the array: >>> np.sort(arr) array(['hello', 'world', nan], dtype=StringDType(na_object=nan)) String Missing Data Sentinels# A string missing data value is an instance of str or subtype of str. If such an array is passed to a string operation or a cast, “missing” entries are treated as if they have a value given by the string sentinel. Comparison operations similarly use the sentinel value directly for missing entries. Other Sentinels# Other objects, such as None are also supported as missing data sentinels. If any missing data are present in an array using such a sentinel, then string operations will raise an error: >>> dt = StringDType(na_object=None) >>> arr = np.array([\"this array has\", None, \"as an entry\"]) >>> np.sort(arr) Traceback (most recent call last): ... TypeError: '<' not supported between instances of 'NoneType' and 'str' Coercing Non-strings# By default, non-string data are coerced to strings: >>> np.array([1, object(), 3.4], dtype=StringDType()) array(['1', '<object object at 0x7faa2497dde0>', '3.4'], dtype=StringDType()) If this behavior is not desired, an instance of the DType can be created that disables string coercion by setting coerce=False in the initializer: >>> np.array([1, object(), 3.4], dtype=StringDType(coerce=False)) Traceback (most recent call last): ... only allows string data when string coercion is disabled. This allows strict data validation in the same pass over the data NumPy uses to create the array. Setting coerce=True recovers the default behavior allowing coercion to strings. Casting To and From Fixed-Width Strings# StringDType supports round-trip casts between numpy.str_, numpy.bytes_, and numpy.void. Casting to a fixed-width string is most useful when strings need to be memory-mapped in an ndarray or when a fixed-width string is needed for reading and writing to a columnar data format with a known maximum string length. In all cases, casting to a fixed-width string requires specifying the maximum allowed string length: >>> arr = np.array([\"hello\", \"world\"], dtype=StringDType()) >>> arr.astype(np.str_) Traceback (most recent call last): ... from StringDType to a fixed-width dtype with an unspecified size is not currently supported, specify an explicit size for the output dtype instead. The above exception was the direct cause of the following : cannot cast dtype StringDType() to <class 'numpy.dtypes.StrDType'>. >>> arr.astype(\"U5\") array(['hello', 'world'], dtype='<U5') The numpy.bytes_ cast is most useful for string data that is known to contain only ASCII characters, as characters outside this range cannot be represented in a single byte in the UTF-8 encoding and are rejected. Any valid unicode string can be cast to numpy.str_, although since numpy.str_ uses a 32-bit UCS4 encoding for all characters, this will often waste memory for real-world textual data that can be well-represented by a more memory-efficient encoding. Additionally, any valid unicode string can be cast to numpy.void, storing the UTF-8 bytes directly in the output array: >>> arr = np.array([\"hello\", \"world\"], dtype=StringDType()) >>> arr.astype(\"V5\") array([b'\\x68\\x65\\x6C\\x6C\\x6F', b'\\x77\\x6F\\x72\\x6C\\x64'], dtype='|V5') Care must be taken to ensure that the output array has enough space for the UTF-8 bytes in the string, since the size of a UTF-8 bytestream in bytes is not necessarily the same as the number of characters in the string. previous Copies and views next Structured arrays On this page Fixed-width data types Variable-width strings Missing data support NaN-like Missing Data Sentinels String Missing Data Sentinels Other Sentinels Coercing Non-strings Casting To and From Fixed-Width Strings\n\nExample:\n```text\n>>> np.array([\"hello\", \"world\"])\narray(['hello', 'world'], dtype='<U5')\n```\n\nExample:\n```text\n>>> np.array([b\"hello\", b\"world\"])\narray([b'hello', b'world'], dtype='|S5')\n```\n\nExample:\n```text\n>>> np.array([b\"hello\", b\"world\"]).astype(np.void)\narray([b'\\x68\\x65\\x6C\\x6C\\x6F', b'\\x77\\x6F\\x72\\x6C\\x64'], dtype='|V5')\n```\n\nExample:\n```text\n>>> from numpy.dtypes import StringDType\n>>> data = [\"this is a longer string\", \"short string\"]\n>>> arr = np.array(data, dtype=StringDType())\n>>> arr\narray(['this is a longer string', 'short string'], dtype=StringDType())\n```\n\nExample:\n```text\n>>> np.empty(3, dtype=StringDType())\narray(['', '', ''], dtype=StringDType())\n```\n\nExample:\n```text\n>>> dt = StringDType(na_object=None)\n>>> arr = np.array([\"this array has\", None, \"as an entry\"], dtype=dt)\n>>> arr\narray(['this array has', None, 'as an entry'],\n      dtype=StringDType(na_object=None))\n>>> arr[1] is None\nTrue\n```\n\nExample:\n```text\n>>> dt = StringDType(na_object=np.nan)\n>>> arr = np.array([\"hello\", np.nan, \"world\"], dtype=dt)\n>>> arr + arr\narray(['hellohello', nan, 'worldworld'], dtype=StringDType(na_object=nan))\n```\n\nExample:\n```text\n>>> np.sort(arr)\narray(['hello', 'world', nan], dtype=StringDType(na_object=nan))\n```\n\nExample:\n```text\n>>> dt = StringDType(na_object=None)\n>>> arr = np.array([\"this array has\", None, \"as an entry\"])\n>>> np.sort(arr)\nTraceback (most recent call last):\n...\nTypeError: '<' not supported between instances of 'NoneType' and 'str'\n```\n\nExample:\n```text\n>>> np.array([1, object(), 3.4], dtype=StringDType())\narray(['1', '<object object at 0x7faa2497dde0>', '3.4'], dtype=StringDType())\n```\n\nExample:\n```text\n>>> np.array([1, object(), 3.4], dtype=StringDType(coerce=False))\nTraceback (most recent call last):\n...\nValueError: StringDType only allows string data when string coercion is disabled.\n```\n\nExample:\n```text\n>>> arr = np.array([\"hello\", \"world\"], dtype=StringDType())\n>>> arr.astype(np.str_)  \nTraceback (most recent call last):\n...\nTypeError: Casting from StringDType to a fixed-width dtype with an\nunspecified size is not currently supported, specify an explicit\nsize for the output dtype instead.\n\nThe above exception was the direct cause of the following\nexception:\n\nTypeError: cannot cast dtype StringDType() to <class 'numpy.dtypes.StrDType'>.\n>>> arr.astype(\"U5\")\narray(['hello', 'world'], dtype='<U5')\n```\n\nExample:\n```text\n>>> arr = np.array([\"hello\", \"world\"], dtype=StringDType())\n>>> arr.astype(\"V5\")\narray([b'\\x68\\x65\\x6C\\x6C\\x6F', b'\\x77\\x6F\\x72\\x6C\\x64'], dtype='|V5')\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.947Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":13,"totalLines":110,"estimatedTokens":3094}}9{"id":"doc-interoperability_with_numpy_numpy_v2_5_manual-03f89ad3","source":"documentation","title":"Interoperability with NumPy — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.interoperability.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide Interoperability with NumPy Interoperability with NumPy# NumPy’s ndarray objects provide both a high-level API for operations on array-structured data and a concrete implementation of the API based on strided in-RAM storage. While this API is powerful and fairly general, its concrete implementation has limitations. As datasets grow and NumPy becomes used in a variety of new environments and architectures, there are cases where the strided in-RAM storage strategy is inappropriate, which has caused different libraries to reimplement this API for their own uses. This includes GPU arrays (CuPy), Sparse arrays (scipy.sparse, PyData/Sparse) and parallel arrays (Dask arrays) as well as various NumPy-like implementations in deep learning frameworks, like TensorFlow and PyTorch. Similarly, there are many projects that build on top of the NumPy API for labeled and indexed arrays (XArray), automatic differentiation (JAX), masked arrays (numpy.ma), physical units (astropy.units, pint, unyt), among others that add additional functionality on top of the NumPy API. Yet, users still want to work with these arrays using the familiar NumPy API and reuse existing code with minimal (ideally zero) porting overhead. With this goal in mind, various protocols are defined for implementations of multi-dimensional arrays with high-level APIs matching NumPy. Broadly speaking, there are three groups of features used for interoperability with of turning a foreign object into an ndarray; Methods of deferring execution from a NumPy function to another array library; Methods that use NumPy functions and return an instance of a foreign object. We describe these features below. 1. Using arbitrary objects in NumPy# The first set of interoperability features from the NumPy API allows foreign objects to be treated as NumPy arrays whenever possible. When NumPy functions encounter a foreign object, they will try (in order): The buffer protocol, described in the Python C-API documentation. The __array_interface__ protocol, described in this page. A precursor to Python’s buffer protocol, it defines a way to access the contents of a NumPy array from other C extensions. The __array__() method, which asks an arbitrary object to convert itself into an array. For both the buffer and the __array_interface__ protocols, the object describes its memory layout and NumPy does everything else (zero-copy if possible). If that’s not possible, the object itself is responsible for returning a ndarray from __array__(). DLPack is yet another protocol to convert foreign objects to NumPy arrays in a language and device agnostic manner. NumPy doesn’t implicitly convert objects to ndarrays using DLPack. It provides the function numpy.from_dlpack that accepts any object implementing the __dlpack__ method and outputs a NumPy ndarray (which is generally a view of the input object’s data buffer). The Python Specification for DLPack page explains the __dlpack__ protocol in detail. dtype interoperability# Similar to __array__() for array objects, defining __numpy_dtype__ allows a custom dtype object to be interoperable with NumPy. The __numpy_dtype__ must return a NumPy dtype instance (note that np.float64 is not a dtype instance, np.dtype(np.float64) is). New in version 2.4: Before NumPy 2.4 a The __array_interface__ attribute can also be used to manipulate the object data in place: >>> class wrapper(): ... pass ... >>> arr = np.array([1, 2, 3, 4]) >>> buf = arr.__array_interface__ >>> buf {'data': (140497590272032, False), 'strides': None, 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (4,), 'version': 3} >>> buf['shape'] = (2, 2) >>> w = wrapper() >>> w.__array_interface__ = buf >>> new_arr = np.array(w, copy=False) >>> new_arr array([[1, 2], [3, 4]]) We can check that arr and new_arr share the same data buffer: >>> new_arr[0, 0] = 1000 >>> new_arr array([[1000, 2], [ 3, 4]]) >>> arr array([1000, 2, 3, 4]) The __array__() method# The __array__() method ensures that any NumPy-like object (an array, any object exposing the array interface, an object whose __array__() method returns an array or any nested sequence) that implements it can be used as a NumPy array. If possible, this will mean using __array__() to create a NumPy ndarray view of the array-like object. Otherwise, this copies the data into a new ndarray object. This is not optimal, as coercing arrays into ndarrays may cause performance problems or create the need for copies and loss of metadata, as the original object and any attributes/behavior it may have had, is lost. The signature of the method should be __array__(self, dtype=None, copy=None). If a passed dtype isn’t None and different than the object’s data type, a casting should happen to a specified type. If copy is None, a copy should be made only if dtype argument enforces it. For copy=True, a copy should always be made, where copy=False should raise an exception if a copy is needed. If a class implements the old signature __array__(self), for np.array(a) a warning will be raised saying that dtype and copy arguments are missing. The DLPack Protocol# The DLPack protocol defines a memory-layout of strided n-dimensional array objects. It offers the following syntax for data numpy.from_dlpack function, which accepts (array) objects with a __dlpack__ method and uses that method to construct a new array containing the data from x. __dlpack__(self, stream=None) and __dlpack_device__ methods on the array object, which will be called from within from_dlpack, to query what device the array is on (may be needed to pass in the correct stream, e.g. in the case of multiple GPUs) and to access the data. Unlike the buffer protocol, DLPack allows exchanging arrays containing data on devices other than the CPU (e.g. Vulkan or GPU). Since NumPy only supports CPU, it can only convert objects whose data exists on the CPU. But other libraries, like PyTorch and CuPy, may exchange data on GPU using this protocol. 2. Operating on foreign objects without converting# A second set of methods defined by the NumPy API allows us to defer the execution from a NumPy function to another array library. Consider the following function. >>> import numpy as np >>> def f(x): ... return np.mean(np.exp(x)) Note that np.exp is a ufunc, which means that it operates on ndarrays in an element-by-element fashion. On the other hand, np.mean operates along one of the array’s axes. We can apply f to a NumPy ndarray object directly: >>> x = np.array([1, 2, 3, 4]) >>> f(x) 21.1977562209304 We would like this function to work equally well with any NumPy-like array object. NumPy allows a class to indicate that it would like to handle computations in a custom-defined way through the following : allows third-party objects to support and override ufuncs. catch-all for NumPy functionality that is not covered by the __array_ufunc__ protocol for universal functions. As long as foreign objects implement the __array_ufunc__ or __array_function__ protocols, it is possible to operate on them without the need for explicit conversion. The __array_ufunc__ protocol# A universal function (or ufunc for short) is a “vectorized” wrapper for a function that takes a fixed number of specific inputs and produces a fixed number of specific outputs. The output of the ufunc (and its methods) is not necessarily an ndarray, if not all input arguments are ndarrays. Indeed, if any input defines an __array_ufunc__ method, control will be passed completely to that function, i.e., the ufunc is overridden. The __array_ufunc__ method defined on that (non-ndarray) object has access to the NumPy ufunc. Because ufuncs have a well-defined structure, the foreign __array_ufunc__ method may rely on ufunc attributes like .at(), .reduce(), and others. A subclass can override what happens when executing NumPy ufuncs on it by overriding the default ndarray.__array_ufunc__ method. This method is executed instead of the ufunc and should return either the result of the operation, or NotImplemented if the operation requested is not implemented. The __array_function__ protocol# To achieve enough coverage of the NumPy API to support downstream projects, there is a need to go beyond __array_ufunc__ and implement a protocol that allows arguments of a NumPy function to take control and divert execution to another function (for example, a GPU or parallel implementation) in a way that is safe and consistent across projects. The semantics of __array_function__ are very similar to __array_ufunc__, except the operation is specified by an arbitrary callable object rather than a ufunc instance and method. For more details, see NEP 18 — A dispatch mechanism for NumPy’s high level array functions. 3. Returning foreign objects# A third type of feature set is meant to use the NumPy function implementation and then convert the return value back into an instance of the foreign object. The __array_finalize__ and __array_wrap__ methods act behind the scenes to ensure that the return type of a NumPy function can be specified as needed. The __array_finalize__ method is the mechanism that NumPy provides to allow subclasses to handle the various ways that new instances get created. This method is called whenever the system internally allocates a new array from an object which is a subclass (subtype) of the ndarray. It can be used to change attributes after construction, or to update meta-information from the “parent.” The __array_wrap__ method “wraps up the action” in the sense of allowing any object (such as user-defined functions) to set the type of its return value and update attributes and metadata. This can be seen as the opposite of the __array__ method. At the end of every object that implements __array_wrap__, this method is called on the input object with the highest array priority, or the output object if one was specified. The __array_priority__ attribute is used to determine what type of object to return in situations where there is more than one possibility for the Python type of the returned object. For example, subclasses may opt to use this method to transform the output array into an instance of the subclass and update metadata before returning the array to the user. For more information on these methods, see Subclassing ndarray and Specific features of ndarray sub-typing. Interoperability examples# Series objects# Consider the following: >>> import pandas as pd >>> ser = pd.Series([1, 2, 3, 4]) >>> type(ser) pandas.core.series.Series Now, ser is not an ndarray, but because it implements the __array_ufunc__ protocol, we can apply ufuncs to it as if it were an ndarray: >>> np.exp(ser) 0 2.718282 1 7.389056 2 20.085537 3 54.598150 >>> np.sin(ser) 0 0.841471 1 0.909297 2 0.141120 3 -0.756802 We can even do operations with other ndarrays: >>> np.add(ser, np.array([5, 6, 7, 8])) 0 6 1 8 2 10 3 12 >>> f(ser) 21.1977562209304 >>> result = ser.__array__() >>> type(result) numpy.ndarray tensors# PyTorch is an optimized tensor library for deep learning using GPUs and CPUs. PyTorch arrays are commonly called tensors. Tensors are similar to NumPy’s ndarrays, except that tensors can run on GPUs or other hardware accelerators. In fact, tensors and NumPy arrays can often share the same underlying memory, eliminating the need to copy data. >>> import torch >>> data = [[1, 2],[3, 4]] >>> x_np = np.array(data) >>> x_tensor = torch.tensor(data) Note that x_np and x_tensor are different kinds of objects: >>> x_np array([[1, 2], [3, 4]]) >>> x_tensor tensor([[1, 2], [3, 4]]) However, we can treat PyTorch tensors as NumPy arrays without the need for explicit conversion: >>> np.exp(x_tensor) tensor([[ 2.7183, 7.3891], [20.0855, 54.5982]], dtype=torch.float64) Also, note that the return type of this function is compatible with the initial data type. Warning While this mixing of ndarrays and tensors may be convenient, it is not recommended. It will not work for non-CPU tensors, and will have unexpected behavior in corner cases. Users should prefer explicitly converting the ndarray to a tensor. Note PyTorch does not implement __array_function__ or __array_ufunc__. Under the hood, the Tensor.__array__() method returns a NumPy ndarray as a view of the tensor data buffer. See this issue and the __torch_function__ implementation for details. Note also that we can see __array_wrap__ in action here, even though torch.Tensor is not a subclass of ndarray: >>> import torch >>> t = torch.arange(4) >>> np.abs(t) tensor([0, 1, 2, 3]) PyTorch implements __array_wrap__ to be able to get tensors back from NumPy functions, and we can modify it directly to control which type of objects are returned from these functions. arrays# CuPy is a NumPy/SciPy-compatible array library for GPU-accelerated computing with Python. CuPy implements a subset of the NumPy interface by implementing cupy.ndarray, a counterpart to NumPy ndarrays. >>> import cupy as cp >>> x_gpu = cp.array([1, 2, 3, 4]) The cupy.ndarray object implements the __array_ufunc__ interface. This enables NumPy ufuncs to be applied to CuPy arrays (this will defer operation to the matching CuPy CUDA/ROCm implementation of the ufunc): >>> np.mean(np.exp(x_gpu)) array(21.19775622) Note that the return type of these operations is still consistent with the initial type: >>> arr = cp.random.randn(1, 2, 3, 4).astype(cp.float32) >>> result = np.sum(arr) >>> print(type(result)) <class 'cupy._core.core.ndarray'> See this page in the CuPy documentation for details. cupy.ndarray also implements the __array_function__ interface, meaning it is possible to do operations such as >>> a = np.random.randn(100, 100) >>> a_gpu = cp.asarray(a) >>> qr_gpu = np.linalg.qr(a_gpu) CuPy implements many NumPy functions on cupy.ndarray objects, but not all. See the CuPy documentation for details. arrays# Dask is a flexible library for parallel computing in Python. Dask Array implements a subset of the NumPy ndarray interface using blocked algorithms, cutting up the large array into many small arrays. This allows computations on larger-than-memory arrays using multiple cores. Dask supports __array__() and __array_ufunc__. >>> import dask.array as da >>> x = da.random.normal(1, 0.1, size=(20, 20), chunks=(10, 10)) >>> np.mean(np.exp(x)) dask.array<mean_agg-aggregate, shape=(), dtype=float64, chunksize=(), chunktype=numpy.ndarray> >>> np.mean(np.exp(x)).compute() 5.090097550553843 Note Dask is lazily evaluated, and the result from a computation isn’t computed until you ask for it by invoking compute(). See the Dask array documentation and the scope of Dask arrays interoperability with NumPy arrays for details. # Several Python data science libraries implement the __dlpack__ protocol. Among them are PyTorch and CuPy. A full list of libraries that implement this protocol can be found on this page of DLPack documentation. Convert a PyTorch CPU tensor to NumPy array: >>> import torch >>> x_torch = torch.arange(5) >>> x_torch tensor([0, 1, 2, 3, 4]) >>> x_np = np.from_dlpack(x_torch) >>> x_np array([0, 1, 2, 3, 4]) >>> # note that x_np is a view of x_torch >>> x_torch[1] = 100 >>> x_torch tensor([ 0, 100, 2, 3, 4]) >>> x_np array([ 0, 100, 2, 3, 4]) The imported arrays are read-only so writing or operating in-place will fail: >>> x_np.flags.writeable False >>> x_np[1] = 1 Traceback (most recent call last): File \"<stdin>\", line 1, in <module> destination is read-only A copy must be created in order to operate on the imported arrays in-place, but will mean duplicating the memory. Do not do this for very large arrays: >>> x_np_copy = x_np.copy() >>> x_np_copy.sort() # works Note GPU tensors cannot be directly zero-copy converted to NumPy arrays since NumPy does not support GPU devices. However, since DLPack v1, cross-device copy is supported via the device parameter: >>> x_torch = torch.arange(5, device='cuda') >>> np.from_dlpack(x_torch) # device=None means same device Traceback (most recent call last): File \"<stdin>\", line 1, in <module> device in DLTensor. >>> np.from_dlpack(x_torch, device='cpu') # copy to CPU array([0, 1, 2, 3, 4]) If both libraries support the device the data buffer is on, it is possible to use the __dlpack__ protocol (e.g. PyTorch and CuPy): >>> x_torch = torch.arange(5, device='cuda') >>> x_cupy = cupy.from_dlpack(x_torch) Similarly, a NumPy array can be converted to a PyTorch tensor: >>> x_np = np.arange(5) >>> x_torch = torch.from_dlpack(x_np) Read-only arrays cannot be exported: >>> x_np = np.arange(5) >>> x_np.flags.writeable = False >>> torch.from_dlpack(x_np) Traceback (most recent call last): File \"<stdin>\", line 1, in <module> File \".../site-packages/torch/utils/dlpack.py\", line 63, in from_dlpack dlpack = ext_tensor.__dlpack__() currently only supports dlpack for writeable arrays Further reading# The array interface protocol Writing custom array containers Special attributes and methods (details on the __array_ufunc__ and __array_function__ protocols) Subclassing ndarray (details on the __array_wrap__ and __array_finalize__ methods) Specific features of ndarray sub-typing (more details on the implementation of __array_finalize__, __array_wrap__ and __array_priority__) NumPy PyTorch documentation on the Bridge with NumPy previous Subclassing ndarray next Writing Performant NumPy Code with Multi-Core CPUs On this page 1. Using arbitrary objects in NumPy dtype interoperability The array interface protocol The __array__() method The DLPack Protocol 2. Operating on foreign objects without converting The __array_ufunc__ protocol The __array_function__ protocol 3. Returning foreign objects Interoperability examples Series objects tensors arrays arrays Further reading\n\nExample:\n```text\n>>> import numpy as np\n>>> x = np.array([1, 2, 5.0, 8])\n>>> x.__array_interface__\n{'data': (94708397920832, False), 'strides': None, 'descr': [('', '<f8')], 'typestr': '<f8', 'shape': (4,), 'version': 3}\n```\n\nExample:\n```text\n>>> class wrapper():\n...     pass\n...\n>>> arr = np.array([1, 2, 3, 4])\n>>> buf = arr.__array_interface__\n>>> buf\n{'data': (140497590272032, False), 'strides': None, 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (4,), 'version': 3}\n>>> buf['shape'] = (2, 2)\n>>> w = wrapper()\n>>> w.__array_interface__ = buf\n>>> new_arr = np.array(w, copy=False)\n>>> new_arr\narray([[1, 2],\n       [3, 4]])\n```\n\nExample:\n```text\n>>> new_arr[0, 0] = 1000\n>>> new_arr\narray([[1000,    2],\n       [   3,    4]])\n>>> arr\narray([1000, 2, 3, 4])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> def f(x):\n...     return np.mean(np.exp(x))\n```\n\nExample:\n```text\n>>> x = np.array([1, 2, 3, 4])\n>>> f(x)\n21.1977562209304\n```\n\nExample:\n```text\n>>> import pandas as pd\n>>> ser = pd.Series([1, 2, 3, 4])\n>>> type(ser)\npandas.core.series.Series\n```\n\nExample:\n```text\n>>> np.exp(ser)\n   0     2.718282\n   1     7.389056\n   2    20.085537\n   3    54.598150\n   dtype: float64\n>>> np.sin(ser)\n   0    0.841471\n   1    0.909297\n   2    0.141120\n   3   -0.756802\n   dtype: float64\n```\n\nExample:\n```text\n>>> np.add(ser, np.array([5, 6, 7, 8]))\n   0     6\n   1     8\n   2    10\n   3    12\n   dtype: int64\n>>> f(ser)\n21.1977562209304\n>>> result = ser.__array__()\n>>> type(result)\nnumpy.ndarray\n```\n\nExample:\n```text\n>>> import torch\n>>> data = [[1, 2],[3, 4]]\n>>> x_np = np.array(data)\n>>> x_tensor = torch.tensor(data)\n```\n\nExample:\n```text\n>>> x_np\narray([[1, 2],\n       [3, 4]])\n>>> x_tensor\ntensor([[1, 2],\n        [3, 4]])\n```\n\nExample:\n```text\n>>> np.exp(x_tensor)\ntensor([[ 2.7183,  7.3891],\n        [20.0855, 54.5982]], dtype=torch.float64)\n```\n\nExample:\n```text\n>>> import torch\n>>> t = torch.arange(4)\n>>> np.abs(t)\ntensor([0, 1, 2, 3])\n```\n\nExample:\n```text\n>>> import cupy as cp\n>>> x_gpu = cp.array([1, 2, 3, 4])\n```\n\nExample:\n```text\n>>> np.mean(np.exp(x_gpu))\narray(21.19775622)\n```\n\nExample:\n```text\n>>> arr = cp.random.randn(1, 2, 3, 4).astype(cp.float32)\n>>> result = np.sum(arr)\n>>> print(type(result))\n<class 'cupy._core.core.ndarray'>\n```\n\nExample:\n```text\n>>> a = np.random.randn(100, 100)\n>>> a_gpu = cp.asarray(a)\n>>> qr_gpu = np.linalg.qr(a_gpu)\n```\n\nExample:\n```text\n>>> import dask.array as da\n>>> x = da.random.normal(1, 0.1, size=(20, 20), chunks=(10, 10))\n>>> np.mean(np.exp(x))\ndask.array<mean_agg-aggregate, shape=(), dtype=float64, chunksize=(), chunktype=numpy.ndarray>\n>>> np.mean(np.exp(x)).compute()\n5.090097550553843\n```\n\nExample:\n```text\n>>> import torch\n>>> x_torch = torch.arange(5)\n>>> x_torch\ntensor([0, 1, 2, 3, 4])\n>>> x_np = np.from_dlpack(x_torch)\n>>> x_np\narray([0, 1, 2, 3, 4])\n>>> # note that x_np is a view of x_torch\n>>> x_torch[1] = 100\n>>> x_torch\ntensor([  0, 100,   2,   3,   4])\n>>> x_np\narray([  0, 100,   2,   3,   4])\n```\n\nExample:\n```text\n>>> x_np.flags.writeable\nFalse\n>>> x_np[1] = 1\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\nValueError: assignment destination is read-only\n```\n\nExample:\n```text\n>>> x_np_copy = x_np.copy()\n>>> x_np_copy.sort()  # works\n```\n\nExample:\n```text\n>>> x_torch = torch.arange(5, device='cuda')\n>>> np.from_dlpack(x_torch)  # fails: implicit device=None means same device\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\nRuntimeError: Unsupported device in DLTensor.\n>>> np.from_dlpack(x_torch, device='cpu')  # works: explicit copy to CPU\narray([0, 1, 2, 3, 4])\n```\n\nExample:\n```text\n>>> x_torch = torch.arange(5, device='cuda')\n>>> x_cupy = cupy.from_dlpack(x_torch)\n```\n\nExample:\n```text\n>>> x_np = np.arange(5)\n>>> x_torch = torch.from_dlpack(x_np)\n```\n\nExample:\n```text\n>>> x_np = np.arange(5)\n>>> x_np.flags.writeable = False\n>>> torch.from_dlpack(x_np)  \nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \".../site-packages/torch/utils/dlpack.py\", line 63, in from_dlpack\n    dlpack = ext_tensor.__dlpack__()\nTypeError: NumPy currently only supports dlpack for writeable arrays\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.950Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":24,"totalLines":230,"estimatedTokens":5621}}10{"id":"doc-broadcasting_numpy_v2_5_manual-af711ca9","source":"documentation","title":"Broadcasting — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.broadcasting.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Broadcasting Broadcasting# See also numpy.broadcast The term broadcasting describes how NumPy treats arrays with different shapes during arithmetic operations. Subject to certain constraints, the smaller array is “broadcast” across the larger array so that they have compatible shapes. Broadcasting provides a means of vectorizing array operations so that looping occurs in C instead of Python. It does this without making needless copies of data and usually leads to efficient algorithm implementations. There are, however, cases where broadcasting is a bad idea because it leads to inefficient use of memory that slows computation. NumPy operations are usually done on pairs of arrays on an element-by-element basis. In the simplest case, the two arrays must have exactly the same shape, as in the following example: >>> import numpy as np >>> a = np.array([1.0, 2.0, 3.0]) >>> b = np.array([2.0, 2.0, 2.0]) >>> a * b array([2., 4., 6.]) NumPy’s broadcasting rule relaxes this constraint when the arrays’ shapes meet certain constraints. The simplest broadcasting example occurs when an array and a scalar value are combined in an operation: >>> import numpy as np >>> a = np.array([1.0, 2.0, 3.0]) >>> b = 2.0 >>> a * b array([2., 4., 6.]) The result is equivalent to the previous example where b was an array. We can think of the scalar b being stretched during the arithmetic operation into an array with the same shape as a. The new elements in b, as shown in Figure 1, are simply copies of the original scalar. The stretching analogy is only conceptual. NumPy is smart enough to use the original scalar value without actually making copies so that broadcasting operations are as memory and computationally efficient as possible. Figure 1# In the simplest example of broadcasting, the scalar b is stretched to become an array of same shape as a so the shapes are compatible for element-by-element multiplication. The code in the second example is more efficient than that in the first because broadcasting moves less memory around during the multiplication (b is a scalar rather than an array). General broadcasting rules# When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing (i.e. rightmost) dimension and works its way left. Two dimensions are compatible when they are equal, or one of them is 1. If these conditions are not met, a could not be broadcast together exception is thrown, indicating that the arrays have incompatible shapes. Input arrays do not need to have the same number of dimensions. The resulting array will have the same number of dimensions as the input array with the greatest number of dimensions, where the size of each dimension is the largest size of the corresponding dimension among the input arrays. Note that missing dimensions are assumed to have size one. For example, if you have a 256x256x3 array of RGB values, and you want to scale each color in the image by a different value, you can multiply the image by a one-dimensional array with 3 values. Lining up the sizes of the trailing axes of these arrays according to the broadcast rules, shows that they are (3d array): 256 x 256 x 3 Scale (1d array): 3 Result (3d array): 256 x 256 x 3 When either of the dimensions compared is one, the other is used. In other words, dimensions with size 1 are stretched or “copied” to match the other. In the following example, both the A and B arrays have axes with length one that are expanded to a larger size during the broadcast (4d array): 8 x 1 x 6 x 1 B (3d array): 7 x 1 x 5 Result (4d array): 8 x 7 x 6 x 5 Broadcastable arrays# A set of arrays is called “broadcastable” to the same shape if the above rules produce a valid result. For example, if a.shape is (5,1), b.shape is (1,6), c.shape is (6,) and d.shape is () so that d is a scalar, then a, b, c, and d are all broadcastable to dimension (5,6); and a acts like a (5,6) array where a[:,0] is broadcast to the other columns, b acts like a (5,6) array where b[0,:] is broadcast to the other rows, c acts like a (1,6) array and therefore like a (5,6) array where c[:] is broadcast to every row, and finally, d acts like a (5,6) array where the single value is repeated. Here are some more (2d array): 5 x 4 B (1d array): 1 Result (2d array): 5 x 4 A (2d array): 5 x 4 B (1d array): 4 Result (2d array): 5 x 4 A (3d array): 15 x 3 x 5 B (3d array): 15 x 1 x 5 Result (3d array): 15 x 3 x 5 A (3d array): 15 x 3 x 5 B (2d array): 3 x 5 Result (3d array): 15 x 3 x 5 A (3d array): 15 x 3 x 5 B (2d array): 3 x 1 Result (3d array): 15 x 3 x 5 Here are examples of shapes that do not (1d array): 3 B (1d array): 4 # trailing dimensions do not match A (2d array): 2 x 1 B (3d array): 8 x 4 x 3 # second from last dimensions mismatched An example of broadcasting when a 1-d array is added to a 2-d array: >>> import numpy as np >>> a = np.array([[ 0.0, 0.0, 0.0], ... [10.0, 10.0, 10.0], ... [20.0, 20.0, 20.0], ... [30.0, 30.0, 30.0]]) >>> b = np.array([1.0, 2.0, 3.0]) >>> a + b array([[ 1., 2., 3.], [11., 12., 13.], [21., 22., 23.], [31., 32., 33.]]) >>> b = np.array([1.0, 2.0, 3.0, 4.0]) >>> a + b Traceback (most recent call last): could not be broadcast together with shapes (4,3) (4,) As shown in Figure 2, b is added to each row of a. In Figure 3, an exception is raised because of the incompatible shapes. Figure 2# A one dimensional array added to a two dimensional array results in broadcasting if number of 1-d array elements matches the number of 2-d array columns. Figure 3# When the trailing dimensions of the arrays are unequal, broadcasting fails because it is impossible to align the values in the rows of the 1st array with the elements of the 2nd arrays for element-by-element addition. Broadcasting provides a convenient way of taking the outer product (or any other outer operation) of two arrays. The following example shows an outer addition operation of two 1-d arrays: >>> import numpy as np >>> a = np.array([0.0, 10.0, 20.0, 30.0]) >>> b = np.array([1.0, 2.0, 3.0]) >>> a[:, np.newaxis] + b array([[ 1., 2., 3.], [11., 12., 13.], [21., 22., 23.], [31., 32., 33.]]) Figure 4# In some cases, broadcasting stretches both arrays to form an output array larger than either of the initial arrays. Here the newaxis index operator inserts a new axis into a, making it a two-dimensional 4x1 array. Combining the 4x1 array with b, which has shape (3,), yields a 4x3 array. A practical quantization# Broadcasting comes up quite often in real world problems. A typical example occurs in the vector quantization (VQ) algorithm used in information theory, classification, and other related areas. The basic operation in VQ finds the closest point in a set of points, called codes in VQ jargon, to a given point, called the observation. In the very simple, two-dimensional case shown below, the values in observation describe the weight and height of an athlete to be classified. The codes represent different classes of athletes. [1] Finding the closest point requires calculating the distance between observation and each of the codes. The shortest distance provides the best match. In this example, codes[0] is the closest class indicating that the athlete is likely a basketball player. >>> from numpy import array, argmin, sqrt, sum >>> observation = array([111.0, 188.0]) >>> codes = array([[102.0, 203.0], ... [132.0, 193.0], ... [45.0, 155.0], ... [57.0, 173.0]]) >>> diff = codes - observation # the broadcast happens here >>> dist = sqrt(sum(diff**2,axis=-1)) >>> argmin(dist) 0 In this example, the observation array is stretched to match the shape of the codes (1d array): 2 Codes (2d array): 4 x 2 Diff (2d array): 4 x 2 Figure 5# The basic operation of vector quantization calculates the distance between an object to be classified, the dark square, and multiple known codes, the gray circles. In this simple case, the codes represent individual classes. More complex cases use multiple codes per class. Typically, a large number of observations, perhaps read from a database, are compared to a set of codes. Consider this (2d array): 10 x 3 Codes (3d array): 5 x 1 x 3 Diff (3d array): 5 x 10 x 3 The three-dimensional array, diff, is a consequence of broadcasting, not a necessity for the calculation. Large data sets will generate a large intermediate array that is computationally inefficient. Instead, if each observation is calculated individually using a Python loop around the code in the two-dimensional example above, a much smaller array is used. Broadcasting is a powerful tool for writing short and usually intuitive code that does its computations very efficiently in C. However, there are cases when broadcasting uses unnecessarily large amounts of memory for a particular algorithm. In these cases, it is better to write the algorithm’s outer loop in Python. This may also produce more readable code, as algorithms that use broadcasting tend to become more difficult to interpret as the number of dimensions in the broadcast increases. Footnotes [1] In this example, weight has more impact on the distance calculation than height because of the larger values. In practice, it is important to normalize the height and weight, often by their standard deviation across the data set, so that both have equal influence on the distance calculation. previous Data types next Copies and views On this page General broadcasting rules Broadcastable arrays A practical quantization\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([1.0, 2.0, 3.0])\n>>> b = np.array([2.0, 2.0, 2.0])\n>>> a * b\narray([2.,  4.,  6.])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([1.0, 2.0, 3.0])\n>>> b = 2.0\n>>> a * b\narray([2.,  4.,  6.])\n```\n\nExample:\n```text\nImage  (3d array): 256 x 256 x 3\nScale  (1d array):             3\nResult (3d array): 256 x 256 x 3\n```\n\nExample:\n```text\nA      (4d array):  8 x 1 x 6 x 1\nB      (3d array):      7 x 1 x 5\nResult (4d array):  8 x 7 x 6 x 5\n```\n\nExample:\n```text\nA      (2d array):  5 x 4\nB      (1d array):      1\nResult (2d array):  5 x 4\n\nA      (2d array):  5 x 4\nB      (1d array):      4\nResult (2d array):  5 x 4\n\nA      (3d array):  15 x 3 x 5\nB      (3d array):  15 x 1 x 5\nResult (3d array):  15 x 3 x 5\n\nA      (3d array):  15 x 3 x 5\nB      (2d array):       3 x 5\nResult (3d array):  15 x 3 x 5\n\nA      (3d array):  15 x 3 x 5\nB      (2d array):       3 x 1\nResult (3d array):  15 x 3 x 5\n```\n\nExample:\n```text\nA      (1d array):  3\nB      (1d array):  4 # trailing dimensions do not match\n\nA      (2d array):      2 x 1\nB      (3d array):  8 x 4 x 3 # second from last dimensions mismatched\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([[ 0.0,  0.0,  0.0],\n...               [10.0, 10.0, 10.0],\n...               [20.0, 20.0, 20.0],\n...               [30.0, 30.0, 30.0]])\n>>> b = np.array([1.0, 2.0, 3.0])\n>>> a + b\narray([[  1.,   2.,   3.],\n        [11.,  12.,  13.],\n        [21.,  22.,  23.],\n        [31.,  32.,  33.]])\n>>> b = np.array([1.0, 2.0, 3.0, 4.0])\n>>> a + b\nTraceback (most recent call last):\nValueError: operands could not be broadcast together with shapes (4,3) (4,)\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([0.0, 10.0, 20.0, 30.0])\n>>> b = np.array([1.0, 2.0, 3.0])\n>>> a[:, np.newaxis] + b\narray([[ 1.,   2.,   3.],\n       [11.,  12.,  13.],\n       [21.,  22.,  23.],\n       [31.,  32.,  33.]])\n```\n\nExample:\n```text\n>>> from numpy import array, argmin, sqrt, sum\n>>> observation = array([111.0, 188.0])\n>>> codes = array([[102.0, 203.0],\n...                [132.0, 193.0],\n...                [45.0, 155.0],\n...                [57.0, 173.0]])\n>>> diff = codes - observation    # the broadcast happens here\n>>> dist = sqrt(sum(diff**2,axis=-1))\n>>> argmin(dist)\n0\n```\n\nExample:\n```text\nObservation      (1d array):      2\nCodes            (2d array):  4 x 2\nDiff             (2d array):  4 x 2\n```\n\nExample:\n```text\nObservation      (2d array):      10 x 3\nCodes            (3d array):   5 x 1 x 3\nDiff             (3d array):  5 x 10 x 3\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.957Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":11,"totalLines":126,"estimatedTokens":3224}}11{"id":"doc-data_types_numpy_v2_5_manual-f77c123f","source":"documentation","title":"Data types — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.types.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Data types Data types# See also Data type objects Array types and conversions between types# NumPy supports a much greater variety of numerical types than Python does. This section shows which are available, and how to modify an array’s data-type. NumPy numerical types are instances of numpy.dtype (data-type) objects, each having unique characteristics. Once you have imported NumPy using import numpy as np you can create arrays with a specified dtype using the scalar types in the numpy top-level API, e.g. numpy.bool, numpy.float32, etc. These scalar types as arguments to the dtype keyword that many numpy functions or methods accept. For example: >>> z = np.arange(3, dtype=np.uint8) >>> z array([0, 1, 2], dtype=uint8) Array types can also be referred to by character codes, for example: >>> np.array([1, 2, 3], dtype='f') array([1., 2., 3.], dtype=float32) >>> np.array([1, 2, 3], dtype='d') array([1., 2., 3.], dtype=float64) See Specifying and constructing data types for more information about specifying and constructing data type objects, including how to specify parameters like the byte order. To determine the type of an array, look at the dtype attribute: >>> z.dtype dtype('uint8') dtype objects also contain information about the type, such as its bit-width and its byte-order. The data type can also be used indirectly to query properties of the type, such as whether it is an integer: >>> d = np.dtype(np.int64) >>> d dtype('int64') >>> np.issubdtype(d, np.integer) True >>> np.issubdtype(d, np.floating) False To convert the type of an array, use the .astype() method. For example: >>> z.astype(np.float64) array([0., 1., 2.]) Note that, above, we could have used the Python float object as a dtype instead of numpy.float64. NumPy knows that int refers to numpy.int_, bool means numpy.bool, that float is numpy.float64 and complex is numpy.complex128. The other data-types do not have Python equivalents. Sometimes the conversion can overflow, for instance when converting a numpy.int64 value 300 to numpy.int8. NumPy follows C casting rules, so that value would overflow and become 44 (300 - 256). If you wish to avoid such overflows, you can specify that the overflow action fail by using same_value for the casting argument (see also Overflow errors): >>> z.astype(np.float64, casting=\"same_value\") array([0., 1., 2.]) Numerical Data Types# There are 5 basic numerical types representing booleans (bool), integers (int), unsigned integers (uint) floating point (float) and complex. A basic numerical type name combined with a numeric bitsize defines a concrete type. The bitsize is the number of bits that are needed to represent a single value in memory. For example, numpy.float64 is a 64 bit floating point data type. Some types, such as numpy.int_ and numpy.intp, have differing bitsizes, dependent on the platforms (e.g. 32-bit vs. 64-bit CPU architectures). This should be taken into account when interfacing with low-level code (such as C or Fortran) where the raw memory is addressed. Data Types for Strings and Bytes# In addition to numerical types, NumPy also supports storing unicode strings, via the numpy.str_ dtype (U character code), null-terminated byte sequences via numpy.bytes_ (S character code), and arbitrary byte sequences, via numpy.void (V character code). All of the above are fixed-width data types. They are parameterized by a width, in either bytes or unicode points, that a single data element in the array must fit inside. This means that storing an array of byte sequences or strings using this dtype requires knowing or calculating the sizes of the longest text or byte sequence in advance. As an example, we can create an array storing the words \"hello\" and \"world!\": >>> np.array([\"hello\", \"world!\"]) array(['hello', 'world!'], dtype='<U6') Here the data type is detected as a unicode string that is a maximum of 6 code points long, enough to store both entries without truncation. If we specify a shorter or longer data type, the string is either truncated or zero-padded to fit in the specified width: >>> np.array([\"hello\", \"world!\"], dtype=\"U5\") array(['hello', 'world'], dtype='<U5') >>> np.array([\"hello\", \"world!\"], dtype=\"U7\") array(['hello', 'world!'], dtype='<U7') We can see the zero-padding a little more clearly if we use the bytes data type and ask NumPy to print out the bytes in the array buffer: >>> np.array([\"hello\", \"world\"], dtype=\"S7\").tobytes() b'hello\\x00\\x00world\\x00\\x00' Each entry is padded with two extra null bytes. Note however that NumPy cannot tell the difference between intentionally stored trailing nulls and padding nulls: >>> x = [b\"hello\\0\\0\", b\"world\"] >>> a = np.array(x, dtype=\"S7\") >>> print(a[0]) b\"hello\" >>> a[0] == x[0] False If you need to store and round-trip any trailing null bytes, you will need to use an unstructured void data type: >>> a = np.array(x, dtype=\"V7\") >>> a array([b'\\x68\\x65\\x6C\\x6C\\x6F\\x00\\x00', b'\\x77\\x6F\\x72\\x6C\\x64\\x00\\x00'], dtype='|V7') >>> a[0] == np.void(x[0]) True Advanced types, not listed above, are explored in section Structured arrays. Relationship Between NumPy Data Types and C Data Types# NumPy provides both bit sized type names and names based on the names of C types. Since the definition of C types are platform dependent, this means the explicitly bit sized should be preferred to avoid platform-dependent behavior in programs using NumPy. To ease integration with C code, where it is more natural to refer to platform-dependent C types, NumPy also provides type aliases that correspond to the C types for the platform. Some dtypes have trailing underscore to avoid confusion with builtin python type names, such as numpy.bool_. Canonical Python API name Python API “C-like” name Actual C type Description numpy.bool or numpy.bool_ N/A bool (defined in stdbool.h) Boolean (True or False) stored as a byte. numpy.int8 numpy.byte signed char Platform-defined integer type with 8 bits. numpy.uint8 numpy.ubyte unsigned char Platform-defined integer type with 8 bits without sign. numpy.int16 numpy.short short Platform-defined integer type with 16 bits. numpy.uint16 numpy.ushort unsigned short Platform-defined integer type with 16 bits without sign. numpy.int32 numpy.intc int Platform-defined integer type with 32 bits. numpy.uint32 numpy.uintc unsigned int Platform-defined integer type with 32 bits without sign. numpy.intp N/A ssize_t/Py_ssize_t Platform-defined integer of size size_t; used e.g. for sizes. numpy.uintp N/A size_t Platform-defined integer type capable of storing the maximum allocation size. N/A 'p' intptr_t Guaranteed to hold pointers. Character code only (Python and C). N/A 'P' uintptr_t Guaranteed to hold pointers without sign. Character code only (Python and C). numpy.int32 or numpy.int64 numpy.long long Platform-defined integer type with at least 32 bits. numpy.uint32 or numpy.uint64 numpy.ulong unsigned long Platform-defined integer type with at least 32 bits without sign. N/A numpy.longlong long long Platform-defined integer type with at least 64 bits. N/A numpy.ulonglong unsigned long long Platform-defined integer type with at least 64 bits without sign. numpy.float16 numpy.half N/A Half precision bit, 5 bits exponent, 10 bits mantissa. numpy.float32 numpy.single float Platform-defined single precision sign bit, 8 bits exponent, 23 bits mantissa. numpy.float64 numpy.double double Platform-defined double precision sign bit, 11 bits exponent, 52 bits mantissa. numpy.float96 or numpy.float128 numpy.longdouble long double Platform-defined extended-precision float. numpy.complex64 numpy.csingle float complex Complex number, represented by two single-precision floats (real and imaginary components). numpy.complex128 numpy.cdouble double complex Complex number, represented by two double-precision floats (real and imaginary components). numpy.complex192 or numpy.complex256 numpy.clongdouble long double complex Complex number, represented by two extended-precision floats (real and imaginary components). Since many of these have platform-dependent definitions, a set of fixed-size aliases are provided (See Sized aliases). Array scalars# NumPy generally returns elements of arrays as array scalars (a scalar with an associated dtype). Array scalars differ from Python scalars, but for the most part they can be used interchangeably (the primary exception is for versions of Python older than v2.x, where integer array scalars cannot act as indices for lists and tuples). There are some exceptions, such as when code requires very specific attributes of a scalar or when it checks specifically whether a value is a Python scalar. Generally, problems are easily fixed by explicitly converting array scalars to Python scalars, using the corresponding Python type function (e.g., int, float, complex, str). The primary advantage of using array scalars is that they preserve the array type (Python may not have a matching scalar type available, e.g. int16). Therefore, the use of array scalars ensures identical behaviour between arrays and scalars, irrespective of whether the value is inside an array or not. NumPy scalars also have many of the same methods arrays do. Overflow errors# The fixed size of NumPy numeric types may cause overflow errors when a value requires more memory than available in the data type. For example, numpy.power evaluates 100 ** 9 correctly for 64-bit integers, but gives -1486618624 (incorrect) for a 32-bit integer. >>> np.power(100, 9, dtype=np.int64) 1000000000000000000 >>> np.power(100, 9, dtype=np.int32) np.int32(-1486618624) The behaviour of NumPy and Python integer types differs significantly for integer overflows and may confuse users expecting NumPy integers to behave similar to Python’s int. Unlike NumPy, the size of Python’s int is flexible. This means Python integers may expand to accommodate any integer and will not overflow. NumPy provides numpy.iinfo and numpy.finfo to verify the minimum or maximum values of NumPy integer and floating point values respectively >>> np.iinfo(int) # Bounds of the default integer on this system. iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64) >>> np.iinfo(np.int32) # Bounds of a 32-bit integer iinfo(min=-2147483648, max=2147483647, dtype=int32) >>> np.iinfo(np.int64) # Bounds of a 64-bit integer iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64) If 64-bit integers are still too small the result may be cast to a floating point number. Floating point numbers offer a larger, but inexact, range of possible values. >>> np.power(100, 100, dtype=np.int64) # Incorrect even with 64-bit int 0 >>> np.power(100, 100, dtype=np.float64) 1e+200 Floating point precision# Many functions in NumPy, especially those in numpy.linalg, involve floating-point arithmetic, which can introduce small inaccuracies due to the way computers represent decimal numbers. For instance, when performing basic arithmetic operations involving floating-point numbers: >>> 0.3 - 0.2 - 0.1 # This does not equal 0 due to floating-point precision -2.7755575615628914e-17 To handle such cases, it’s advisable to use functions like np.isclose to compare values, rather than checking for exact equality: >>> np.isclose(0.3 - 0.2 - 0.1, 0, rtol=1e-05) # Check for closeness to 0 True In this example, np.isclose accounts for the minor inaccuracies that occur in floating-point calculations by applying a relative tolerance, ensuring that results within a small threshold are considered close. For information about precision in calculations, see Floating-Point Arithmetic. Extended precision# Python’s floating-point numbers are usually 64-bit floating-point numbers, nearly equivalent to numpy.float64. In some unusual situations it may be useful to use floating-point numbers with more precision. Whether this is possible in numpy depends on the hardware and on the development , x86 machines provide hardware floating-point with 80-bit precision, and while most C compilers provide this as their long double type, MSVC (standard for Windows builds) makes long double identical to double (64 bits). NumPy makes the compiler’s long double available as numpy.longdouble (and np.clongdouble for the complex numbers). You can find out what your numpy provides with np.finfo(np.longdouble). NumPy does not provide a dtype with more precision than C’s long double; in particular, the 128-bit IEEE quad precision data type (FORTRAN’s REAL*16) is not available. For efficient memory alignment, numpy.longdouble is usually stored padded with zero bits, either to 96 or 128 bits. Which is more efficient depends on hardware and development environment; typically on 32-bit systems they are padded to 96 bits, while on 64-bit systems they are typically padded to 128 bits. np.longdouble is padded to the system default; np.float96 and np.float128 are provided for users who want specific padding. In spite of the names, np.float96 and np.float128 provide only as much precision as np.longdouble, that is, 80 bits on most x86 machines and 64 bits in standard Windows builds. Be warned that even if numpy.longdouble offers more precision than python float, it is easy to lose that extra precision, since python often forces values to pass through float. For example, the % formatting operator requires its arguments to be converted to standard python types, and it is therefore impossible to preserve extended precision even if many decimal places are requested. It can be useful to test your code with the value 1 + np.finfo(np.longdouble).eps. previous Importing data with genfromtxt next Broadcasting On this page Array types and conversions between types Numerical Data Types Data Types for Strings and Bytes Relationship Between NumPy Data Types and C Data Types Array scalars Overflow errors Floating point precision Extended precision\n\nExample:\n```text\n>>> z = np.arange(3, dtype=np.uint8)\n>>> z\narray([0, 1, 2], dtype=uint8)\n```\n\nExample:\n```text\n>>> np.array([1, 2, 3], dtype='f')\narray([1.,  2.,  3.], dtype=float32)\n>>> np.array([1, 2, 3], dtype='d')\narray([1.,  2.,  3.], dtype=float64)\n```\n\nExample:\n```text\n>>> z.dtype\ndtype('uint8')\n```\n\nExample:\n```text\n>>> d = np.dtype(np.int64)\n>>> d\ndtype('int64')\n\n>>> np.issubdtype(d, np.integer)\nTrue\n\n>>> np.issubdtype(d, np.floating)\nFalse\n```\n\nExample:\n```text\n>>> z.astype(np.float64)                 \narray([0.,  1.,  2.])\n```\n\nExample:\n```text\n>>> z.astype(np.float64, casting=\"same_value\")   \narray([0.,  1.,  2.])\n```\n\nExample:\n```text\n>>> np.array([\"hello\", \"world!\"])\narray(['hello', 'world!'], dtype='<U6')\n```\n\nExample:\n```text\n>>> np.array([\"hello\", \"world!\"], dtype=\"U5\")\narray(['hello', 'world'], dtype='<U5')\n>>> np.array([\"hello\", \"world!\"], dtype=\"U7\")\narray(['hello', 'world!'], dtype='<U7')\n```\n\nExample:\n```text\n>>> np.array([\"hello\", \"world\"], dtype=\"S7\").tobytes()\nb'hello\\x00\\x00world\\x00\\x00'\n```\n\nExample:\n```text\n>>> x = [b\"hello\\0\\0\", b\"world\"]\n>>> a = np.array(x, dtype=\"S7\")\n>>> print(a[0])\nb\"hello\"\n>>> a[0] == x[0]\nFalse\n```\n\nExample:\n```text\n>>> a = np.array(x, dtype=\"V7\")\n>>> a\narray([b'\\x68\\x65\\x6C\\x6C\\x6F\\x00\\x00', b'\\x77\\x6F\\x72\\x6C\\x64\\x00\\x00'],\n      dtype='|V7')\n>>> a[0] == np.void(x[0])\nTrue\n```\n\nExample:\n```text\n>>> np.power(100, 9, dtype=np.int64)\n1000000000000000000\n>>> np.power(100, 9, dtype=np.int32)\nnp.int32(-1486618624)\n```\n\nExample:\n```text\n>>> np.iinfo(int) # Bounds of the default integer on this system.\niinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)\n>>> np.iinfo(np.int32) # Bounds of a 32-bit integer\niinfo(min=-2147483648, max=2147483647, dtype=int32)\n>>> np.iinfo(np.int64) # Bounds of a 64-bit integer\niinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)\n```\n\nExample:\n```text\n>>> np.power(100, 100, dtype=np.int64) # Incorrect even with 64-bit int\n0\n>>> np.power(100, 100, dtype=np.float64)\n1e+200\n```\n\nExample:\n```text\n>>> 0.3 - 0.2 - 0.1  # This does not equal 0 due to floating-point precision\n-2.7755575615628914e-17\n```\n\nExample:\n```text\n>>> np.isclose(0.3 - 0.2 - 0.1, 0, rtol=1e-05)  # Check for closeness to 0\nTrue\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.960Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":16,"totalLines":127,"estimatedTokens":4233}}12{"id":"doc-array_creation_numpy_v2_5_manual-85713430","source":"documentation","title":"Array creation — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.creation.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Array creation Array creation# See also Array creation routines Introduction# There are 6 general mechanisms for creating from other Python structures (i.e. lists and tuples) Intrinsic NumPy array creation functions (e.g. arange, ones, zeros, etc.) Replicating, joining, or mutating existing arrays Reading arrays from disk, either from standard or custom formats Creating arrays from raw bytes through the use of strings or buffers Use of special library functions (e.g., random) You can use these methods to create ndarrays or Structured arrays. This document will cover general methods for ndarray creation. 1) Converting Python sequences to NumPy arrays# NumPy arrays can be defined using Python sequences such as lists and tuples. Lists and tuples are defined using [...] and (...), respectively. Lists and tuples can define ndarray list of numbers will create a 1D array, a list of lists will create a 2D array, further nested lists will create higher-dimensional arrays. In general, any array object is called an ndarray in NumPy. >>> import numpy as np >>> a1D = np.array([1, 2, 3, 4]) >>> a2D = np.array([[1, 2], [3, 4]]) >>> a3D = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) When you use numpy.array to define a new array, you should consider the dtype of the elements in the array, which can be specified explicitly. This feature gives you more control over the underlying data structures and how the elements are handled in C/C++ functions. When values do not fit and you are using a dtype, NumPy may raise an error: >>> import numpy as np >>> np.array([127, 128, 129], dtype=np.int8) Traceback (most recent call last): ... integer 128 out of bounds for int8 An 8-bit signed integer represents integers from -128 to 127. Assigning the int8 array to integers outside of this range results in overflow. This feature can often be misunderstood. If you perform calculations with mismatching dtypes, you can get unwanted results, for example: >>> import numpy as np >>> a = np.array([2, 3, 4], dtype=np.uint32) >>> b = np.array([5, 6, 7], dtype=np.uint32) >>> c_unsigned32 = a - b >>> print('unsigned c:', c_unsigned32, c_unsigned32.dtype) unsigned c: [4294967293 4294967293 4294967293] uint32 >>> c_signed32 = a - b.astype(np.int32) >>> print('signed c:', c_signed32, c_signed32.dtype) signed c: [-3 -3 -3] int64 Notice when you perform operations with two arrays of the same , the resulting array is the same type. When you perform operations with different dtype, NumPy will assign a new type that satisfies all of the array elements involved in the computation, here uint32 and int32 can both be represented in as int64. The default NumPy behavior is to create arrays in either 32 or 64-bit signed integers (platform dependent and matches C long size) or double precision floating point numbers. If you expect your integer arrays to be a specific type, then you need to specify the dtype while you create the array. 2) Intrinsic NumPy array creation functions# NumPy has over 40 built-in functions for creating arrays as laid out in the Array creation routines. These functions can be split into roughly three categories, based on the dimension of the array they arrays 2D arrays ndarrays 1 - 1D array creation functions# The 1D array creation functions e.g. numpy.linspace and numpy.arange generally need at least two inputs, start and stop. numpy.arange creates arrays with regularly incrementing values. Check the documentation for complete information and examples. A few examples are shown: >>> import numpy as np >>> np.arange(10) array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> np.arange(2, 10, dtype=np.float64) array([2., 3., 4., 5., 6., 7., 8., 9.]) >>> np.arange(2, 3, 0.1) array([2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9]) practice for numpy.arange is to use integer start, end, and step values. There are some subtleties regarding dtype. In the second example, the dtype is defined. In the third example, the array is dtype=np.float64 to accommodate the step size of 0.1. Due to roundoff error, the stop value is sometimes included. numpy.linspace will create arrays with a specified number of elements, and spaced equally between the specified beginning and end values. For example: >>> import numpy as np >>> np.linspace(1., 4., 6) array([1. , 1.6, 2.2, 2.8, 3.4, 4. ]) The advantage of this creation function is that you guarantee the number of elements and the starting and end point. The previous arange(start, stop, step) will not include the value stop. 2 - 2D array creation functions# The 2D array creation functions e.g. numpy.eye, numpy.diag, and numpy.vander define properties of special matrices represented as 2D arrays. np.eye(n, m) defines a 2D identity matrix. The elements where i=j (row index and column index are equal) are 1 and the rest are 0, as such: >>> import numpy as np >>> np.eye(3) array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) >>> np.eye(3, 5) array([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.]]) numpy.diag can define either a square 2D array with given values along the diagonal or if given a 2D array returns a 1D array that is only the diagonal elements. The two array creation functions can be helpful while doing linear algebra, as such: >>> import numpy as np >>> np.diag([1, 2, 3]) array([[1, 0, 0], [0, 2, 0], [0, 0, 3]]) >>> np.diag([1, 2, 3], 1) array([[0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3], [0, 0, 0, 0]]) >>> a = np.array([[1, 2], [3, 4]]) >>> np.diag(a) array([1, 4]) vander(x, n) defines a Vandermonde matrix as a 2D NumPy array. Each column of the Vandermonde matrix is a decreasing power of the input 1D array or list or tuple, x where the highest polynomial order is n-1. This array creation routine is helpful in generating linear least squares models, as such: >>> import numpy as np >>> np.vander(np.linspace(0, 2, 5), 2) array([[0. , 1. ], [0.5, 1. ], [1. , 1. ], [1.5, 1. ], [2. , 1. ]]) >>> np.vander([1, 2, 3, 4], 2) array([[1, 1], [2, 1], [3, 1], [4, 1]]) >>> np.vander((1, 2, 3, 4), 4) array([[ 1, 1, 1, 1], [ 8, 4, 2, 1], [27, 9, 3, 1], [64, 16, 4, 1]]) 3 - general ndarray creation functions# The ndarray creation functions e.g. numpy.ones, numpy.zeros, and random define arrays based upon the desired shape. The ndarray creation functions can create arrays with any dimension by specifying how many dimensions and length along that dimension in a tuple or list. numpy.zeros will create an array filled with 0 values with the specified shape. The default dtype is float64: >>> import numpy as np >>> np.zeros((2, 3)) array([[0., 0., 0.], [0., 0., 0.]]) >>> np.zeros((2, 3, 2)) array([[[0., 0.], [0., 0.], [0., 0.]], [[0., 0.], [0., 0.], [0., 0.]]]) numpy.ones will create an array filled with 1 values. It is identical to zeros in all other respects as such: >>> import numpy as np >>> np.ones((2, 3)) array([[1., 1., 1.], [1., 1., 1.]]) >>> np.ones((2, 3, 2)) array([[[1., 1.], [1., 1.], [1., 1.]], [[1., 1.], [1., 1.], [1., 1.]]]) The random method of the result of default_rng will create an array filled with random values between 0 and 1. It is included with the numpy.random library. Below, two arrays are created with shapes (2,3) and (2,3,2), respectively. The seed is set to 42 so you can reproduce these pseudorandom numbers: >>> import numpy as np >>> from numpy.random import default_rng >>> default_rng(42).random((2,3)) array([[0.77395605, 0.43887844, 0.85859792], [0.69736803, 0.09417735, 0.97562235]]) >>> default_rng(42).random((2,3,2)) array([[[0.77395605, 0.43887844], [0.85859792, 0.69736803], [0.09417735, 0.97562235]], [[0.7611397 , 0.78606431], [0.12811363, 0.45038594], [0.37079802, 0.92676499]]]) numpy.indices will create a set of arrays (stacked as a one-higher dimensioned array), one per dimension with each representing variation in that dimension: >>> import numpy as np >>> np.indices((3,3)) array([[[0, 0, 0], [1, 1, 1], [2, 2, 2]], [[0, 1, 2], [0, 1, 2], [0, 1, 2]]]) This is particularly useful for evaluating functions of multiple dimensions on a regular grid. 3) Replicating, joining, or mutating existing arrays# Once you have created arrays, you can replicate, join, or mutate those existing arrays to create new arrays. When you assign an array or its elements to a new variable, you have to explicitly numpy.copy the array, otherwise the variable is a view into the original array. Consider the following example: >>> import numpy as np >>> a = np.array([1, 2, 3, 4, 5, 6]) >>> b = a[:2] >>> b += 1 >>> print('a =', a, '; b =', b) a = [2 3 3 4 5 6] ; b = [2 3] In this example, you did not create a new array. You created a variable, b that viewed the first 2 elements of a. When you added 1 to b you would get the same result by adding 1 to a[:2]. If you want to create a new array, use the numpy.copy array creation routine as such: >>> import numpy as np >>> a = np.array([1, 2, 3, 4]) >>> b = a[:2].copy() >>> b += 1 >>> print('a = ', a, 'b = ', b) a = [1 2 3 4] b = [2 3] For more information and examples look at Copies and Views. There are a number of routines to join existing arrays e.g. numpy.vstack, numpy.hstack, and numpy.block. Here is an example of joining four 2-by-2 arrays into a 4-by-4 array using block: >>> import numpy as np >>> A = np.ones((2, 2)) >>> B = np.eye(2, 2) >>> C = np.zeros((2, 2)) >>> D = np.diag((-3, -4)) >>> np.block([[A, B], [C, D]]) array([[ 1., 1., 1., 0.], [ 1., 1., 0., 1.], [ 0., 0., -3., 0.], [ 0., 0., 0., -4.]]) Other routines use similar syntax to join ndarrays. Check the routine’s documentation for further examples and syntax. 4) Reading arrays from disk, either from standard or custom formats# This is the most common case of large array creation. The details depend greatly on the format of data on disk. This section gives general pointers on how to handle various formats. For more detailed examples of IO look at How to Read and Write files. Standard binary formats# Various fields have standard formats for array data. The following lists the ones with known Python libraries to read them and return NumPy arrays (there may be others for which it is possible to read and convert to NumPy arrays so check the last section as well) Examples of formats that cannot be read directly but for which it is not hard to convert are those formats supported by libraries like PIL (able to read and write many image formats such as jpg, png, etc). Common ASCII formats# Delimited files such as comma separated value (csv) and tab separated value (tsv) files are used for programs like Excel and LabView. Python functions can read and parse these files line-by-line. NumPy has two standard routines for importing a file with delimited data numpy.loadtxt and numpy.genfromtxt. These functions have more involved use cases in Reading and writing files. A simple example given a simple.csv: $ cat simple.csv x, y 0, 0 1, 1 2, 4 3, 9 Importing simple.csv is accomplished using numpy.loadtxt: >>> import numpy as np >>> np.loadtxt('simple.csv', delimiter = ',', skiprows = 1) array([[0., 0.], [1., 1.], [2., 4.], [3., 9.]]) More generic ASCII files can be read using scipy.io and Pandas. 5) Creating arrays from raw bytes through the use of strings or buffers# There are a variety of approaches one can use. If the file has a relatively simple format then one can write a simple I/O library and use the NumPy fromfile() function and .tofile() method to read and write NumPy arrays directly (mind your byteorder though!) If a good C or C++ library exists that read the data, one can wrap that library with a variety of techniques though that certainly is much more work and requires significantly more advanced knowledge to interface with C or C++. 6) Use of special library functions (e.g., SciPy, pandas, and OpenCV)# NumPy is the fundamental library for array containers in the Python Scientific Computing stack. Many Python libraries, including SciPy, Pandas, and OpenCV, use NumPy ndarrays as the common format for data exchange, These libraries can create, operate on, and work with NumPy arrays. previous NumPy fundamentals next Indexing on ndarrays On this page Introduction 1) Converting Python sequences to NumPy arrays 2) Intrinsic NumPy array creation functions 1 - 1D array creation functions 2 - 2D array creation functions 3 - general ndarray creation functions 3) Replicating, joining, or mutating existing arrays 4) Reading arrays from disk, either from standard or custom formats Standard binary formats Common ASCII formats 5) Creating arrays from raw bytes through the use of strings or buffers 6) Use of special library functions (e.g., SciPy, pandas, and OpenCV)\n\nExample:\n```text\n>>> import numpy as np\n>>> a1D = np.array([1, 2, 3, 4])\n>>> a2D = np.array([[1, 2], [3, 4]])\n>>> a3D = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.array([127, 128, 129], dtype=np.int8)\nTraceback (most recent call last):\n...\nOverflowError: Python integer 128 out of bounds for int8\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([2, 3, 4], dtype=np.uint32)\n>>> b = np.array([5, 6, 7], dtype=np.uint32)\n>>> c_unsigned32 = a - b\n>>> print('unsigned c:', c_unsigned32, c_unsigned32.dtype)\nunsigned c: [4294967293 4294967293 4294967293] uint32\n>>> c_signed32 = a - b.astype(np.int32)\n>>> print('signed c:', c_signed32, c_signed32.dtype)\nsigned c: [-3 -3 -3] int64\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.arange(10)\narray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n>>> np.arange(2, 10, dtype=np.float64)\narray([2., 3., 4., 5., 6., 7., 8., 9.])\n>>> np.arange(2, 3, 0.1)\narray([2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.linspace(1., 4., 6)\narray([1. ,  1.6,  2.2,  2.8,  3.4,  4. ])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.eye(3)\narray([[1., 0., 0.],\n       [0., 1., 0.],\n       [0., 0., 1.]])\n>>> np.eye(3, 5)\narray([[1., 0., 0., 0., 0.],\n       [0., 1., 0., 0., 0.],\n       [0., 0., 1., 0., 0.]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.diag([1, 2, 3])\narray([[1, 0, 0],\n       [0, 2, 0],\n       [0, 0, 3]])\n>>> np.diag([1, 2, 3], 1)\narray([[0, 1, 0, 0],\n       [0, 0, 2, 0],\n       [0, 0, 0, 3],\n       [0, 0, 0, 0]])\n>>> a = np.array([[1, 2], [3, 4]])\n>>> np.diag(a)\narray([1, 4])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.vander(np.linspace(0, 2, 5), 2)\narray([[0. , 1. ],\n      [0.5, 1. ],\n      [1. , 1. ],\n      [1.5, 1. ],\n      [2. , 1. ]])\n>>> np.vander([1, 2, 3, 4], 2)\narray([[1, 1],\n       [2, 1],\n       [3, 1],\n       [4, 1]])\n>>> np.vander((1, 2, 3, 4), 4)\narray([[ 1,  1,  1,  1],\n       [ 8,  4,  2,  1],\n       [27,  9,  3,  1],\n       [64, 16,  4,  1]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.zeros((2, 3))\narray([[0., 0., 0.],\n       [0., 0., 0.]])\n>>> np.zeros((2, 3, 2))\narray([[[0., 0.],\n        [0., 0.],\n        [0., 0.]],\n\n       [[0., 0.],\n        [0., 0.],\n        [0., 0.]]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.ones((2, 3))\narray([[1., 1., 1.],\n       [1., 1., 1.]])\n>>> np.ones((2, 3, 2))\narray([[[1., 1.],\n        [1., 1.],\n        [1., 1.]],\n\n       [[1., 1.],\n        [1., 1.],\n        [1., 1.]]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.random import default_rng\n>>> default_rng(42).random((2,3))\narray([[0.77395605, 0.43887844, 0.85859792],\n       [0.69736803, 0.09417735, 0.97562235]])\n>>> default_rng(42).random((2,3,2))\narray([[[0.77395605, 0.43887844],\n        [0.85859792, 0.69736803],\n        [0.09417735, 0.97562235]],\n       [[0.7611397 , 0.78606431],\n        [0.12811363, 0.45038594],\n        [0.37079802, 0.92676499]]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.indices((3,3))\narray([[[0, 0, 0],\n        [1, 1, 1],\n        [2, 2, 2]],\n       [[0, 1, 2],\n        [0, 1, 2],\n        [0, 1, 2]]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([1, 2, 3, 4, 5, 6])\n>>> b = a[:2]\n>>> b += 1\n>>> print('a =', a, '; b =', b)\na = [2 3 3 4 5 6] ; b = [2 3]\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([1, 2, 3, 4])\n>>> b = a[:2].copy()\n>>> b += 1\n>>> print('a = ', a, 'b = ', b)\na =  [1 2 3 4] b =  [2 3]\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> A = np.ones((2, 2))\n>>> B = np.eye(2, 2)\n>>> C = np.zeros((2, 2))\n>>> D = np.diag((-3, -4))\n>>> np.block([[A, B], [C, D]])\narray([[ 1.,  1.,  1.,  0.],\n       [ 1.,  1.,  0.,  1.],\n       [ 0.,  0., -3.,  0.],\n       [ 0.,  0.,  0., -4.]])\n```\n\nExample:\n```text\nHDF5: h5py\nFITS: Astropy\n```\n\nExample:\n```text\n$ cat simple.csv\nx, y\n0, 0\n1, 1\n2, 4\n3, 9\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> np.loadtxt('simple.csv', delimiter = ',', skiprows = 1) \narray([[0., 0.],\n       [1., 1.],\n       [2., 4.],\n       [3., 9.]])\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.970Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":18,"totalLines":222,"estimatedTokens":4384}}13{"id":"doc-writing_performant_numpy_code_with_multi_core_cp-1e1a3b0a","source":"documentation","title":"Writing Performant NumPy Code with Multi-Core CPUs — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.performant_code.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide Writing Performant NumPy Code with Multi-Core CPUs Writing Performant NumPy Code with Multi-Core CPUs# Introduction# NumPy is designed for high performance numerical computing in Python by leveraging vectorized operations. However, vectorization does not always fully utilize the capabilities of multi-core processors. To exploit parallelism, additional strategies are necessary. In this section, we cover the following concepts for using multi-core processors in Python Using multi-core processors with Python standard libraries Third party libraries for multi-core processing General concepts for multi-core processors in Python# Multiprocessing# Multiprocessing is a technique that allows the execution of multiple processes simultaneously, each with its own Python interpreter and memory space. As a high-level API, Python provides the concurrent.futures.ProcessPoolExecutor class to facilitate multiprocessing. Firstly, we introduce brief Pros and Cons of # Bypasses the Global Interpreter Lock (GIL), allowing true parallelism Avoids accidental data sharing due to separate memory spaces Cons# Higher memory usage due to separate memory spaces for each process Difficulty in sharing data between processes, requiring serialization (pickling) of objects General tips# The following are general tips for utilizing multiprocessing. Some of these tips are used in the Multiprocessing Example. Reduce creation overhead# Process creation has a higher overhead compared to thread creation due to the need to initialize a new Python interpreter and memory space. To mitigate this overhead, consider the following process pools to reuse existing processes instead of creating new ones for each task. concurrent.futures.ProcessPoolExecutor provides this feature. Select appropriate startup methods. Avoid explicitly selecting fork unless you know that it is safe in your application. Forking a multithreaded process is problematic and can lead to deadlocks or crashes. Python 3.14 changed the default start method on POSIX platforms from fork to forkserver to avoid common multithreaded process incompatibilities. See the multiprocessing documentation for more details. Reduce communication overhead# Inter-process communication (IPC) can introduce significant overhead due to data serialization and transfer between processes. In Python, only picklable objects are allowed to be passed between processes. Due to this limitation, multiprocessing is not suitable for programs which need to serialize data between processes frequently. To reduce communication overhead, consider the following the amount of data transferred between processes. Use shared memory constructs such as multiprocessing.shared_memory, multiprocessing.Array or multiprocessing.Value for large data that needs to be accessed by multiple processes. Balance processing load to ensure that all processes are utilized efficiently and avoid idle time. Pickling considerations# The worker function and its arguments must be picklable when using multiprocessing. This requirement can become a limitation when working with complex data structures or dynamically defined functions. If you encounter pickling-related issues, consider the following your code to use simpler data structures or functions. For example, define worker functions at the top level of a module and avoid lambda or nested functions. Consider third-party libraries such as joblib. joblib’s default backend loky relies on cloudpickle for serialization and can handle a wider range of Python objects than the standard pickle module. See the joblib documentaion on Serialization of un-picklable objects for more details. Multithreading# Multithreading allows multiple threads to run within the same process, sharing the same memory space. Free-threaded Python was introduced experimentally in Python 3.13 and became a supported (non-experimental) feature in Python 3.14. When combined with libraries that are explicitly designed to be thread-safe, this can enable true parallel execution with threads. For details on free-threaded Python builds, see the Python Free-Threading Guide. As a high-level API, Python provides the concurrent.futures.ThreadPoolExecutor class for thread-based parallelism. Python also provides the concurrent.futures.InterpreterPoolExecutor, which uses multiple interpreters running in separate threads and avoids sharing Python objects between them. However, it is not yet available in NumPy. (See gh-24755 for details.) The main pros and cons of multithreading are as # Lower memory usage since threads share the same memory space Easier communication between threads Cons# Possibility of race conditions when mutating shared data simultaneously with reads in other threads Limited performance improvement if using Python libraries are not thread-safe or have limited support for free-threaded Python builds General tips# The following are general tips for utilizing multithreading. For more details on thread safety guarantees for built-in types in Python’s free-threaded build, see the Python documentation on Thread Safety Guarantees. Some of these tips are used in the Multithreading Example. Avoid race conditions# Race conditions occur when multiple threads update shared data simultaneously, leading to unpredictable results. To avoid race conditions, consider the following the amount of shared data between threads by designing your program to use thread-local storage or by passing data explicitly to threads. Prefer immutable NumPy arrays or read-only access patterns when possible, since they reduce the need for explicit synchronization. Use thread-safe data structures or synchronization primitives like locks, semaphores, or condition variables to manage access to shared data. Note that improper use of these synchronization mechanisms can cause deadlocks, so they should be used with care. Avoid CPU oversubscription# Some NumPy operations, such as matrix multiplication and linear algebra functions (See Linear Algebra), may use multiple threads provided by the underlying BLAS library (e.g. OpenBLAS, MKL). If these operations are executed from another thread pool that already uses all available CPU cores, CPU oversubscription can occur. In this situation, both the outer thread pool and the BLAS threads compete for the same CPU resources, which can reduce performance. To avoid CPU oversubscription, consider the following the number of threads in BLAS to 1, for example using threadpoolctl Common tips for both multiprocessing and multithreading# Balance processing load# If the processing load is not evenly distributed among workers, some workers may finish their tasks earlier and remain idle while others are still working. It leads to inefficient use of resources and longer overall execution time. To achieve better load balancing, consider the following dynamic task allocation where tasks are assigned to workers as they become available, rather than pre-allocating tasks. Check chunksize parameter to ensure that tasks are neither too small (causing excessive overhead) nor too large (leading to load imbalance). Determine the correct number of cpus# Pythons provides os.cpu_count and os.process_cpu_count functions to get the number of CPUs in the system and the current process, respectively. However, in some environments (e.g., Docker containers or HPC clusters), this may not reflect the actual number of CPUs available to the process. To get a more accurate count of available CPUs, consider the following joblib.cpu_count(), which takes into account constraints such as CPU affinity settings and Linux CFS scheduler quotas. (See joblib section for more details about joblib.) Using multi-core processors with Python standard libraries# In this section, we demonstrate how to use Python’s standard libraries to leverage multi-core processors with NumPy. As an example, we use Mandelbrot set generation. Mandelbrot set is defined as the set of complex numbers c for which the sequence defined by the iterative function does not diverge to infinity: \\[z_{n+1} = z_n^2 + c, \\quad z_0 = 0\\] If the absolute value of \\(z_n\\) remains bounded (i.e., does not exceed a certain threshold, typically 2 ) after a fixed number of iterations, then c is considered to be in the Mandelbrot set. Following to this definition, we can calculate each point in the complex plane independently, making it suited for parallel computation. The hot colors in the image below represent the number of iterations it took for the sequence to diverge for each point in the complex plane. Multiprocessing Example# The following code demonstrates how to use concurrent.futures.ProcessPoolExecutor to parallelize the Mandelbrot set generation across multiple processes. This example prioritizes clarity over efficiency. In practice, transferring large NumPy arrays between processes can be expensive. Defining shared-memory arrays or creating arrays within each process may be more efficient implementation. from concurrent.futures import ProcessPoolExecutor import numpy as np from numpy.typing import NDArray def mandelbrot_block( [np.complex128], ) -> NDArray[np.int64]: z = np.zeros(c_block.shape, dtype=np.complex128) steps = np.zeros(c_block.shape, dtype=np.int64) for _ in range(max_iter): mask = np.abs(z) <= 2 z[mask] = z[mask] * z[mask] + c_block[mask] steps[mask] += 1 return steps def mandelbrot_set( [np.complex128], , , ) -> NDArray[np.int64]: n_workers = min(n_workers, arr.size) arrs = np.array_split(arr, n_workers) with ProcessPoolExecutor(max_workers=n_workers) as = [ pool.submit(mandelbrot_block, _arr, max_iter) for _arr in arrs ] results = [future.result() for future in futures] return np.concatenate(results) if __name__ == '__main__': xmin, xmax, ymin, ymax = -2.0, 1.0, -1.5, 1.5 nx, ny = 800, 800 max_iter = 10000 n_workers = 10 real = np.linspace(xmin, xmax, nx, dtype=np.float64) imag = np.linspace(ymin, ymax, ny, dtype=np.float64) arr = (real[:, np.newaxis] + 1j * imag[np.newaxis, :]).ravel() mandelbrot_image = mandelbrot_set(arr, max_iter, n_workers) mandelbrot_image = mandelbrot_image.reshape((nx, ny)) Multithreading Example# As in the multiprocessing example, we demonstrate how to use concurrent.futures.ThreadPoolExecutor to parallelize the Mandelbrot set generation across multiple threads. For more detailed explanations and additional examples, see Examples Demonstrating Free-Threaded Python. Setup# Install a free-threaded build Python# Before running the multithreading example, ensure you have a free-threaded build of Python 3.13 or later. About how to install a free-threaded build of Python, please refer to the Installing Free-Threaded Python. According to the Python documentation, there are several ways to verify if your Python build is free-threaded. Run python -VV in your terminal and check free-threading build is shown Check the value of sys._is_gil_enabled() in a Python shell, which should return False. Code Example# The following code demonstrates how to use concurrent.futures.ThreadPoolExecutor to parallelize the Mandelbrot set generation across multiple threads. This implementation shares several arrays between threads. For example, SHARED_readonly_arr is a read-only array that holds the complex numbers to be evaluated, and SHARED_updating_steps is an array that holds the number of iterations for each point. import sys from concurrent.futures import ThreadPoolExecutor import numpy as np def mandelbrot_block(start: int, , ) -> = np.zeros(stop - start, dtype=np.complex128) indexes = slice(start, stop) arr_target = SHARED_readonly_arr[indexes] steps_target = SHARED_updating_steps[indexes] threshold = 2.0 for _ in range(max_iter): mask = np.abs(z_target) <= threshold z_target[mask] = z_target[mask] * z_target[mask] + arr_target[mask] steps_target[mask] += 1 SHARED_updating_steps[indexes] = steps_target return None def mandelbrot_set( , , , ) -> = total_size // n_workers with ThreadPoolExecutor(max_workers=n_workers) as = [ pool.submit( mandelbrot_block, start, min(start + chunksize, total_size), max_iter ) for start in range(0, total_size, chunksize) ] _ = [future.result() for future in futures] if __name__ == '__main__': print(\"Python version is free-threaded:\", not sys._is_gil_enabled()) assert not sys._is_gil_enabled() xmin, xmax, ymin, ymax = -2.0, 1.0, -1.5, 1.5 nx, ny = 800, 800 max_iter = 10000 n_workers = 10 real = np.linspace(xmin, xmax, nx, dtype=np.float64) imag = np.linspace(ymin, ymax, ny, dtype=np.float64) SHARED_readonly_arr = (real[:, np.newaxis] + 1j * imag[np.newaxis, :]).ravel() SHARED_readonly_arr.flags.writeable = False SHARED_updating_steps = np.zeros(SHARED_readonly_arr.shape, dtype=np.int64) mandelbrot_set(SHARED_readonly_arr.size, max_iter, n_workers) mandelbrot_image = SHARED_updating_steps.reshape((nx, ny)) Third Party Libraries for Multi-Core Processing# In many practical scenarios, third-party libraries can provide more convenient and efficient solutions than using Python’s standard libraries. Dask# Dask is an open-source library that provides parallel compuing features not only for a single machine but also for a cluster of machines. It also provides DaskArray which has a similar API to NumPy’s ndarray. If you are familiar with NumPy, you can easily get started with DaskArray. Dask ://docs.dask.org/en/stable/ Dask GitHub /dask joblib# joblib is a library that provides helper functions which make it easy to parallelize tasks. For example, joblib’s default backend loky relies on cloudpickle for serialization and can handle a wider range of Python objects than the standard pickle module. (e.g., lambda functions) joblib.cpu_count() returns the number of CPUs available to the current process, taking into account constraints such as CPU affinity settings and Linux CFS scheduler quotas. This may provide a more accurate value than os.cpu_count and os.process_cpu_count functions in Docker containers and other resource-constrained environments. For more details on joblib, see the following ://joblib.readthedocs.io/en/latest/ joblib GitHub /joblib threadpoolctl# threadpoolctl is a library that provides utilities to control the behavior of thread pools in Python, including other thread pools used by libraries such as BLAS and OpenMP. It allows you to avoid CPU oversubscription when using multiple libraries that utilize threads. For more details on threadpoolctl, see the following GitHub /threadpoolctl previous Interoperability with NumPy next Glossary On this page Introduction General concepts for multi-core processors in Python Multiprocessing Pros Cons General tips Reduce creation overhead Reduce communication overhead Pickling considerations Multithreading Pros Cons General tips Avoid race conditions Avoid CPU oversubscription Common tips for both multiprocessing and multithreading Balance processing load Determine the correct number of cpus Using multi-core processors with Python standard libraries Multiprocessing Example Multithreading Example Setup Install a free-threaded build Python Code Example Third Party Libraries for Multi-Core Processing Dask joblib threadpoolctl\n\nExample:\n```text\nfrom concurrent.futures import ProcessPoolExecutor\n\nimport numpy as np\nfrom numpy.typing import NDArray\n\n\ndef mandelbrot_block(\n    c_block: NDArray[np.complex128], max_iter: int\n) -> NDArray[np.int64]:\n    z = np.zeros(c_block.shape, dtype=np.complex128)\n    steps = np.zeros(c_block.shape, dtype=np.int64)\n\n    for _ in range(max_iter):\n        mask = np.abs(z) <= 2\n        z[mask] = z[mask] * z[mask] + c_block[mask]\n        steps[mask] += 1\n    return steps\n\n\ndef mandelbrot_set(\n    arr: NDArray[np.complex128],\n    max_iter: int,\n    n_workers: int,\n) -> NDArray[np.int64]:\n    n_workers = min(n_workers, arr.size)\n    arrs = np.array_split(arr, n_workers)\n\n    with ProcessPoolExecutor(max_workers=n_workers) as pool:\n        futures = [\n            pool.submit(mandelbrot_block, _arr, max_iter) for _arr in arrs\n        ]\n        results = [future.result() for future in futures]\n\n    return np.concatenate(results)\n\n\nif __name__ == '__main__':\n\n    xmin, xmax, ymin, ymax = -2.0, 1.0, -1.5, 1.5\n    nx, ny = 800, 800\n    max_iter = 10000\n    n_workers = 10\n\n    real = np.linspace(xmin, xmax, nx, dtype=np.float64)\n    imag = np.linspace(ymin, ymax, ny, dtype=np.float64)\n\n    arr = (real[:, np.newaxis] + 1j * imag[np.newaxis, :]).ravel()\n    mandelbrot_image = mandelbrot_set(arr, max_iter, n_workers)\n    mandelbrot_image = mandelbrot_image.reshape((nx, ny))\n```\n\nExample:\n```text\nimport sys\nfrom concurrent.futures import ThreadPoolExecutor\n\nimport numpy as np\n\n\ndef mandelbrot_block(start: int, stop: int, max_iter: int) -> None:\n    z_target = np.zeros(stop - start, dtype=np.complex128)\n\n    indexes = slice(start, stop)\n    arr_target = SHARED_readonly_arr[indexes]\n    steps_target = SHARED_updating_steps[indexes]\n\n    threshold = 2.0\n    for _ in range(max_iter):\n        mask = np.abs(z_target) <= threshold\n        z_target[mask] = z_target[mask] * z_target[mask] + arr_target[mask]\n        steps_target[mask] += 1\n    SHARED_updating_steps[indexes] = steps_target\n    return None\n\n\ndef mandelbrot_set(\n    total_size: int,\n    max_iter: int,\n    n_workers: int,\n) -> None:\n\n    chunksize = total_size // n_workers\n    with ThreadPoolExecutor(max_workers=n_workers) as pool:\n        futures = [\n            pool.submit(\n                mandelbrot_block, start, min(start + chunksize, total_size), max_iter\n            )\n            for start in range(0, total_size, chunksize)\n        ]\n        _ = [future.result() for future in futures]\n\n\nif __name__ == '__main__':\n\n    print(\"Python version is free-threaded:\", not sys._is_gil_enabled())\n    assert not sys._is_gil_enabled()\n\n    xmin, xmax, ymin, ymax = -2.0, 1.0, -1.5, 1.5\n    nx, ny = 800, 800\n    max_iter = 10000\n    n_workers = 10\n\n    real = np.linspace(xmin, xmax, nx, dtype=np.float64)\n    imag = np.linspace(ymin, ymax, ny, dtype=np.float64)\n\n    SHARED_readonly_arr = (real[:, np.newaxis] + 1j * imag[np.newaxis, :]).ravel()\n    SHARED_readonly_arr.flags.writeable = False\n\n    SHARED_updating_steps = np.zeros(SHARED_readonly_arr.shape, dtype=np.int64)\n\n    mandelbrot_set(SHARED_readonly_arr.size, max_iter, n_workers)\n    mandelbrot_image = SHARED_updating_steps.reshape((nx, ny))\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.978Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":119,"estimatedTokens":4738}}14{"id":"doc-numpy_for_matlab_users_numpy_v2_5_manual-8effe165","source":"documentation","title":"NumPy for MATLAB users — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/numpy-for-matlab-users.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy for MATLAB users NumPy for MATLAB users# Introduction# MATLAB® and NumPy have a lot in common, but NumPy was created to work with Python, not to be a MATLAB clone. This guide will help MATLAB users get started with NumPy. Some key differences# In MATLAB, the basic type, even for scalars, is a multidimensional array. Array assignments in MATLAB are stored as 2D arrays of double precision floating point numbers, unless you specify the number of dimensions and type. Operations on the 2D instances of these arrays are modeled on matrix operations in linear algebra. In NumPy, the basic type is a multidimensional array. Array assignments in NumPy are usually stored as n-dimensional arrays with the minimum type required to hold the objects in sequence, unless you specify the number of dimensions and type. NumPy performs operations element-by-element, so multiplying 2D arrays with * is not a matrix multiplication – it’s an element-by-element multiplication. (The @ operator, available since Python 3.5, can be used for conventional matrix multiplication.) MATLAB numbers indices from 1; a(1) is the first element. See note INDEXING NumPy, like Python, numbers indices from 0; a[0] is the first element. MATLAB’s scripting language was created for linear algebra so the syntax for some array manipulations is more compact than NumPy’s. On the other hand, the API for adding GUIs and creating full-fledged applications is more or less an afterthought. NumPy is based on Python, a general-purpose language. The advantage to NumPy is access to Python libraries , Matplotlib, Pandas, OpenCV, and more. In addition, Python is often embedded as a scripting language in other software, allowing NumPy to be used there too. MATLAB array slicing uses pass-by-value semantics, with a lazy copy-on-write scheme to prevent creating copies until they are needed. Slicing operations copy parts of the array. NumPy array slicing uses pass-by-reference, that does not copy the arguments. Slicing operations are views into an array. Rough equivalents# The table below gives rough equivalents for some common MATLAB expressions. These are similar expressions, not equivalents. For details, see the documentation. In the table below, it is assumed that you have executed the following commands in numpy as np from scipy import io, integrate, linalg, signal from scipy.sparse.linalg import cg, eigs Also assume below that if the Notes talk about “matrix” that the arguments are two-dimensional entities. General purpose equivalents# MATLAB NumPy Notes help func info(func) or help(func) or func? (in IPython) get help on the function func which func see note HELP find out where func is defined type func np.source(func) or func?? (in IPython) print source for func (if not a native function) % comment # comment comment a line of code with the text comment for i=1:3 fprintf('%i\\n',i) end for i in range(1, 4): print(i) use a for-loop to print the numbers 1, 2, and 3 using range a && b a and b short-circuiting logical AND operator (Python native operator); scalar arguments only a || b a or b short-circuiting logical OR operator (Python native operator); scalar arguments only >> 4 == 4 ans = 1 >> 4 == 5 ans = 0 >>> 4 == 4 True >>> 4 == 5 False The boolean objects in Python are True and False, as opposed to MATLAB logical types of 1 and 0. a=4 if a==4 fprintf('a = 4\\n') elseif a==5 fprintf('a = 5\\n') end a = 4 if a == ('a = 4') elif a == ('a = 5') create an if-else statement to check if a is 4 or 5 and print result 1*i, 1*j, 1i, 1j 1j complex numbers eps np.finfo(float).eps or np.spacing(1) distance from 1 to the next larger representable real number in double precision load data.mat io.loadmat('data.mat') Load MATLAB variables saved to the file data.mat. (Note: When saving arrays to data.mat in MATLAB/Octave, use a recent binary format. scipy.io.loadmat will create a dictionary with the saved arrays and further information.) ode45 integrate.solve_ivp(f) integrate an ODE with Runge-Kutta 4,5 ode15s integrate.solve_ivp(f, method='BDF') integrate an ODE with BDF method Linear algebra equivalents# MATLAB NumPy Notes ndims(a) np.ndim(a) or a.ndim number of dimensions of array a numel(a) np.size(a) or a.size number of elements of array a size(a) np.shape(a) or a.shape “size” of array a size(a,n) a.shape[n-1] get the number of elements of the n-th dimension of array a. (Note that MATLAB uses 1 based indexing while Python uses 0 based indexing, See note INDEXING) [ 1 2 3; 4 5 6 ] np.array([[1., 2., 3.], [4., 5., 6.]]) define a 2x3 2D array [ a b; c d ] np.block([[a, b], [c, d]]) construct a matrix from blocks a, b, c, and d a(end) a[-1] access last element in MATLAB vector (1xn or nx1) or 1D NumPy array a (length n) a(2,5) a[1, 4] access element in second row, fifth column in 2D array a a(2,:) a[1] or a[1, :] entire second row of 2D array a a(1:5,:) a[0:5] or a[:5] or a[0:5, :] first 5 rows of 2D array a a(end-4:end,:) a[-5:] last 5 rows of 2D array a a(1:3,5:9) a[0:3, ] The first through third rows and fifth through ninth columns of a 2D array, a. a([2,4,5],[1,3]) a[np.ix_([1, 3, 4], [0, 2])] rows 2,4 and 5 and columns 1 and 3. This allows the matrix to be modified, and doesn’t require a regular slice. a(3:2:21,:) a[2:21:2,:] every other row of a, starting with the third and going to the twenty-first a(1:2:end,:) a[::2, :] every other row of a, starting with the first a(end:-1:1,:) or flipud(a) a[::-1,:] a with rows in reverse order a([1:end 1],:) a[np.r_[:len(a),0]] a with copy of the first row appended to the end a.' a.transpose() or a.T transpose of a a' a.conj().transpose() or a.conj().T conjugate transpose of a a * b a @ b matrix multiply a .* b a * b element-wise multiply a./b a/b element-wise divide a.^3 a**3 element-wise exponentiation (a > 0.5) (a > 0.5) matrix whose i,jth element is (a_ij > 0.5). The MATLAB result is an array of logical values 0 and 1. The NumPy result is an array of the boolean values False and True. find(a > 0.5) np.nonzero(a > 0.5) find the indices where (a > 0.5) a(:,find(v > 0.5)) a[:,np.nonzero(v > 0.5)[0]] extract the columns of a where vector v > 0.5 a(:,find(v>0.5)) a[:, v.T > 0.5] extract the columns of a where column vector v > 0.5 a(a<0.5)=0 a[a < 0.5]=0 a with elements less than 0.5 zeroed out a .* (a>0.5) a * (a > 0.5) a with elements less than 0.5 zeroed out a(:) = 3 a[:] = 3 set all values to the same scalar value y=x y = x.copy() NumPy assigns by reference y=x(2,:) y = x[1, :].copy() NumPy slices are by reference y=x(:) y = x.flatten() turn array into vector (note that this forces a copy). To obtain the same data ordering as in MATLAB, use x.flatten('F'). np.arange(1., 11.) or np.r_[1.:11.] or np.r_[1:10:10j] create an increasing vector (see note RANGES) np.arange(10.) or np.r_[:10.] or np.r_[:9:10j] create an increasing vector (see note RANGES) [1:10]' np.arange(1.,11.)[:, np.newaxis] create a column vector zeros(3,4) np.zeros((3, 4)) 3x4 two-dimensional array full of 64-bit floating point zeros zeros(3,4,5) np.zeros((3, 4, 5)) 3x4x5 three-dimensional array full of 64-bit floating point zeros ones(3,4) np.ones((3, 4)) 3x4 two-dimensional array full of 64-bit floating point ones eye(3) np.eye(3) 3x3 identity matrix diag(a) np.diag(a) returns a vector of the diagonal elements of 2D array, a diag(v,0) np.diag(v, 0) returns a square diagonal matrix whose nonzero values are the elements of vector, v rng(42,'twister') rand(3,4) from numpy.random import default_rng rng = default_rng(42) rng.random((3, 4)) or older ((3, 4)) generate a random 3x4 array with default random number generator and seed = 42 linspace(1,3,4) np.linspace(1,3,4) 4 equally spaced samples between 1 and 3, inclusive [x,y]=meshgrid(0:8,0:5) np.mgrid[0:9.,0:6.] or np.meshgrid(r_[0:9.],r_[0:6.]) two 2D of x values, the other of y values ogrid[0:9.,0:6.] or np.ix_(np.r_[0:9.],np.r_[0:6.] the best way to eval functions on a grid [x,y]=meshgrid([1,2,4],[2,4,5]) np.meshgrid([1,2,4],[2,4,5]) np.ix_([1,2,4],[2,4,5]) the best way to eval functions on a grid repmat(a, m, n) np.tile(a, (m, n)) create m by n copies of a [a b] np.concatenate((a,b),1) or np.hstack((a,b)) or np.column_stack((a,b)) or np.c_[a,b] concatenate columns of a and b [a; b] np.concatenate((a,b)) or np.vstack((a,b)) or np.r_[a,b] concatenate rows of a and b max(max(a)) a.max() or np.nanmax(a) maximum element of a (with ndims(a)<=2 for MATLAB, if there are NaN’s, nanmax will ignore these and return largest value) max(a) a.max(0) maximum element of each column of array a max(a,[],2) a.max(1) maximum element of each row of array a max(a,b) np.maximum(a, b) compares a and b element-wise, and returns the maximum value from each pair norm(v) np.sqrt(v @ v) or np.linalg.norm(v) L2 norm of vector v a & b logical_and(a,b) element-by-element AND operator (NumPy ufunc) See note LOGICOPS a | b np.logical_or(a,b) element-by-element OR operator (NumPy ufunc) See note LOGICOPS bitand(a,b) a & b bitwise AND operator (Python native and NumPy ufunc) bitor(a,b) a | b bitwise OR operator (Python native and NumPy ufunc) inv(a) linalg.inv(a) inverse of square 2D array a pinv(a) linalg.pinv(a) pseudo-inverse of 2D array a rank(a) np.linalg.matrix_rank(a) matrix rank of a 2D array a a\\b linalg.solve(a, b) if a is square; linalg.lstsq(a, b) otherwise solution of a x = b for x b/a Solve a.T x.T = b.T instead solution of x a = b for x [U,S,V]=svd(a) U, S, Vh = linalg.svd(a); V = Vh.T singular value decomposition of a chol(a) linalg.cholesky(a) Cholesky factorization of a 2D array [V,D]=eig(a) D,V = linalg.eig(a) eigenvalues \\(\\lambda\\) and eigenvectors \\(v\\) of a, where \\(\\mathbf{a} v = \\lambda v\\) [V,D]=eig(a,b) D,V = linalg.eig(a, b) eigenvalues \\(\\lambda\\) and eigenvectors \\(v\\) of a, b where \\(\\mathbf{a} v = \\lambda \\mathbf{b} v\\) [V,D]=eigs(a,3) D,V = eigs(a, k=3) find the k=3 largest eigenvalues and eigenvectors of 2D array, a [Q,R]=qr(a,0) Q,R = linalg.qr(a) QR decomposition [L,U,P]=lu(a) where a==P'*L*U P,L,U = linalg.lu(a) where a == P@L@U LU decomposition with partial pivoting (note: P(MATLAB) == transpose(P(NumPy))) conjgrad cg conjugate gradients solver fft(a) np.fft.fft(a) Fourier transform of a ifft(a) np.fft.ifft(a) inverse Fourier transform of a sort(a) np.sort(a) or a.sort(axis=0) sort each column of a 2D array, a sort(a, 2) np.sort(a, axis=1) or a.sort(axis=1) sort the each row of 2D array, a [b,I]=sortrows(a,1) I = np.argsort(a[:, 0]); b = a[I,:] save the array a as array b with rows sorted by the first column x = Z\\y x = linalg.lstsq(Z, y) perform a linear regression of the form \\(\\mathbf{Zx}=\\mathbf{y}\\) decimate(x, q) signal.resample(x, np.ceil(len(x)/q)) downsample with low-pass filtering unique(a) np.unique(a) a vector of unique values in array a squeeze(a) a.squeeze() remove singleton dimensions of array a. Note that MATLAB will always return arrays of 2D or higher while NumPy will return arrays of 0D or higher Notes# to a submatrix can be done with lists of indices using the ix_ command. E.g., for 2D array a, one might =[1, 3]; a[np.ix_(ind, ind)] += 100. is no direct equivalent of MATLAB’s which command, but the commands help will usually list the filename where the function is located. Python also has an inspect module (do import inspect) which provides a getfile that often works. uses one based indexing, so the initial element of a sequence has index 1. Python uses zero based indexing, so the initial element of a sequence has index 0. Confusion and flamewars arise because each has advantages and disadvantages. One based indexing is consistent with common human language usage, where the “first” element of a sequence has index 1. Zero based indexing simplifies indexing. See also a text by prof.dr. Edsger W. Dijkstra. MATLAB, can be used as both a range literal and a ‘slice’ index (inside parentheses); however, in Python, constructs like can only be used as a slice index (inside square brackets). Thus the somewhat quirky r_ object was created to allow NumPy to have a similarly terse range construction mechanism. Note that r_ is not called like a function or a constructor, but rather indexed using square brackets, which allows the use of Python’s slice syntax in the arguments. LOGICOPS: & or | in NumPy is bitwise AND/OR, while in MATLAB & and | are logical AND/OR. The two can appear to work the same, but there are important differences. If you would have used MATLAB’s & or | operators, you should use the NumPy ufuncs logical_and/logical_or. The notable differences between MATLAB’s and NumPy’s & and | operators {0,1} ’s output is the bitwise AND of the inputs. MATLAB treats any non-zero value as 1 and returns the logical AND. For example (3 & 4) in NumPy is 0, while in MATLAB both 3 and 4 are considered logical true and (3 & 4) returns 1. ’s & operator is higher precedence than logical operators like < and >; MATLAB’s is the reverse. If you know you have boolean arguments, you can get away with using NumPy’s bitwise operators, but be careful with parentheses, like = (x > 1) & (x < 2). The absence of NumPy operator forms of logical_and and logical_or is an unfortunate consequence of Python’s design. RESHAPE and LINEAR always allows multi-dimensional arrays to be accessed using scalar or linear indices, NumPy does not. Linear indices are common in MATLAB programs, e.g. find() on a matrix returns them, whereas NumPy’s find behaves differently. When converting MATLAB code it might be necessary to first reshape a matrix to a linear sequence, perform some indexing operations and then reshape back. As reshape (usually) produces views onto the same storage, it should be possible to do this fairly efficiently. Note that the scan order used by reshape in NumPy defaults to the ‘C’ order, whereas MATLAB uses the Fortran order. If you are simply converting to a linear sequence and back this doesn’t matter. But if you are converting reshapes from MATLAB code which relies on the scan order, then this MATLAB = reshape(x,3,4); should become z = x.reshape(3,4,order='F').copy() in NumPy. ‘array’ or ‘matrix’? Which should I use?# Historically, NumPy has provided a special matrix type, np.matrix, which is a subclass of ndarray which makes binary operations linear algebra operations. You may see it used in some existing code instead of np.array. So, which one to use? Short answer# Use arrays. They support multidimensional array algebra that is supported in MATLAB They are the standard vector/matrix/tensor type of NumPy. Many NumPy functions return arrays, not matrices. There is a clear distinction between element-wise operations and linear algebra operations. You can have standard vectors or row/column vectors if you like. Until Python 3.5 the only disadvantage of using the array type was that you had to use dot instead of * to multiply (reduce) two tensors (scalar product, matrix vector multiplication etc.). Since Python 3.5 you can use the matrix multiplication @ operator. Given the above, we intend to deprecate matrix eventually. Long answer# NumPy contains both an array class and a matrix class. The array class is intended to be a general-purpose n-dimensional array for many kinds of numerical computing, while matrix is intended to facilitate linear algebra computations specifically. In practice there are only a handful of key differences between the two. Operators * and @, functions dot(), and multiply(): For array, * means element-wise multiplication, while @ means matrix multiplication; they have associated functions multiply() and dot(). For matrix, * means matrix multiplication, and for element-wise multiplication one has to use the multiply() function. Handling of vectors (one-dimensional arrays) For array, the vector shapes 1xN, Nx1, and N are all different things. Operations like A[:,1] return a one-dimensional array of shape N, not a two-dimensional array of shape Nx1. Transpose on a one-dimensional array does nothing. For matrix, one-dimensional arrays are always upconverted to 1xN or Nx1 matrices (row or column vectors). A[:,1] returns a two-dimensional matrix of shape Nx1. Handling of higher-dimensional arrays (ndim > 2) array objects can have number of dimensions > 2; matrix objects always have exactly two dimensions. Convenience attributes array has a .T attribute, which returns the transpose of the data. matrix also has .H, .I, and .A attributes, which return the conjugate transpose, inverse, and asarray() of the matrix, respectively. Convenience constructor The array constructor takes (nested) Python sequences as initializers. As in, array([[1,2,3],[4,5,6]]). The matrix constructor additionally takes a convenient string initializer. As in matrix(\"[1 2 3; 4 5 6]\"). There are pros and cons to using :) Element-wise multiplication is *B. :( You have to remember that matrix multiplication has its own operator, @. :) You can treat one-dimensional arrays as either row or column vectors. A @ v treats v as a column vector, while v @ A treats v as a row vector. This can save you having to type a lot of transposes. :) array is the “default” NumPy type, so it gets the most testing, and is the type most likely to be returned by 3rd party code that uses NumPy. :) Is quite at home handling data of any number of dimensions. :) Closer in semantics to tensor algebra, if you are familiar with that. :) All operations (*, /, +, - etc.) are element-wise. :( Sparse matrices from scipy.sparse do not interact as well with arrays. matrix :\\\\ Behavior is more like that of MATLAB matrices. <:( Maximum of two-dimensional. To hold three-dimensional data you need array or perhaps a Python list of matrix. <:( Minimum of two-dimensional. You cannot have vectors. They must be cast as single-column or single-row matrices. <:( Since array is the default in NumPy, some functions may return an array even if you give them a matrix as an argument. This shouldn’t happen with NumPy functions (if it does it’s a bug), but 3rd party code based on NumPy may not honor type preservation like NumPy does. :) A*B is matrix multiplication, so it looks just like you write it in linear algebra (For Python >= 3.5 plain arrays have the same convenience with the @ operator). <:( Element-wise multiplication requires calling a function, multiply(A,B). <:( The use of operator overloading is a bit illogical: * does not work element-wise but / does. Interaction with scipy.sparse is a bit cleaner. The array is thus much more advisable to use. Indeed, we intend to deprecate matrix eventually. Customizing your environment# In MATLAB the main tool available to you for customizing the environment is to modify the search path with the locations of your favorite functions. You can put such customizations into a startup script that MATLAB will run on startup. NumPy, or rather Python, has similar facilities. To modify your Python search path to include the locations of your own modules, define the PYTHONPATH environment variable. To have a particular script file executed when the interactive Python interpreter is started, define the PYTHONSTARTUP environment variable to contain the name of your startup script. Unlike MATLAB, where anything on your path can be called immediately, with Python you need to first do an ‘import’ statement to make functions in a particular file accessible. For example you might make a startup script that looks like this (Note: this is just an example, not a statement of “best practices”): # Make all numpy available via shorter 'np' prefix import numpy as np # # Make the SciPy linear algebra functions available as linalg.func() # e.g. linalg.lu, linalg.eig (for general l*B@u==A@u solution) from scipy import linalg # # Define a Hermitian function def hermitian(A, **kwargs): return np.conj(A,**kwargs).T # Make a shortcut for hermitian: # hermitian(A) --> H(A) H = hermitian To use the deprecated matrix and other matlib functions: # Make all matlib functions accessible at the top level via M.func() import numpy.matlib as M # Make some matlib functions accessible directly at the top level via, e.g. rand(3,3) from numpy.matlib import matrix,rand,zeros,ones,empty,eye Links# Another somewhat outdated MATLAB/NumPy cross-reference can be found at https://mathesaurus.sf.net/ An extensive list of tools for scientific work with Python can be found in the topical software page. See List of Python for a list of software that use Python as a scripting language MATLAB® and SimuLink® are registered trademarks of The MathWorks, Inc. previous Universal functions (ufunc) basics next NumPy how-tos On this page Introduction Some key differences Rough equivalents General purpose equivalents Linear algebra equivalents Notes ‘array’ or ‘matrix’? Which should I use? Short answer Long answer Customizing your environment Links\n\nExample:\n```text\nimport numpy as np\nfrom scipy import io, integrate, linalg, signal\nfrom scipy.sparse.linalg import cg, eigs\n```\n\nExample:\n```text\nfor i=1:3\n    fprintf('%i\\n',i)\nend\n```\n\nExample:\n```text\nfor i in range(1, 4):\n   print(i)\n```\n\nExample:\n```text\n>> 4 == 4\nans = 1\n>> 4 == 5\nans = 0\n```\n\nExample:\n```text\n>>> 4 == 4\nTrue\n>>> 4 == 5\nFalse\n```\n\nExample:\n```text\na=4\nif a==4\n    fprintf('a = 4\\n')\nelseif a==5\n    fprintf('a = 5\\n')\nend\n```\n\nExample:\n```text\na = 4\nif a == 4:\n    print('a = 4')\nelif a == 5:\n    print('a = 5')\n```\n\nExample:\n```text\nrng(42,'twister')\nrand(3,4)\n```\n\nExample:\n```text\nfrom numpy.random import default_rng\nrng = default_rng(42)\nrng.random((3, 4))\n```\n\nExample:\n```text\n# Make all numpy available via shorter 'np' prefix\nimport numpy as np\n#\n# Make the SciPy linear algebra functions available as linalg.func()\n# e.g. linalg.lu, linalg.eig (for general l*B@u==A@u solution)\nfrom scipy import linalg\n#\n# Define a Hermitian function\ndef hermitian(A, **kwargs):\n    return np.conj(A,**kwargs).T\n# Make a shortcut for hermitian:\n#    hermitian(A) --> H(A)\nH = hermitian\n```\n\nExample:\n```text\n# Make all matlib functions accessible at the top level via M.func()\nimport numpy.matlib as M\n# Make some matlib functions accessible directly at the top level via, e.g. rand(3,3)\nfrom numpy.matlib import matrix,rand,zeros,ones,empty,eye\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.984Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":11,"totalLines":96,"estimatedTokens":5694}}15{"id":"doc-indexing_on_ndarrays_numpy_v2_5_manual-304fbeb1","source":"documentation","title":"Indexing on ndarrays — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.indexing.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Indexing on ndarrays Indexing on ndarrays# See also Indexing routines ndarrays can be indexed using the standard Python x[obj] syntax, where x is the array and obj the selection. There are different kinds of indexing available depending on indexing, advanced indexing and field access. Most of the following examples show the use of indexing when referencing data in an array. The examples work just as well when assigning to an array. See Assigning values to indexed arrays for specific examples and explanations on how assignments work. Note that in Python, x[(exp1, exp2, ..., expN)] is equivalent to x[exp1, exp2, ..., expN]; the latter is just syntactic sugar for the former. Basic indexing# Single element indexing# Single element indexing works exactly like that for other standard Python sequences. It is 0-based, and accepts negative indices for indexing from the end of the array. >>> x = np.arange(10) >>> x[2] 2 >>> x[-2] 8 It is not necessary to separate each dimension’s index into its own set of square brackets. >>> x = x.reshape((2, 5)) # now x is 2-dimensional >>> x[1, 3] 8 >>> x[1, -1] 9 Note that if one indexes a multidimensional array with fewer indices than dimensions, one gets a subdimensional array. For example: >>> x[0] array([0, 1, 2, 3, 4]) That is, each index specified selects the array corresponding to the rest of the dimensions selected. In the above example, choosing 0 means that the remaining dimension of length 5 is being left unspecified, and that what is returned is an array of that dimensionality and size. It must be noted that the returned array is a view, i.e., it is not a copy of the original, but points to the same values in memory as does the original array. In this case, the 1-D array at the first position (0) is returned. So using a single index on the returned array, results in a single element being returned. That is: >>> x[0][2] 2 So note that x[0, 2] == x[0][2] though the second case is more inefficient as a new temporary array is created after the first index that is subsequently indexed by 2. Note NumPy uses C-order indexing. That means that the last index usually represents the most rapidly changing memory location, unlike Fortran or IDL, where the first index represents the most rapidly changing location in memory. This difference represents a great potential for confusion. Slicing and striding# Basic slicing extends Python’s basic concept of slicing to N dimensions. Basic slicing occurs when obj is a slice object (constructed by :step notation inside of brackets), an integer, or a tuple of slice objects and integers. Ellipsis and newaxis objects can be interspersed with these as well. The simplest case of indexing with N integers returns an array scalar representing the corresponding item. As in Python, all indices are the i-th index \\(n_i\\), the valid range is \\(0 \\le n_i < d_i\\) where \\(d_i\\) is the i-th element of the shape of the array. Negative indices are interpreted as counting from the end of the array (i.e., if \\(n_i < 0\\), it means \\(n_i + d_i\\)). All arrays generated by basic slicing are always views of the original array. Note NumPy slicing creates a view instead of a copy as in the case of built-in Python sequences such as string, tuple and list. Care must be taken when extracting a small portion from a large array which becomes useless after the extraction, because the small portion extracted contains a reference to the large original array whose memory will not be released until all arrays derived from it are garbage-collected. In such cases an explicit copy() is recommended. The standard rules of sequence slicing apply to basic slicing on a per-dimension basis (including using a step index). Some useful concepts to remember basic slice syntax is :k where i is the starting index, j is the stopping index, and k is the step (\\(k\\neq0\\)). This selects the m elements (in the corresponding dimension) with index values i, i + k, …, i + (m - 1) k where \\(m = q + (r\\neq0)\\) and q and r are the quotient and remainder obtained by dividing j - i by - i = q k + r, so that i + (m - 1) k < j. For example: >>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> x[1:7:2] array([1, 3, 5]) Negative i and j are interpreted as n + i and n + j where n is the number of elements in the corresponding dimension. Negative k makes stepping go towards smaller indices. From the above example: >>> x[-2:10] array([8, 9]) >>> x[-3:3:-1] array([7, 6, 5, 4]) Assume n is the number of elements in the dimension being sliced. Then, if i is not given it defaults to 0 for k > 0 and n - 1 for k < 0 . If j is not given it defaults to n for k > 0 and -n-1 for k < 0 . If k is not given it defaults to 1. Note that :: is the same means select all indices along this axis. From the above example: >>> x[5:] array([5, 6, 7, 8, 9]) If the number of objects in the selection tuple is less than N, assumed for any subsequent dimensions. For example: >>> x = np.array([[[1],[2],[3]], [[4],[5],[6]]]) >>> x.shape (2, 3, 1) >>> x[1:2] array([[[4], [5], [6]]]) An integer, i, returns the same values as +1 except the dimensionality of the returned object is reduced by 1. In particular, a selection tuple with the p-th element an integer (and all other entries :) returns the corresponding sub-array with dimension N - 1. If N = 1 then the returned object is an array scalar. These objects are explained in Scalars. If the selection tuple has all the p-th entry which is a slice object :k, then the returned array has dimension N formed by stacking, along the p-th axis, the sub-arrays returned by integer indexing of elements i, i+k, …, i + (m - 1) k < j. Basic slicing with more than one in the slicing tuple, acts like repeated application of slicing using a single , where the are successively taken (with all other replaced by :). Thus, x[ind1, ..., ind2,:] acts like x[ind1][..., ind2, :] under basic slicing. Warning The above is not true for advanced indexing. You may use slicing to set values in the array, but (unlike lists) you can never grow the array. The size of the value to be set in x[obj] = value must be (broadcastable to) the same shape as x[obj]. A slicing tuple can always be constructed as obj and used in the x[obj] notation. Slice objects can be used in the construction in place of the [start:stop:step] notation. For example, x[1:10:5, ::-1] can also be implemented as obj = (slice(1, 10, 5), slice(None, None, -1)); x[obj] . This can be useful for constructing generic code that works on arrays of arbitrary dimensions. See Dealing with variable numbers of indices within programs for more information. Dimensional indexing tools# There are some tools to facilitate the easy matching of array shapes with expressions and in assignments. Ellipsis expands to the number needed for the selection tuple to index all dimensions. In most cases, this means that the length of the expanded selection tuple is x.ndim. There may only be a single ellipsis present. From the above example: >>> x[..., 0] array([[1, 2, 3], [4, 5, 6]]) This is equivalent to: >>> x[:, :, 0] array([[1, 2, 3], [4, 5, 6]]) Each newaxis object in the selection tuple serves to expand the dimensions of the resulting selection by one unit-length dimension. The added dimension is the position of the newaxis object in the selection tuple. newaxis is an alias for None, and None can be used in place of this with the same result. From the above example: >>> x[:, np.newaxis, :, :].shape (2, 1, 3, 1) >>> x[:, None, :, :].shape (2, 1, 3, 1) This can be handy to combine two arrays in a way that otherwise would require explicit reshaping operations. For example: >>> x = np.arange(5) >>> x[:, np.newaxis] + x[np.newaxis, :] array([[0, 1, 2, 3, 4], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8]]) Advanced indexing# Advanced indexing is triggered when the selection object, obj, is a non-tuple sequence object, an ndarray (of data type integer or bool), or a tuple with at least one sequence object or ndarray (of data type integer or bool). There are two types of advanced and Boolean. Advanced indexing always returns a copy of the data (contrast with basic slicing that returns a view). Warning The definition of advanced indexing means that x[(1, 2, 3),] is fundamentally different than x[(1, 2, 3)]. The latter is equivalent to x[1, 2, 3] which will trigger basic selection while the former will trigger advanced indexing. Be sure to understand why this occurs. Integer array indexing# Integer array indexing allows selection of arbitrary items in the array based on their N-dimensional index. Each integer array represents a number of indices into that dimension. Negative values are permitted in the index arrays and work as they do with single indices or slices: >>> x = np.arange(10, 1, -1) >>> x array([10, 9, 8, 7, 6, 5, 4, 3, 2]) >>> x[np.array([3, 3, 1, 8])] array([7, 7, 9, 2]) >>> x[np.array([3, 3, -3, 8])] array([7, 7, 4, 2]) If the index values are out of bounds then an IndexError is thrown: >>> x = np.array([[1, 2], [3, 4], [5, 6]]) >>> x[np.array([1, -1])] array([[3, 4], [5, 6]]) >>> x[np.array([3, 4])] Traceback (most recent call last): ... 3 is out of bounds for axis 0 with size 3 When the index consists of as many integer arrays as dimensions of the array being indexed, the indexing is straightforward, but different from slicing. Advanced indices always are broadcast and iterated as [i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M], ..., ind_N[i_1, ..., i_M]] Note that the resulting shape is identical to the (broadcast) indexing array shapes ind_1, ..., ind_N. If the indices cannot be broadcast to the same shape, an exception arrays could not be broadcast together with shapes... is raised. Indexing with multidimensional index arrays tend to be more unusual uses, but they are permitted, and they are useful for some problems. We’ll start with the simplest multidimensional case: >>> y = np.arange(35).reshape(5, 7) >>> y array([[ 0, 1, 2, 3, 4, 5, 6], [ 7, 8, 9, 10, 11, 12, 13], [14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27], [28, 29, 30, 31, 32, 33, 34]]) >>> y[np.array([0, 2, 4]), np.array([0, 1, 2])] array([ 0, 15, 30]) In this case, if the index arrays have a matching shape, and there is an index array for each dimension of the array being indexed, the resultant array has the same shape as the index arrays, and the values correspond to the index set for each position in the index arrays. In this example, the first index value is 0 for both index arrays, and thus the first value of the resultant array is y[0, 0]. The next value is y[2, 1], and the last is y[4, 2]. If the index arrays do not have the same shape, there is an attempt to broadcast them to the same shape. If they cannot be broadcast to the same shape, an exception is raised: >>> y[np.array([0, 2, 4]), np.array([0, 1])] Traceback (most recent call last): ... arrays could not be broadcast together with shapes (3,) (2,) The broadcasting mechanism permits index arrays to be combined with scalars for other indices. The effect is that the scalar value is used for all the corresponding values of the index arrays: >>> y[np.array([0, 2, 4]), 1] array([ 1, 15, 29]) Jumping to the next level of complexity, it is possible to only partially index an array with index arrays. It takes a bit of thought to understand what happens in such cases. For example if we just use one index array with y: >>> y[np.array([0, 2, 4])] array([[ 0, 1, 2, 3, 4, 5, 6], [14, 15, 16, 17, 18, 19, 20], [28, 29, 30, 31, 32, 33, 34]]) It results in the construction of a new array where each value of the index array selects one row from the array being indexed and the resultant array has the resulting shape (number of index elements, size of row). In general, the shape of the resultant array will be the concatenation of the shape of the index array (or the shape that all the index arrays were broadcast to) with the shape of any unused dimensions (those not indexed) in the array being indexed. Example From each row, a specific element should be selected. The row index is just [0, 1, 2] and the column index specifies the element to choose for the corresponding row, here [0, 1, 0]. Using both together the task can be solved using advanced indexing: >>> x = np.array([[1, 2], [3, 4], [5, 6]]) >>> x[[0, 1, 2], [0, 1, 0]] array([1, 4, 5]) To achieve a behaviour similar to the basic slicing above, broadcasting can be used. The function ix_ can help with this broadcasting. This is best understood with an example. Example From a 4x3 array the corner elements should be selected using advanced indexing. Thus all elements for which the column is one of [0, 2] and the row is one of [0, 3] need to be selected. To use advanced indexing one needs to select all elements explicitly. Using the method explained previously one could write: >>> x = np.array([[ 0, 1, 2], ... [ 3, 4, 5], ... [ 6, 7, 8], ... [ 9, 10, 11]]) >>> rows = np.array([[0, 0], ... [3, 3]], dtype=np.intp) >>> columns = np.array([[0, 2], ... [0, 2]], dtype=np.intp) >>> x[rows, columns] array([[ 0, 2], [ 9, 11]]) However, since the indexing arrays above just repeat themselves, broadcasting can be used (compare operations such as rows[:, np.newaxis] + columns) to simplify this: >>> rows = np.array([0, 3], dtype=np.intp) >>> columns = np.array([0, 2], dtype=np.intp) >>> rows[:, np.newaxis] array([[0], [3]]) >>> x[rows[:, np.newaxis], columns] array([[ 0, 2], [ 9, 11]]) This broadcasting can also be achieved using the function ix_: >>> x[np.ix_(rows, columns)] array([[ 0, 2], [ 9, 11]]) Note that without the np.ix_ call, only the diagonal elements would be selected: >>> x[rows, columns] array([ 0, 11]) This difference is the most important thing to remember about indexing with multiple advanced indices. Example A real-life example of where advanced indexing may be useful is for a color lookup table where we want to map the values of an image into RGB triples for display. The lookup table could have a shape (nlookup, 3). Indexing such an array with an image with shape (ny, nx) with dtype=np.uint8 (or any integer type so long as values are with the bounds of the lookup table) will result in an array of shape (ny, nx, 3) where a triple of RGB values is associated with each pixel location. Boolean array indexing# This advanced indexing occurs when obj is an array object of Boolean type, such as may be returned from comparison operators. A single boolean index array is practically identical to x[obj.nonzero()] where, as described above, obj.nonzero() returns a tuple (of length obj.ndim) of integer index arrays showing the True elements of obj. However, it is faster when obj.shape == x.shape. If obj.ndim == x.ndim, x[obj] returns a 1-dimensional array filled with the elements of x corresponding to the True values of obj. The search order will be row-major, C-style. An index error will be raised if the shape of obj does not match the corresponding dimensions of x, regardless of whether those values are True or False. A common use case for this is filtering for desired element values. For example, one may wish to select all entries from an array which are not numpy.nan: >>> x = np.array([[1., 2.], [np.nan, 3.], [np.nan, np.nan]]) >>> x[~np.isnan(x)] array([1., 2., 3.]) Or wish to add a constant to all negative elements: >>> x = np.array([1., -1., -2., 3]) >>> x[x < 0] += 20 >>> x array([ 1., 19., 18., 3.]) In general if an index includes a Boolean array, the result will be identical to inserting obj.nonzero() into the same position and using the integer array indexing mechanism described above. x[ind_1, boolean_array, ind_2] is equivalent to x[(ind_1,) + boolean_array.nonzero() + (ind_2,)]. If there is only one Boolean array and no integer indexing array present, this is straightforward. Care must only be taken to make sure that the boolean index has exactly as many dimensions as it is supposed to work with. In general, when the boolean array has fewer dimensions than the array being indexed, this is equivalent to x[b, ...], which means x is indexed by b followed by as are needed to fill out the rank of x. Thus the shape of the result is one dimension containing the number of True elements of the boolean array, followed by the remaining dimensions of the array being indexed: >>> x = np.arange(35).reshape(5, 7) >>> b = x > 20 >>> b[:, 5] array([False, False, False, True, True]) >>> x[b[:, 5]] array([[21, 22, 23, 24, 25, 26, 27], [28, 29, 30, 31, 32, 33, 34]]) Here the 4th and 5th rows are selected from the indexed array and combined to make a 2-D array. Example From an array, select all rows which sum up to less or equal two: >>> x = np.array([[0, 1], [1, 1], [2, 2]]) >>> rowsum = x.sum(-1) >>> x[rowsum <= 2, :] array([[0, 1], [1, 1]]) Combining multiple Boolean indexing arrays or a Boolean with an integer indexing array can best be understood with the obj.nonzero() analogy. The function ix_ also supports boolean arrays and will work without any surprises. Example Use boolean indexing to select all rows adding up to an even number. At the same time columns 0 and 2 should be selected with an advanced integer index. Using the ix_ function this can be done with: >>> x = np.array([[ 0, 1, 2], ... [ 3, 4, 5], ... [ 6, 7, 8], ... [ 9, 10, 11]]) >>> rows = (x.sum(-1) % 2) == 0 >>> rows array([False, True, False, True]) >>> columns = [0, 2] >>> x[np.ix_(rows, columns)] array([[ 3, 5], [ 9, 11]]) Without the np.ix_ call, only the diagonal elements would be selected. Or without np.ix_ (compare the integer array examples): >>> rows = rows.nonzero()[0] >>> x[rows[:, np.newaxis], columns] array([[ 3, 5], [ 9, 11]]) Example Use a 2-D boolean array of shape (2, 3) with four True elements to select rows from a 3-D array of shape (2, 3, 5) results in a 2-D result of shape (4, 5): >>> x = np.arange(30).reshape(2, 3, 5) >>> x array([[[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]], [[15, 16, 17, 18, 19], [20, 21, 22, 23, 24], [25, 26, 27, 28, 29]]]) >>> b = np.array([[True, True, False], [False, True, True]]) >>> x[b] array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [20, 21, 22, 23, 24], [25, 26, 27, 28, 29]]) Combining advanced and basic indexing# When there is at least one slice (:), ellipsis (...) or newaxis in the index (or the array has more dimensions than there are advanced indices), then the behaviour can be more complicated. It is like concatenating the indexing result for each advanced index element. In the simplest case, there is only a single advanced index combined with a slice. For example: >>> y = np.arange(35).reshape(5,7) >>> y[np.array([0, 2, 4]), ] array([[ 1, 2], [15, 16], [29, 30]]) In effect, the slice and index array operation are independent. The slice operation extracts columns with index 1 and 2, (i.e. the 2nd and 3rd columns), followed by the index array operation which extracts rows with index 0, 2 and 4 (i.e the first, third and fifth rows). This is equivalent to: >>> y[:, ][np.array([0, 2, 4]), :] array([[ 1, 2], [15, 16], [29, 30]]) A single advanced index can, for example, replace a slice and the result array will be the same. However, it is a copy and may have a different memory layout. A slice is preferable when it is possible. For example: >>> x = np.array([[ 0, 1, 2], ... [ 3, 4, 5], ... [ 6, 7, 8], ... [ 9, 10, 11]]) >>> x[1:2, ] array([[4, 5]]) >>> x[1:2, [1, 2]] array([[4, 5]]) The easiest way to understand a combination of multiple advanced indices may be to think in terms of the resulting shape. There are two parts to the indexing operation, the subspace defined by the basic indexing (excluding integers) and the subspace from the advanced indexing part. Two cases of index combination need to be advanced indices are separated by a slice, Ellipsis or newaxis. For example x[arr1, :, arr2]. The advanced indices are all next to each other. For example x[..., arr1, arr2, :] but not x[arr1, :, 1] since 1 is an advanced index in this regard. In the first case, the dimensions resulting from the advanced indexing operation come first in the result array, and the subspace dimensions after that. In the second case, the dimensions from the advanced indexing operations are inserted into the result array at the same spot as they were in the initial array (the latter logic is what makes simple advanced indexing behave just like slicing). Example Suppose x.shape is (10, 20, 30) and ind is a (2, 5, 2)-shaped indexing intp array, then result = x[..., ind, :] has shape (10, 2, 5, 2, 30) because the (20,)-shaped subspace has been replaced with a (2, 5, 2)-shaped broadcasted indexing subspace. If we let i, j, k loop over the (2, 5, 2)-shaped subspace then result[..., i, j, k, :] = x[..., ind[i, j, k], :]. This example produces the same result as x.take(ind, axis=-2). Example Let x.shape be (10, 20, 30, 40, 50) and suppose ind_1 and ind_2 can be broadcast to the shape (2, 3, 4). Then x[:, ind_1, ind_2] has shape (10, 2, 3, 4, 40, 50) because the (20, 30)-shaped subspace from X has been replaced with the (2, 3, 4) subspace from the indices. However, x[:, ind_1, :, ind_2] has shape (2, 3, 4, 10, 30, 50) because there is no unambiguous place to drop in the indexing subspace, thus it is tacked-on to the beginning. It is always possible to use .transpose() to move the subspace anywhere desired. Note that this example cannot be replicated using take. Example Slicing can be combined with broadcasted boolean indices: >>> x = np.arange(35).reshape(5, 7) >>> b = x > 20 >>> b array([[False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [ True, True, True, True, True, True, True], [ True, True, True, True, True, True, True]]) >>> x[b[:, 5], ] array([[22, 23], [29, 30]]) Field access# See also Structured arrays If the ndarray object is a structured array the fields of the array can be accessed by indexing the array with strings, dictionary-like. Indexing x['field-name'] returns a new view to the array, which is of the same shape as x (except when the field is a sub-array) but of data type x.dtype['field-name'] and contains only the part of the data in the specified field. Also, record array scalars can be “indexed” this way. Indexing into a structured array can also be done with a list of field names, e.g. x[['field-name1', 'field-name2']]. As of NumPy 1.16, this returns a view containing only those fields. In older versions of NumPy, it returned a copy. See the user guide section on Structured arrays for more information on multifield indexing. If the accessed field is a sub-array, the dimensions of the sub-array are appended to the shape of the result. For example: >>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))]) >>> x['a'].shape (2, 2) >>> x['a'].dtype dtype('int32') >>> x['b'].shape (2, 2, 3, 3) >>> x['b'].dtype dtype('float64') Flat iterator indexing# x.flat returns an iterator that will iterate over the entire array (in C-contiguous style with the last index varying the fastest). This iterator object can also be indexed using basic slicing or advanced indexing as long as the selection object is not a tuple. This should be clear from the fact that x.flat is a 1-dimensional view. It can be used for integer indexing with 1-dimensional C-style-flat indices. The shape of any returned array is therefore the shape of the integer indexing object. Assigning values to indexed arrays# As mentioned, one can select a subset of an array to assign to using a single index, slices, and index and mask arrays. The value being assigned to the indexed array must be shape consistent (the same shape or broadcastable to the shape the index produces). For example, it is permitted to assign a constant to a slice: >>> x = np.arange(10) >>> x[2:7] = 1 or an array of the right size: >>> x[2:7] = np.arange(5) Note that assignments may result in changes if assigning higher types to lower types (like floats to ints) or even exceptions (assigning complex to floats or ints): >>> x[1] = 1.2 >>> x[1] 1 >>> x[1] = 1.2j Traceback (most recent call last): ... 't convert complex to int Unlike some of the references (such as array and mask indices) assignments are always made to the original data in the array (indeed, nothing else would make sense!). Note though, that some actions may not work as one may naively expect. This particular example is often surprising to people: >>> x = np.arange(0, 50, 10) >>> x array([ 0, 10, 20, 30, 40]) >>> x[np.array([1, 1, 3, 1])] += 1 >>> x array([ 0, 11, 20, 31, 40]) Where people expect that the 1st location will be incremented by 3. In fact, it will only be incremented by 1. The reason is that a new array is extracted from the original (as a temporary) containing the values at 1, 1, 3, 1, then the value 1 is added to the temporary, and then the temporary is assigned back to the original array. Thus the value of the array at x[1] + 1 is assigned to x[1] three times, rather than being incremented 3 times. Dealing with variable numbers of indices within programs# The indexing syntax is very powerful but limiting when dealing with a variable number of indices. For example, if you want to write a function that can handle arguments with various numbers of dimensions without having to write special case code for each number of possible dimensions, how can that be done? If one supplies to the index a tuple, the tuple will be interpreted as a list of indices. For example: >>> z = np.arange(81).reshape(3, 3, 3, 3) >>> indices = (1, 1, 1, 1) >>> z[indices] 40 So one can use code to construct tuples of any number of indices and then use these within an index. Slices can be specified within programs by using the slice() function in Python. For example: >>> indices = (1, 1, 1, slice(0, 2)) # same as [1, 1, 1, ] >>> z[indices] array([39, 40]) Likewise, ellipsis can be specified by code by using the Ellipsis object: >>> indices = (1, Ellipsis, 1) # same as [1, ..., 1] >>> z[indices] array([[28, 31, 34], [37, 40, 43], [46, 49, 52]]) For this reason, it is possible to use the output from the np.nonzero() function directly as an index since it always returns a tuple of index arrays. Because of the special treatment of tuples, they are not automatically converted to an array as a list would be. As an example: >>> z[[1, 1, 1, 1]] # produces a large array array([[[[27, 28, 29], [30, 31, 32], ... >>> z[(1, 1, 1, 1)] # returns a single value 40 Detailed notes# These are some detailed notes, which are not of importance for day to day indexing (in no particular order): The native NumPy indexing type is intp and may differ from the default integer array type. intp is the smallest data type sufficient to safely index any array; for advanced indexing it may be faster than other types. For advanced assignments, there is in general no guarantee for the iteration order. This means that if an element is set more than once, it is not possible to predict the final result. An empty (tuple) index is a full scalar index into a zero-dimensional array. x[()] returns a scalar if x is zero-dimensional and a view otherwise. On the other hand, x[...] always returns a view. If a zero-dimensional array is present in the index and it is a full integer index the result will be a scalar and not a zero-dimensional array. (Advanced indexing is not triggered.) When an ellipsis (...) is present but has no size (i.e. replaces zero :) the result will still always be an array. A view if no advanced index is present, otherwise a copy. The nonzero equivalence for Boolean arrays does not hold for zero dimensional boolean arrays. When the result of an advanced indexing operation has no elements but an individual index is out of bounds, whether or not an IndexError is raised is undefined (e.g. x[[], [123]] with 123 being out of bounds). When a casting error occurs during assignment (for example updating a numerical array using a sequence of strings), the array being assigned to may end up in an unpredictable partially updated state. However, if any other error (such as an out of bounds index) occurs, the array will remain unchanged. The memory layout of an advanced indexing result is optimized for each indexing operation and no particular memory order can be assumed. When using a subclass (especially one which manipulates its shape), the default ndarray.__setitem__ behaviour will call __getitem__ for basic indexing but not for advanced indexing. For such a subclass it may be preferable to call ndarray.__setitem__ with a base class ndarray view on the data. This must be done if the subclasses __getitem__ does not return views. previous Array creation next I/O with NumPy On this page Basic indexing Single element indexing Slicing and striding Dimensional indexing tools Advanced indexing Integer array indexing Boolean array indexing Combining advanced and basic indexing Field access Flat iterator indexing Assigning values to indexed arrays Dealing with variable numbers of indices within programs Detailed notes\n\nExample:\n```text\n>>> x = np.arange(10)\n>>> x[2]\n2\n>>> x[-2]\n8\n```\n\nExample:\n```text\n>>> x = x.reshape((2, 5))  # now x is 2-dimensional\n>>> x[1, 3]\n8\n>>> x[1, -1]\n9\n```\n\nExample:\n```text\n>>> x[0]\narray([0, 1, 2, 3, 4])\n```\n\nExample:\n```text\n>>> x[0][2]\n2\n```\n\nExample:\n```text\n>>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n>>> x[1:7:2]\narray([1, 3, 5])\n```\n\nExample:\n```text\n>>> x[-2:10]\narray([8, 9])\n>>> x[-3:3:-1]\narray([7, 6, 5, 4])\n```\n\nExample:\n```text\n>>> x[5:]\narray([5, 6, 7, 8, 9])\n```\n\nExample:\n```text\n>>> x = np.array([[[1],[2],[3]], [[4],[5],[6]]])\n>>> x.shape\n(2, 3, 1)\n>>> x[1:2]\narray([[[4],\n        [5],\n        [6]]])\n```\n\nExample:\n```text\n>>> x[..., 0]\narray([[1, 2, 3],\n      [4, 5, 6]])\n```\n\nExample:\n```text\n>>> x[:, :, 0]\narray([[1, 2, 3],\n      [4, 5, 6]])\n```\n\nExample:\n```text\n>>> x[:, np.newaxis, :, :].shape\n(2, 1, 3, 1)\n>>> x[:, None, :, :].shape\n(2, 1, 3, 1)\n```\n\nExample:\n```text\n>>> x = np.arange(5)\n>>> x[:, np.newaxis] + x[np.newaxis, :]\narray([[0, 1, 2, 3, 4],\n      [1, 2, 3, 4, 5],\n      [2, 3, 4, 5, 6],\n      [3, 4, 5, 6, 7],\n      [4, 5, 6, 7, 8]])\n```\n\nExample:\n```text\n>>> x = np.arange(10, 1, -1)\n>>> x\narray([10,  9,  8,  7,  6,  5,  4,  3,  2])\n>>> x[np.array([3, 3, 1, 8])]\narray([7, 7, 9, 2])\n>>> x[np.array([3, 3, -3, 8])]\narray([7, 7, 4, 2])\n```\n\nExample:\n```text\n>>> x = np.array([[1, 2], [3, 4], [5, 6]])\n>>> x[np.array([1, -1])]\narray([[3, 4],\n      [5, 6]])\n>>> x[np.array([3, 4])]\nTraceback (most recent call last):\n  ...\nIndexError: index 3 is out of bounds for axis 0 with size 3\n```\n\nExample:\n```text\nresult[i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M],\n                           ..., ind_N[i_1, ..., i_M]]\n```\n\nExample:\n```text\n>>> y = np.arange(35).reshape(5, 7)\n>>> y\narray([[ 0,  1,  2,  3,  4,  5,  6],\n       [ 7,  8,  9, 10, 11, 12, 13],\n       [14, 15, 16, 17, 18, 19, 20],\n       [21, 22, 23, 24, 25, 26, 27],\n       [28, 29, 30, 31, 32, 33, 34]])\n>>> y[np.array([0, 2, 4]), np.array([0, 1, 2])]\narray([ 0, 15, 30])\n```\n\nExample:\n```text\n>>> y[np.array([0, 2, 4]), np.array([0, 1])]\nTraceback (most recent call last):\n  ...\nIndexError: shape mismatch: indexing arrays could not be broadcast\ntogether with shapes (3,) (2,)\n```\n\nExample:\n```text\n>>> y[np.array([0, 2, 4]), 1]\narray([ 1, 15, 29])\n```\n\nExample:\n```text\n>>> y[np.array([0, 2, 4])]\narray([[ 0,  1,  2,  3,  4,  5,  6],\n       [14, 15, 16, 17, 18, 19, 20],\n       [28, 29, 30, 31, 32, 33, 34]])\n```\n\nExample:\n```text\n>>> x = np.array([[1, 2], [3, 4], [5, 6]])\n>>> x[[0, 1, 2], [0, 1, 0]]\narray([1, 4, 5])\n```\n\nExample:\n```text\n>>> x = np.array([[ 0,  1,  2],\n...               [ 3,  4,  5],\n...               [ 6,  7,  8],\n...               [ 9, 10, 11]])\n>>> rows = np.array([[0, 0],\n...                  [3, 3]], dtype=np.intp)\n>>> columns = np.array([[0, 2],\n...                     [0, 2]], dtype=np.intp)\n>>> x[rows, columns]\narray([[ 0,  2],\n       [ 9, 11]])\n```\n\nExample:\n```text\n>>> rows = np.array([0, 3], dtype=np.intp)\n>>> columns = np.array([0, 2], dtype=np.intp)\n>>> rows[:, np.newaxis]\narray([[0],\n       [3]])\n>>> x[rows[:, np.newaxis], columns]\narray([[ 0,  2],\n       [ 9, 11]])\n```\n\nExample:\n```text\n>>> x[np.ix_(rows, columns)]\narray([[ 0,  2],\n       [ 9, 11]])\n```\n\nExample:\n```text\n>>> x[rows, columns]\narray([ 0, 11])\n```\n\nExample:\n```text\n>>> x = np.array([[1., 2.], [np.nan, 3.], [np.nan, np.nan]])\n>>> x[~np.isnan(x)]\narray([1., 2., 3.])\n```\n\nExample:\n```text\n>>> x = np.array([1., -1., -2., 3])\n>>> x[x < 0] += 20\n>>> x\narray([ 1., 19., 18., 3.])\n```\n\nExample:\n```text\n>>> x = np.arange(35).reshape(5, 7)\n>>> b = x > 20\n>>> b[:, 5]\narray([False, False, False,  True,  True])\n>>> x[b[:, 5]]\narray([[21, 22, 23, 24, 25, 26, 27],\n      [28, 29, 30, 31, 32, 33, 34]])\n```\n\nExample:\n```text\n>>> x = np.array([[0, 1], [1, 1], [2, 2]])\n>>> rowsum = x.sum(-1)\n>>> x[rowsum <= 2, :]\narray([[0, 1],\n       [1, 1]])\n```\n\nExample:\n```text\n>>> x = np.array([[ 0,  1,  2],\n...               [ 3,  4,  5],\n...               [ 6,  7,  8],\n...               [ 9, 10, 11]])\n>>> rows = (x.sum(-1) % 2) == 0\n>>> rows\narray([False,  True, False,  True])\n>>> columns = [0, 2]\n>>> x[np.ix_(rows, columns)]\narray([[ 3,  5],\n       [ 9, 11]])\n```\n\nExample:\n```text\n>>> rows = rows.nonzero()[0]\n>>> x[rows[:, np.newaxis], columns]\narray([[ 3,  5],\n       [ 9, 11]])\n```\n\nExample:\n```text\n>>> x = np.arange(30).reshape(2, 3, 5)\n>>> x\narray([[[ 0,  1,  2,  3,  4],\n        [ 5,  6,  7,  8,  9],\n        [10, 11, 12, 13, 14]],\n      [[15, 16, 17, 18, 19],\n        [20, 21, 22, 23, 24],\n        [25, 26, 27, 28, 29]]])\n>>> b = np.array([[True, True, False], [False, True, True]])\n>>> x[b]\narray([[ 0,  1,  2,  3,  4],\n      [ 5,  6,  7,  8,  9],\n      [20, 21, 22, 23, 24],\n      [25, 26, 27, 28, 29]])\n```\n\nExample:\n```text\n>>> y = np.arange(35).reshape(5,7)\n>>> y[np.array([0, 2, 4]), 1:3]\narray([[ 1,  2],\n       [15, 16],\n       [29, 30]])\n```\n\nExample:\n```text\n>>> y[:, 1:3][np.array([0, 2, 4]), :]\narray([[ 1,  2],\n       [15, 16],\n       [29, 30]])\n```\n\nExample:\n```text\n>>> x = np.array([[ 0,  1,  2],\n...               [ 3,  4,  5],\n...               [ 6,  7,  8],\n...               [ 9, 10, 11]])\n>>> x[1:2, 1:3]\narray([[4, 5]])\n>>> x[1:2, [1, 2]]\narray([[4, 5]])\n```\n\nExample:\n```text\n>>> x = np.arange(35).reshape(5, 7)\n>>> b = x > 20\n>>> b\narray([[False, False, False, False, False, False, False],\n      [False, False, False, False, False, False, False],\n      [False, False, False, False, False, False, False],\n      [ True,  True,  True,  True,  True,  True,  True],\n      [ True,  True,  True,  True,  True,  True,  True]])\n>>> x[b[:, 5], 1:3]\narray([[22, 23],\n      [29, 30]])\n```\n\nExample:\n```text\n>>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])\n>>> x['a'].shape\n(2, 2)\n>>> x['a'].dtype\ndtype('int32')\n>>> x['b'].shape\n(2, 2, 3, 3)\n>>> x['b'].dtype\ndtype('float64')\n```\n\nExample:\n```text\n>>> x = np.arange(10)\n>>> x[2:7] = 1\n```\n\nExample:\n```text\n>>> x[2:7] = np.arange(5)\n```\n\nExample:\n```text\n>>> x[1] = 1.2\n>>> x[1]\n1\n>>> x[1] = 1.2j  \nTraceback (most recent call last):\n  ...\nTypeError: can't convert complex to int\n```\n\nExample:\n```text\n>>> x = np.arange(0, 50, 10)\n>>> x\narray([ 0, 10, 20, 30, 40])\n>>> x[np.array([1, 1, 3, 1])] += 1\n>>> x\narray([ 0, 11, 20, 31, 40])\n```\n\nExample:\n```text\n>>> z = np.arange(81).reshape(3, 3, 3, 3)\n>>> indices = (1, 1, 1, 1)\n>>> z[indices]\n40\n```\n\nExample:\n```text\n>>> indices = (1, 1, 1, slice(0, 2))  # same as [1, 1, 1, 0:2]\n>>> z[indices]\narray([39, 40])\n```\n\nExample:\n```text\n>>> indices = (1, Ellipsis, 1)  # same as [1, ..., 1]\n>>> z[indices]\narray([[28, 31, 34],\n       [37, 40, 43],\n       [46, 49, 52]])\n```\n\nExample:\n```text\n>>> z[[1, 1, 1, 1]]  # produces a large array\narray([[[[27, 28, 29],\n         [30, 31, 32], ...\n>>> z[(1, 1, 1, 1)]  # returns a single value\n40\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:55.989Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":44,"totalLines":408,"estimatedTokens":9185}}16{"id":"doc-universal_functions_ufunc_basics_numpy_v2_5_manu-4920dc02","source":"documentation","title":"Universal functions (ufunc) basics — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.ufuncs.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Universal functions (ufunc) basics Universal functions (ufunc) basics# See also Universal functions (ufunc) A universal function (or ufunc for short) is a function that operates on ndarrays in an element-by-element fashion, supporting array broadcasting, type casting, and several other standard features. That is, a ufunc is a “vectorized” wrapper for a function that takes a fixed number of specific inputs and produces a fixed number of specific outputs. There are also generalized ufuncs which are functions over vectors (or arrays) instead of single-element scalars. For example, numpy.add is a ufunc that operates element-by-element, while numpy.matmul is a gufunc that operates on vectors/matrices: >>> a = np.arange(6).reshape(3, 2) >>> a array([[0, 1], [2, 3], [4, 5]]) >>> np.add(a, a) # element-wise addition array([[ 0, 2], [ 4, 6], [ 8, 10]]) >>> np.matmul(a, a.T) # matrix multiplication (3x2) @ (2x3) -> (3x3) array([[ 1, 3, 5], [ 3, 13, 23], [ 5, 23, 41]]) In NumPy, universal functions are instances of the numpy.ufunc class. Many of the built-in functions are implemented in compiled C code. The basic ufuncs operate on scalars, but there is also a generalized kind for which the basic elements are sub-arrays (vectors, matrices, etc.), and broadcasting is done over other dimensions. The simplest example is the addition operator: >>> np.array([0,2,3,4]) + np.array([1,1,-1,2]) array([1, 3, 2, 6]) One can also produce custom numpy.ufunc instances using the numpy.frompyfunc factory function. Ufunc methods# All ufuncs have 5 methods. 4 reduce-like methods (reduce, accumulate, reduceat, outer) and one for inplace operations (at). See Methods for more. However, these methods only make sense on ufuncs that take two input arguments and return one output argument (so-called “scalar” ufuncs since the inner loop operates on a single scalar value). Attempting to call these methods on other ufuncs will cause a ValueError. For example, numpy.add takes two inputs and returns one output, so its methods work: >>> np.add.reduce([1, 2, 3]) 6 But numpy.divmod returns two outputs (quotient and remainder), so calling its methods raises an error: >>> np.divmod.reduce([1, 2, 3]) Traceback (most recent call last): ... only supported for functions returning a single value The reduce-like methods all take an axis keyword, a dtype keyword, and an out keyword, and the arrays must all have dimension >= 1. The axis keyword specifies the axis of the array over which the reduction will take place (with negative values counting backwards). Generally, it is an integer, though for numpy.ufunc.reduce, it can also be a tuple of int to reduce over several axes at once, or None, to reduce over all axes. For example: >>> x = np.arange(9).reshape(3,3) >>> x array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> np.add.reduce(x, 1) array([ 3, 12, 21]) >>> np.add.reduce(x, (0, 1)) 36 The dtype keyword allows you to manage a very common problem that arises when naively using ufunc.reduce. Sometimes you may have an array of a certain data type and wish to add up all of its elements, but the result does not fit into the data type of the array. This commonly happens if you have an array of single-byte integers. The dtype keyword allows you to alter the data type over which the reduction takes place (and therefore the type of the output). Thus, you can ensure that the output is a data type with precision large enough to handle your output. The responsibility of altering the reduce type is mostly up to you. There is one no dtype is given for a reduction on the “add” or “multiply” operations, then if the input type is an integer (or Boolean) data-type and smaller than the size of the numpy.int_ data type, it will be internally upcast to the int_ (or numpy.uint) data-type. In the previous example: >>> x.dtype dtype('int64') >>> np.multiply.reduce(x, dtype=np.float64) array([ 0., 28., 80.]) Finally, the out keyword allows you to provide an output array (or a tuple of output arrays for multi-output ufuncs). If out is given, the dtype argument is only used for the internal computations. Considering x from the previous example: >>> y = np.zeros(3, dtype=np.int_) >>> y array([0, 0, 0]) >>> np.multiply.reduce(x, dtype=np.float64, out=y) array([ 0, 28, 80]) Ufuncs also have a fifth method, numpy.ufunc.at, that allows in place operations to be performed using advanced indexing. No buffering is used on the dimensions where advanced indexing is used, so the advanced index can list an item more than once and the operation will be performed on the result of the previous operation for that item. Output type determination# If the input arguments of the ufunc (or its methods) are ndarrays, then the output will be as well. The exception is when the result is zero-dimensional, in which case the output will be converted to an array scalar. This can be avoided by passing in out=... or out=Ellipsis. If some or all of the input arguments are not ndarrays, then the output may not be an ndarray either. Indeed, if any input defines an __array_ufunc__ method, control will be passed completely to that function, i.e., the ufunc is overridden. If none of the inputs overrides the ufunc, then all output arrays will be passed to the __array_wrap__ method of the input (besides ndarrays, and scalars) that defines it and has the highest __array_priority__ of any other input to the universal function. The default __array_priority__ of the ndarray is 0.0, and the default __array_priority__ of a subtype is 0.0. Matrices have __array_priority__ equal to 10.0. All ufuncs can also take output arguments which must be arrays or subclasses. If necessary, the result will be cast to the data-type(s) of the provided output array(s). If the output has an __array_wrap__ method it is called instead of the one found on the inputs. Broadcasting# See also Broadcasting basics Each universal function takes array inputs and produces array outputs by performing the core function element-wise on the inputs (where an element is generally a scalar, but can be a vector or higher-order sub-array for generalized ufuncs). Standard broadcasting rules are applied so that inputs not sharing exactly the same shapes can still be usefully operated on. By these rules, if an input has a dimension size of 1 in its shape, the first data entry in that dimension will be used for all calculations along that dimension. In other words, the stepping machinery of the ufunc will simply not step along that dimension (the stride will be 0 for that dimension). Type casting rules# Note In NumPy 1.6.0, a type promotion API was created to encapsulate the mechanism for determining output types. See the functions numpy.result_type, numpy.promote_types, and numpy.min_scalar_type for more details. At the core of every ufunc is a one-dimensional strided loop that implements the actual function for a specific type combination. When a ufunc is created, it is given a static list of inner loops and a corresponding list of type signatures over which the ufunc operates. The ufunc machinery uses this list to determine which inner loop to use for a particular case. You can inspect the >>> def print_table(ntypes): ... print('X ' + ' '.join(ntypes)) ... for row in print(row, end='') ... for col in print(mark[np.can_cast(row, col)], end='') ... print() ... >>> print_table(np.typecodes['All']) X ? b h i l q n p B H I L Q N P e f d g F D G S U V O M m ? Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y - Y b - Y Y Y Y Y Y Y - - - - - - - Y Y Y Y Y Y Y Y Y Y Y - Y h - - Y Y Y Y Y Y - - - - - - - - Y Y Y Y Y Y Y Y Y Y - Y i - - - Y Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y l - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y q - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y n - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y p - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y B - - Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y - Y H - - - Y Y Y Y Y - Y Y Y Y Y Y - Y Y Y Y Y Y Y Y Y Y - Y I - - - - Y Y Y Y - - Y Y Y Y Y - - Y Y - Y Y Y Y Y Y - Y L - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - - Q - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - - N - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - - P - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - - e - - - - - - - - - - - - - - - Y Y Y Y Y Y Y Y Y Y Y - - f - - - - - - - - - - - - - - - - Y Y Y Y Y Y Y Y Y Y - - d - - - - - - - - - - - - - - - - - Y Y - Y Y Y Y Y Y - - g - - - - - - - - - - - - - - - - - - Y - - Y Y Y Y Y - - F - - - - - - - - - - - - - - - - - - - Y Y Y Y Y Y Y - - D - - - - - - - - - - - - - - - - - - - - Y Y Y Y Y Y - - G - - - - - - - - - - - - - - - - - - - - - Y Y Y Y Y - - S - - - - - - - - - - - - - - - - - - - - - - Y Y Y Y - - U - - - - - - - - - - - - - - - - - - - - - - - Y Y Y - - V - - - - - - - - - - - - - - - - - - - - - - - - Y Y - - O - - - - - - - - - - - - - - - - - - - - - - - - - Y - - M - - - - - - - - - - - - - - - - - - - - - - - - Y Y Y - m - - - - - - - - - - - - - - - - - - - - - - - - Y Y - Y You should note that, while included in the table for completeness, the ‘S’, ‘U’, and ‘V’ types cannot be operated on by ufuncs. Also, note that on a 32-bit system the integer types may have different sizes, resulting in a slightly altered table. Mixed scalar-array operations use a different set of casting rules that ensure that a scalar cannot “upcast” an array unless the scalar is of a fundamentally different kind of data (i.e., under a different hierarchy in the data-type hierarchy) than the array. This rule enables you to use scalar constants in your code (which, as Python types, are interpreted accordingly in ufuncs) without worrying about whether the precision of the scalar constant will cause upcasting on your large (small precision) array. Use of internal buffers# Internally, buffers are used for misaligned data, swapped data, and data that has to be converted from one data type to another. The size of internal buffers is settable on a per-thread basis. There can be up to \\(2 (n_{\\mathrm{inputs}} + n_{\\mathrm{outputs}})\\) buffers of the specified size created to handle the data from all the inputs and outputs of a ufunc. The default size of a buffer is 10,000 elements. Whenever buffer-based calculation would be needed, but all input arrays are smaller than the buffer size, those misbehaved or incorrectly-typed arrays will be copied before the calculation proceeds. Adjusting the size of the buffer may therefore alter the speed at which ufunc calculations of various sorts are completed. A simple interface for setting this variable is accessible using the function numpy.setbufsize. Error handling# Universal functions can trip special floating-point status registers in your hardware (such as divide-by-zero). If available on your platform, these registers will be regularly checked during calculation. Error handling is controlled on a per-thread basis, and can be configured using the functions numpy.seterr and numpy.seterrcall. Overriding ufunc behavior# Classes (including ndarray subclasses) can override how ufuncs act on them by defining certain special methods. For details, see Standard array subclasses. previous Structured arrays next NumPy for MATLAB users On this page Ufunc methods Output type determination Broadcasting Type casting rules Use of internal buffers Error handling Overriding ufunc behavior\n\nExample:\n```text\n>>> a = np.arange(6).reshape(3, 2)\n>>> a\narray([[0, 1],\n       [2, 3],\n       [4, 5]])\n>>> np.add(a, a)  # element-wise addition\narray([[ 0,  2],\n       [ 4,  6],\n       [ 8, 10]])\n>>> np.matmul(a, a.T)  # matrix multiplication (3x2) @ (2x3) -> (3x3)\narray([[ 1,  3,  5],\n       [ 3, 13, 23],\n       [ 5, 23, 41]])\n```\n\nExample:\n```text\n>>> np.array([0,2,3,4]) + np.array([1,1,-1,2])\narray([1, 3, 2, 6])\n```\n\nExample:\n```text\n>>> np.add.reduce([1, 2, 3])\n6\n```\n\nExample:\n```text\n>>> np.divmod.reduce([1, 2, 3])\nTraceback (most recent call last):\n    ...\nValueError: reduce only supported for functions returning a single value\n```\n\nExample:\n```text\n>>> x = np.arange(9).reshape(3,3)\n>>> x\narray([[0, 1, 2],\n      [3, 4, 5],\n      [6, 7, 8]])\n>>> np.add.reduce(x, 1)\narray([ 3, 12, 21])\n>>> np.add.reduce(x, (0, 1))\n36\n```\n\nExample:\n```text\n>>> x.dtype\ndtype('int64')\n>>> np.multiply.reduce(x, dtype=np.float64)\narray([ 0., 28., 80.])\n```\n\nExample:\n```text\n>>> y = np.zeros(3, dtype=np.int_)\n>>> y\narray([0, 0, 0])\n>>> np.multiply.reduce(x, dtype=np.float64, out=y)\narray([ 0, 28, 80])\n```\n\nExample:\n```text\n>>> mark = {False: ' -', True: ' Y'}\n>>> def print_table(ntypes):\n...     print('X ' + ' '.join(ntypes))\n...     for row in ntypes:\n...         print(row, end='')\n...         for col in ntypes:\n...             print(mark[np.can_cast(row, col)], end='')\n...         print()\n...\n>>> print_table(np.typecodes['All'])\nX ? b h i l q n p B H I L Q N P e f d g F D G S U V O M m\n? Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y - Y\nb - Y Y Y Y Y Y Y - - - - - - - Y Y Y Y Y Y Y Y Y Y Y - Y\nh - - Y Y Y Y Y Y - - - - - - - - Y Y Y Y Y Y Y Y Y Y - Y\ni - - - Y Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y\nl - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y\nq - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y\nn - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y\np - - - - Y Y Y Y - - - - - - - - - Y Y - Y Y Y Y Y Y - Y\nB - - Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y - Y\nH - - - Y Y Y Y Y - Y Y Y Y Y Y - Y Y Y Y Y Y Y Y Y Y - Y\nI - - - - Y Y Y Y - - Y Y Y Y Y - - Y Y - Y Y Y Y Y Y - Y\nL - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - -\nQ - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - -\nN - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - -\nP - - - - - - - - - - - Y Y Y Y - - Y Y - Y Y Y Y Y Y - -\ne - - - - - - - - - - - - - - - Y Y Y Y Y Y Y Y Y Y Y - -\nf - - - - - - - - - - - - - - - - Y Y Y Y Y Y Y Y Y Y - -\nd - - - - - - - - - - - - - - - - - Y Y - Y Y Y Y Y Y - -\ng - - - - - - - - - - - - - - - - - - Y - - Y Y Y Y Y - -\nF - - - - - - - - - - - - - - - - - - - Y Y Y Y Y Y Y - -\nD - - - - - - - - - - - - - - - - - - - - Y Y Y Y Y Y - -\nG - - - - - - - - - - - - - - - - - - - - - Y Y Y Y Y - -\nS - - - - - - - - - - - - - - - - - - - - - - Y Y Y Y - -\nU - - - - - - - - - - - - - - - - - - - - - - - Y Y Y - -\nV - - - - - - - - - - - - - - - - - - - - - - - - Y Y - -\nO - - - - - - - - - - - - - - - - - - - - - - - - - Y - -\nM - - - - - - - - - - - - - - - - - - - - - - - - Y Y Y -\nm - - - - - - - - - - - - - - - - - - - - - - - - Y Y - Y\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:56.002Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":8,"totalLines":113,"estimatedTokens":3848}}17{"id":"doc-numpy_quickstart_numpy_v2_5_manual-752038e7","source":"documentation","title":"NumPy quickstart — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/quickstart.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy quickstart NumPy quickstart# Prerequisites# You’ll need to know a bit of Python. For a refresher, see the Python tutorial. To work the examples, you’ll need matplotlib installed in addition to NumPy. Learner profile This is a quick overview of arrays in NumPy. It demonstrates how n-dimensional (\\(n>=2\\)) arrays are represented and can be manipulated. In particular, if you don’t know how to apply common functions to n-dimensional arrays (without using for-loops), or if you want to understand axis and shape properties for n-dimensional arrays, this article might be of help. Learning Objectives After reading, you should be able the difference between one-, two- and n-dimensional arrays in NumPy; Understand how to apply some linear algebra operations to n-dimensional arrays without using for-loops; Understand axis and shape properties for n-dimensional arrays. The basics# NumPy’s main object is the homogeneous multidimensional array. It is a table of elements (usually numbers), all of the same type, indexed by a tuple of non-negative integers. In NumPy dimensions are called axes. For example, the array for the coordinates of a point in 3D space, [1, 2, 1], has one axis. That axis has 3 elements in it, so we say it has a length of 3. In the example pictured below, the array has 2 axes. The first axis has a length of 2, the second axis has a length of 3. [[1., 0., 0.], [0., 1., 2.]] NumPy’s array class is called ndarray. It is also known by the alias array. Note that numpy.array is not the same as the Standard Python Library class array.array, which only handles one-dimensional arrays and offers less functionality. The more important attributes of an ndarray object number of axes (dimensions) of the array. ndarray.shapethe dimensions of the array. This is a tuple of integers indicating the size of the array in each dimension. For a matrix with n rows and m columns, shape will be (n,m). The length of the shape tuple is therefore the number of axes, ndim. ndarray.sizethe total number of elements of the array. This is equal to the product of the elements of shape. ndarray.dtypean object describing the type of the elements in the array. One can create or specify dtype’s using standard Python types. Additionally NumPy provides types of its own. numpy.int32, numpy.int16, and numpy.float64 are some examples. ndarray.itemsizethe size in bytes of each element of the array. For example, an array of elements of type float64 has itemsize 8 (=64/8), while one of type complex32 has itemsize 4 (=32/8). It is equivalent to ndarray.dtype.itemsize. ndarray.datathe buffer containing the actual elements of the array. Normally, we won’t need to use this attribute because we will access the elements in an array using indexing facilities. An example# >>> import numpy as np >>> a = np.arange(15).reshape(3, 5) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) >>> a.shape (3, 5) >>> a.ndim 2 >>> a.dtype.name 'int64' >>> a.itemsize 8 >>> a.size 15 >>> type(a) <class 'numpy.ndarray'> >>> b = np.array([6, 7, 8]) >>> b array([6, 7, 8]) >>> type(b) <class 'numpy.ndarray'> Array creation# There are several ways to create arrays. For example, you can create an array from a regular Python list or tuple using the array function. The type of the resulting array is deduced from the type of the elements in the sequences. >>> import numpy as np >>> a = np.array([2, 3, 4]) >>> a array([2, 3, 4]) >>> a.dtype dtype('int64') >>> b = np.array([1.2, 3.5, 5.1]) >>> b.dtype dtype('float64') A frequent error consists in calling array with multiple arguments, rather than providing a single sequence as an argument. >>> a = np.array(1, 2, 3, 4) # WRONG Traceback (most recent call last): ... () takes from 1 to 2 positional arguments but 4 were given >>> a = np.array([1, 2, 3, 4]) # RIGHT array transforms sequences of sequences into two-dimensional arrays, sequences of sequences of sequences into three-dimensional arrays, and so on. >>> b = np.array([(1.5, 2, 3), (4, 5, 6)]) >>> b array([[1.5, 2. , 3. ], [4. , 5. , 6. ]]) The type of the array can also be explicitly specified at creation time: >>> c = np.array([[1, 2], [3, 4]], dtype=np.complex128) >>> c array([[1.+0.j, 2.+0.j], [3.+0.j, 4.+0.j]]) Often, the elements of an array are originally unknown, but its size is known. Hence, NumPy offers several functions to create arrays with initial placeholder content. These minimize the necessity of growing arrays, an expensive operation. The function zeros creates an array full of zeros, the function ones creates an array full of ones, and the function empty creates an array whose initial content is random and depends on the state of the memory. By default, the dtype of the created array is float64, but it can be specified via the key word argument dtype. >>> np.zeros((3, 4)) array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]) >>> np.ones((2, 3, 4), dtype=np.int16) array([[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]], dtype=int16) >>> np.empty((2, 3)) array([[3.73603959e-262, 6.02658058e-154, 6.55490914e-260], # may vary [5.30498948e-313, 3.14673309e-307, 1.00000000e+000]]) To create sequences of numbers, NumPy provides the arange function which is analogous to the Python built-in range, but returns an array. >>> np.arange(10, 30, 5) array([10, 15, 20, 25]) >>> np.arange(0, 2, 0.3) # it accepts float arguments array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8]) When arange is used with floating point arguments, it is generally not possible to predict the number of elements obtained, due to the finite floating point precision. For this reason, it is usually better to use the function linspace that receives as an argument the number of elements that we want, instead of the step: >>> from numpy import pi >>> np.linspace(0, 2, 9) # 9 numbers from 0 to 2 array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ]) >>> x = np.linspace(0, 2 * pi, 100) # useful to evaluate function at lots of points >>> f = np.sin(x) See also array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, random.Generator.random, random.Generator.normal, fromfunction, fromfile Printing arrays# When you print an array, NumPy displays it in a similar way to nested lists, but with the following last axis is printed from left to right, the second-to-last is printed from top to bottom, the rest are also printed from top to bottom, with each slice separated from the next by an empty line. One-dimensional arrays are then printed as rows, bidimensionals as matrices and tridimensionals as lists of matrices. >>> a = np.arange(6) # 1d array >>> print(a) [0 1 2 3 4 5] >>> >>> b = np.arange(12).reshape(4, 3) # 2d array >>> print(b) [[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]] >>> >>> c = np.arange(24).reshape(2, 3, 4) # 3d array >>> print(c) [[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] [[12 13 14 15] [16 17 18 19] [20 21 22 23]]] See below to get more details on reshape. If an array is too large to be printed, NumPy automatically skips the central part of the array and only prints the corners: >>> print(np.arange(10000)) [ 0 1 2 ... 9997 9998 9999] >>> >>> print(np.arange(10000).reshape(100, 100)) [[ 0 1 2 ... 97 98 99] [ 100 101 102 ... 197 198 199] [ 200 201 202 ... 297 298 299] ... [9700 9701 9702 ... 9797 9798 9799] [9800 9801 9802 ... 9897 9898 9899] [9900 9901 9902 ... 9997 9998 9999]] To disable this behaviour and force NumPy to print the entire array, you can change the printing options using set_printoptions. >>> np.set_printoptions(threshold=sys.maxsize) # sys module should be imported Basic operations# Arithmetic operators on arrays apply elementwise. A new array is created and filled with the result. >>> a = np.array([20, 30, 40, 50]) >>> b = np.arange(4) >>> b array([0, 1, 2, 3]) >>> c = a - b >>> c array([20, 29, 38, 47]) >>> b**2 array([0, 1, 4, 9]) >>> 10 * np.sin(a) array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854]) >>> a < 35 array([ True, True, False, False]) Unlike in many matrix languages, the product operator * operates elementwise in NumPy arrays. The matrix product can be performed using the @ operator (in python >=3.5) or the dot function or method: >>> A = np.array([[1, 1], ... [0, 1]]) >>> B = np.array([[2, 0], ... [3, 4]]) >>> A * B # elementwise product array([[2, 0], [0, 4]]) >>> A @ B # matrix product array([[5, 4], [3, 4]]) >>> A.dot(B) # another matrix product array([[5, 4], [3, 4]]) Some operations, such as += and *=, act in place to modify an existing array rather than create a new one. >>> rg = np.random.default_rng(1) # create instance of default random number generator >>> a = np.ones((2, 3), dtype=np.int_) >>> b = rg.random((2, 3)) >>> a *= 3 >>> a array([[3, 3, 3], [3, 3, 3]]) >>> b += a >>> b array([[3.51182162, 3.9504637 , 3.14415961], [3.94864945, 3.31183145, 3.42332645]]) >>> a += b # b is not automatically converted to integer type Traceback (most recent call last): ... numpy._core._exceptions._UFuncOutputCastingError: Cannot cast ufunc 'add' output from dtype('float64') to dtype('int64') with casting rule 'same_kind' When operating with arrays of different types, the type of the resulting array corresponds to the more general or precise one (a behavior known as upcasting). >>> a = np.ones(3, dtype=np.int32) >>> b = np.linspace(0, pi, 3) >>> b.dtype.name 'float64' >>> c = a + b >>> c array([1. , 2.57079633, 4.14159265]) >>> c.dtype.name 'float64' >>> d = np.exp(c * 1j) >>> d array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j, -0.54030231-0.84147098j]) >>> d.dtype.name 'complex128' Many unary operations, such as computing the sum of all the elements in the array, are implemented as methods of the ndarray class. >>> a = rg.random((2, 3)) >>> a array([[0.82770259, 0.40919914, 0.54959369], [0.02755911, 0.75351311, 0.53814331]]) >>> a.sum() 3.1057109529998157 >>> a.min() 0.027559113243068367 >>> a.max() 0.8277025938204418 By default, these operations apply to the array as though it were a list of numbers, regardless of its shape. However, by specifying the axis parameter you can apply an operation along the specified axis of an array: >>> b = np.arange(12).reshape(3, 4) >>> b array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> b.sum(axis=0) # sum of each column array([12, 15, 18, 21]) >>> >>> b.min(axis=1) # min of each row array([0, 4, 8]) >>> >>> b.cumsum(axis=1) # cumulative sum along each row array([[ 0, 1, 3, 6], [ 4, 9, 15, 22], [ 8, 17, 27, 38]]) Universal functions# NumPy provides familiar mathematical functions such as sin, cos, and exp. In NumPy, these are called “universal functions” (ufunc). Within NumPy, these functions operate elementwise on an array, producing an array as output. >>> B = np.arange(3) >>> B array([0, 1, 2]) >>> np.exp(B) array([1. , 2.71828183, 7.3890561 ]) >>> np.sqrt(B) array([0. , 1. , 1.41421356]) >>> C = np.array([2., -1., 4.]) >>> np.add(B, C) array([2., 0., 6.]) See also all, any, apply_along_axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, invert, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sort, std, sum, trace, transpose, var, vdot, vectorize, where Indexing, slicing and iterating# One-dimensional arrays can be indexed, sliced and iterated over, much like lists and other Python sequences. >>> a = np.arange(10)**3 >>> a array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]) >>> a[2] 8 >>> a[2:5] array([ 8, 27, 64]) >>> # equivalent to a[0:6:2] = 1000; >>> # from start to position 6, exclusive, set every 2nd element to 1000 >>> a[:6:2] = 1000 >>> a array([1000, 1, 1000, 27, 1000, 125, 216, 343, 512, 729]) >>> a[::-1] # reversed a array([ 729, 512, 343, 216, 125, 1000, 27, 1000, 1, 1000]) >>> for i in print(i**(1 / 3.)) ... 9.999999999999998 # may vary 1.0 9.999999999999998 3.0 9.999999999999998 4.999999999999999 5.999999999999999 6.999999999999999 7.999999999999999 8.999999999999998 Multidimensional arrays can have one index per axis. These indices are given in a tuple separated by commas: >>> def f(x, y): ... return 10 * x + y ... >>> b = np.fromfunction(f, (5, 4), dtype=np.int_) >>> b array([[ 0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33], [40, 41, 42, 43]]) >>> b[2, 3] 23 >>> b[0:5, 1] # each row in the second column of b array([ 1, 11, 21, 31, 41]) >>> b[:, 1] # equivalent to the previous example array([ 1, 11, 21, 31, 41]) >>> b[1:3, :] # each column in the second and third row of b array([[10, 11, 12, 13], [20, 21, 22, 23]]) When fewer indices are provided than the number of axes, the missing indices are considered complete slices: >>> b[-1] # the last row. Equivalent to b[-1, :] array([40, 41, 42, 43]) The expression within brackets in b[i] is treated as an i followed by as many instances needed to represent the remaining axes. NumPy also allows you to write this using dots as b[i, ...]. The dots (...) represent as many colons as needed to produce a complete indexing tuple. For example, if x is an array with 5 axes, then x[1, 2, ...] is equivalent to x[1, 2, :, :, :], x[..., 3] to x[:, :, :, :, 3] and x[4, ..., 5, :] to x[4, :, :, 5, :]. >>> c = np.array([[[ 0, 1, 2], # a 3D array (two stacked 2D arrays) ... [ 10, 12, 13]], ... [[100, 101, 102], ... [110, 112, 113]]]) >>> c.shape (2, 2, 3) >>> c[1, ...] # same as c[1, :, :] or c[1] array([[100, 101, 102], [110, 112, 113]]) >>> c[..., 2] # same as c[:, :, 2] array([[ 2, 13], [102, 113]]) Iterating over multidimensional arrays is done with respect to the first axis: >>> for row in print(row) ... [0 1 2 3] [10 11 12 13] [20 21 22 23] [30 31 32 33] [40 41 42 43] However, if one wants to perform an operation on each element in the array, one can use the flat attribute which is an iterator over all the elements of the array: >>> for element in b.flat: ... print(element) ... 0 1 2 3 10 11 12 13 20 21 22 23 30 31 32 33 40 41 42 43 See also Indexing on ndarrays, Indexing routines (reference), newaxis, ndenumerate, indices Shape manipulation# Changing the shape of an array# An array has a shape given by the number of elements along each axis: >>> a = np.floor(10 * rg.random((3, 4))) >>> a array([[3., 7., 3., 4.], [1., 4., 2., 2.], [7., 2., 4., 9.]]) >>> a.shape (3, 4) The shape of an array can be changed with various commands. Note that the following three commands all return a modified array, but do not change the original array: >>> a.ravel() # returns the array, flattened array([3., 7., 3., 4., 1., 4., 2., 2., 7., 2., 4., 9.]) >>> a.reshape(6, 2) # returns the array with a modified shape array([[3., 7.], [3., 4.], [1., 4.], [2., 2.], [7., 2.], [4., 9.]]) >>> a.T # returns the array, transposed array([[3., 1., 7.], [7., 4., 2.], [3., 2., 4.], [4., 2., 9.]]) >>> a.T.shape (4, 3) >>> a.shape (3, 4) The order of the elements in the array resulting from ravel is normally “C-style”, that is, the rightmost index “changes the fastest”, so the element after a[0, 0] is a[0, 1]. If the array is reshaped to some other shape, again the array is treated as “C-style”. NumPy normally creates arrays stored in this order, so ravel will usually not need to copy its argument, but if the array was made by taking slices of another array or created with unusual options, it may need to be copied. The functions ravel and reshape can also be instructed, using an optional argument, to use FORTRAN-style arrays, in which the leftmost index changes the fastest. The reshape function returns its argument with a modified shape, whereas the ndarray.resize method modifies the array itself: >>> a array([[3., 7., 3., 4.], [1., 4., 2., 2.], [7., 2., 4., 9.]]) >>> a.resize((2, 6)) >>> a array([[3., 7., 3., 4., 1., 4.], [2., 2., 7., 2., 4., 9.]]) If a dimension is given as -1 in a reshaping operation, the other dimensions are automatically calculated: >>> a.reshape(3, -1) array([[3., 7., 3., 4.], [1., 4., 2., 2.], [7., 2., 4., 9.]]) See also ndarray.shape, reshape, resize, ravel Stacking together different arrays# Several arrays can be stacked together along different axes: >>> a = np.floor(10 * rg.random((2, 2))) >>> a array([[9., 7.], [5., 2.]]) >>> b = np.floor(10 * rg.random((2, 2))) >>> b array([[1., 9.], [5., 1.]]) >>> np.vstack((a, b)) array([[9., 7.], [5., 2.], [1., 9.], [5., 1.]]) >>> np.hstack((a, b)) array([[9., 7., 1., 9.], [5., 2., 5., 1.]]) The function column_stack stacks 1D arrays as columns into a 2D array. It is equivalent to hstack only for 2D arrays: >>> from numpy import newaxis >>> np.column_stack((a, b)) # with 2D arrays array([[9., 7., 1., 9.], [5., 2., 5., 1.]]) >>> a = np.array([4., 2.]) >>> b = np.array([3., 8.]) >>> np.column_stack((a, b)) # returns a 2D array array([[4., 3.], [2., 8.]]) >>> np.hstack((a, b)) # the result is different array([4., 2., 3., 8.]) >>> a[:, newaxis] # view `a` as a 2D column vector array([[4.], [2.]]) >>> np.column_stack((a[:, newaxis], b[:, newaxis])) array([[4., 3.], [2., 8.]]) >>> np.hstack((a[:, newaxis], b[:, newaxis])) # the result is the same array([[4., 3.], [2., 8.]]) In general, for arrays with more than two dimensions, hstack stacks along their second axes, vstack stacks along their first axes, and concatenate allows for an optional arguments giving the number of the axis along which the concatenation should happen. Note In complex cases, r_ and c_ are useful for creating arrays by stacking numbers along one axis. They allow the use of range >>> np.r_[1:4, 0, 4] array([1, 2, 3, 0, 4]) When used with arrays as arguments, r_ and c_ are similar to vstack and hstack in their default behavior, but allow for an optional argument giving the number of the axis along which to concatenate. See also hstack, vstack, column_stack, concatenate, c_, r_ Splitting one array into several smaller ones# Using hsplit, you can split an array along its horizontal axis, either by specifying the number of equally shaped arrays to return, or by specifying the columns after which the division should occur: >>> a = np.floor(10 * rg.random((2, 12))) >>> a array([[6., 7., 6., 9., 0., 5., 4., 0., 6., 8., 5., 2.], [8., 5., 5., 7., 1., 8., 6., 7., 1., 8., 1., 0.]]) >>> # Split `a` into 3 >>> np.hsplit(a, 3) [array([[6., 7., 6., 9.], [8., 5., 5., 7.]]), array([[0., 5., 4., 0.], [1., 8., 6., 7.]]), array([[6., 8., 5., 2.], [1., 8., 1., 0.]])] >>> # Split `a` after the third and the fourth column >>> np.hsplit(a, (3, 4)) [array([[6., 7., 6.], [8., 5., 5.]]), array([[9.], [7.]]), array([[0., 5., 4., 0., 6., 8., 5., 2.], [1., 8., 6., 7., 1., 8., 1., 0.]])] vsplit splits along the vertical axis, and array_split allows one to specify along which axis to split. Copies and views# When operating and manipulating arrays, their data is sometimes copied into a new array and sometimes not. This is often a source of confusion for beginners. There are three copy at all# Simple assignments make no copy of objects or their data. >>> a = np.array([[ 0, 1, 2, 3], ... [ 4, 5, 6, 7], ... [ 8, 9, 10, 11]]) >>> b = a # no new object is created >>> b is a # a and b are two names for the same ndarray object True Python passes mutable objects as references, so function calls make no copy. >>> def f(x): ... print(id(x)) ... >>> id(a) # id is a unique identifier of an object 148293216 # may vary >>> f(a) 148293216 # may vary View or shallow copy# Different array objects can share the same data. The view method creates a new array object that looks at the same data. >>> c = a.view() >>> c is a False >>> c.base is a # c is a view of the data owned by a True >>> c.flags.owndata False >>> >>> c = c.reshape((2, 6)) # a's shape doesn't change, reassigned c is still a view of a >>> a.shape (3, 4) >>> c[0, 4] = 1234 # a's data changes >>> a array([[ 0, 1, 2, 3], [1234, 5, 6, 7], [ 8, 9, 10, 11]]) Slicing an array returns a view of it: >>> s = a[:, ] >>> s[:] = 10 # s[:] is a view of s. Note the difference between s = 10 and s[:] = 10 >>> a array([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]]) Deep copy# The copy method makes a complete copy of the array and its data. >>> d = a.copy() # a new array object with new data is created >>> d is a False >>> d.base is a # d doesn't share anything with a False >>> d[0, 0] = 9999 >>> a array([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]]) Sometimes copy should be called after slicing if the original array is not required anymore. For example, suppose a is a huge intermediate result and the final result b only contains a small fraction of a, a deep copy should be made when constructing b with slicing: >>> a = np.arange(int(1e8)) >>> b = a[:100].copy() >>> del a # the memory of ``a`` can be released. If b = a[:100] is used instead, a is referenced by b and will persist in memory even if del a is executed. See also Copies and views. Functions and methods overview# Here is a list of some useful NumPy functions and methods names ordered in categories. See Routines and objects by topic for the full list. Array Creationarange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r_, zeros, zeros_like Conversionsndarray.astype, atleast_1d, atleast_2d, atleast_3d, mat Manipulationsarray_split, column_stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, ndarray.item, newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack Questionsall, any, nonzero, where Orderingargmax, argmin, argsort, max, min, ptp, searchsorted, sort Operationschoose, compress, cumprod, cumsum, inner, ndarray.fill, imag, prod, put, putmask, real, sum Basic Statisticscov, mean, std, var Basic Linear Algebracross, dot, outer, linalg.svd, vdot Less basic# Broadcasting rules# Broadcasting allows universal functions to deal in a meaningful way with inputs that do not have exactly the same shape. The first rule of broadcasting is that if all input arrays do not have the same number of dimensions, a “1” will be repeatedly prepended to the shapes of the smaller arrays until all the arrays have the same number of dimensions. The second rule of broadcasting ensures that arrays with a size of 1 along a particular dimension act as if they had the size of the array with the largest shape along that dimension. The value of the array element is assumed to be the same along that dimension for the “broadcast” array. After application of the broadcasting rules, the sizes of all arrays must match. More details can be found in Broadcasting. Advanced indexing and index tricks# NumPy offers more indexing facilities than regular Python sequences. In addition to indexing by integers and slices, as we saw before, arrays can be indexed by arrays of integers and arrays of booleans. Indexing with arrays of indices# >>> a = np.arange(12)**2 # the first 12 square numbers >>> i = np.array([1, 1, 3, 8, 5]) # an array of indices >>> a[i] # the elements of `a` at the positions `i` array([ 1, 1, 9, 64, 25]) >>> >>> j = np.array([[3, 4], [9, 7]]) # a bidimensional array of indices >>> a[j] # the same shape as `j` array([[ 9, 16], [81, 49]]) When the indexed array a is multidimensional, a single array of indices refers to the first dimension of a. The following example shows this behavior by converting an image of labels into a color image using a palette. >>> palette = np.array([[0, 0, 0], # black ... [255, 0, 0], # red ... [0, 255, 0], # green ... [0, 0, 255], # blue ... [255, 255, 255]]) # white >>> image = np.array([[0, 1, 2, 0], # each value corresponds to a color in the palette ... [0, 3, 4, 0]]) >>> palette[image] # the (2, 4, 3) color image array([[[ 0, 0, 0], [255, 0, 0], [ 0, 255, 0], [ 0, 0, 0]], [[ 0, 0, 0], [ 0, 0, 255], [255, 255, 255], [ 0, 0, 0]]]) We can also give indexes for more than one dimension. The arrays of indices for each dimension must have the same shape. >>> a = np.arange(12).reshape(3, 4) >>> a array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> i = np.array([[0, 1], # indices for the first dim of `a` ... [1, 2]]) >>> j = np.array([[2, 1], # indices for the second dim ... [3, 3]]) >>> >>> a[i, j] # i and j must have equal shape array([[ 2, 5], [ 7, 11]]) >>> >>> a[i, 2] array([[ 2, 6], [ 6, 10]]) >>> >>> a[:, j] array([[[ 2, 1], [ 3, 3]], [[ 6, 5], [ 7, 7]], [[10, 9], [11, 11]]]) In Python, arr[i, j] is exactly the same as arr[(i, j)]—so we can put i and j in a tuple and then do the indexing with that. >>> l = (i, j) >>> # equivalent to a[i, j] >>> a[l] array([[ 2, 5], [ 7, 11]]) However, we can not do this by putting i and j into an array, because this array will be interpreted as indexing the first dimension of a. >>> s = np.array([i, j]) >>> # not what we want >>> a[s] Traceback (most recent call last): File \"<stdin>\", line 1, in <module> 3 is out of bounds for axis 0 with size 3 >>> # same as `a[i, j]` >>> a[tuple(s)] array([[ 2, 5], [ 7, 11]]) Another common use of indexing with arrays is the search of the maximum value of time-dependent series: >>> time = np.linspace(20, 145, 5) # time scale >>> data = np.sin(np.arange(20)).reshape(5, 4) # 4 time-dependent series >>> time array([ 20. , 51.25, 82.5 , 113.75, 145. ]) >>> data array([[ 0. , 0.84147098, 0.90929743, 0.14112001], [-0.7568025 , -0.95892427, -0.2794155 , 0.6569866 ], [ 0.98935825, 0.41211849, -0.54402111, -0.99999021], [-0.53657292, 0.42016704, 0.99060736, 0.65028784], [-0.28790332, -0.96139749, -0.75098725, 0.14987721]]) >>> # index of the maxima for each series >>> ind = data.argmax(axis=0) >>> ind array([2, 0, 3, 1]) >>> # times corresponding to the maxima >>> time_max = time[ind] >>> >>> data_max = data[ind, range(data.shape[1])] # => data[ind[0], 0], data[ind[1], 1]... >>> time_max array([ 82.5 , 20. , 113.75, 51.25]) >>> data_max array([0.98935825, 0.84147098, 0.99060736, 0.6569866 ]) >>> np.all(data_max == data.max(axis=0)) True You can also use indexing with arrays as a target to assign to: >>> a = np.arange(5) >>> a array([0, 1, 2, 3, 4]) >>> a[[1, 3, 4]] = 0 >>> a array([0, 0, 2, 0, 0]) However, when the list of indices contains repetitions, the assignment is done several times, leaving behind the last value: >>> a = np.arange(5) >>> a[[0, 0, 2]] = [1, 2, 3] >>> a array([2, 1, 3, 3, 4]) This is reasonable enough, but watch out if you want to use Python’s += construct, as it may not do what you expect: >>> a = np.arange(5) >>> a[[0, 0, 2]] += 1 >>> a array([1, 1, 3, 3, 4]) Even though 0 occurs twice in the list of indices, the 0th element is only incremented once. This is because Python requires a += 1 to be equivalent to a = a + 1. Indexing with boolean arrays# When we index arrays with arrays of (integer) indices we are providing the list of indices to pick. With boolean indices the approach is different; we explicitly choose which items in the array we want and which ones we don’t. The most natural way one can think of for boolean indexing is to use boolean arrays that have the same shape as the original array: >>> a = np.arange(12).reshape(3, 4) >>> b = a > 4 >>> b # `b` is a boolean with `a`'s shape array([[False, False, False, False], [False, True, True, True], [ True, True, True, True]]) >>> a[b] # 1d array with the selected elements array([ 5, 6, 7, 8, 9, 10, 11]) This property can be very useful in assignments: >>> a[b] = 0 # All elements of `a` higher than 4 become 0 >>> a array([[0, 1, 2, 3], [4, 0, 0, 0], [0, 0, 0, 0]]) You can look at the following example to see how to use boolean indexing to generate an image of the Mandelbrot set: >>> import numpy as np >>> import matplotlib.pyplot as plt >>> def mandelbrot(h, w, maxit=20, r=2): ... \"\"\"Returns an image of the Mandelbrot fractal of size (h,w).\"\"\" ... x = np.linspace(-2.5, 1.5, 4*h+1) ... y = np.linspace(-1.5, 1.5, 3*w+1) ... A, B = np.meshgrid(x, y) ... C = A + B*1j ... z = np.zeros_like(C) ... divtime = maxit + np.zeros(z.shape, dtype=np.int_) ... ... for i in range(maxit): ... z = z**2 + C ... diverge = abs(z) > r # who is diverging ... div_now = diverge & (divtime == maxit) # who is diverging now ... divtime[div_now] = i # note when ... z[diverge] = r # avoid diverging too much ... ... return divtime >>> plt.clf() >>> plt.imshow(mandelbrot(400, 400)) The second way of indexing with booleans is more similar to integer indexing; for each dimension of the array we give a 1D boolean array selecting the slices we want: >>> a = np.arange(12).reshape(3, 4) >>> b1 = np.array([False, True, True]) # first dim selection >>> b2 = np.array([True, False, True, False]) # second dim selection >>> >>> a[b1, :] # selecting rows array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> a[b1] # same thing array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> a[:, b2] # selecting columns array([[ 0, 2], [ 4, 6], [ 8, 10]]) >>> >>> a[b1, b2] # a weird thing to do array([ 4, 10]) Note that the length of the 1D boolean array must coincide with the length of the dimension (or axis) you want to slice. In the previous example, b1 has length 3 (the number of rows in a), and b2 (of length 4) is suitable to index the 2nd axis (columns) of a. The ix_() function# The ix_ function can be used to combine different vectors so as to obtain the result for each n-uplet. For example, if you want to compute all the a+b*c for all the triplets taken from each of the vectors a, b and c: >>> a = np.array([2, 3, 4, 5]) >>> b = np.array([8, 5, 4]) >>> c = np.array([5, 4, 6, 8, 3]) >>> ax, bx, cx = np.ix_(a, b, c) >>> ax array([[[2]], [[3]], [[4]], [[5]]]) >>> bx array([[[8], [5], [4]]]) >>> cx array([[[5, 4, 6, 8, 3]]]) >>> ax.shape, bx.shape, cx.shape ((4, 1, 1), (1, 3, 1), (1, 1, 5)) >>> result = ax + bx * cx >>> result array([[[42, 34, 50, 66, 26], [27, 22, 32, 42, 17], [22, 18, 26, 34, 14]], [[43, 35, 51, 67, 27], [28, 23, 33, 43, 18], [23, 19, 27, 35, 15]], [[44, 36, 52, 68, 28], [29, 24, 34, 44, 19], [24, 20, 28, 36, 16]], [[45, 37, 53, 69, 29], [30, 25, 35, 45, 20], [25, 21, 29, 37, 17]]]) >>> result[3, 2, 4] 17 >>> a[3] + b[2] * c[4] 17 You could also implement the reduce as follows: >>> def ufunc_reduce(ufct, *vectors): ... vs = np.ix_(*vectors) ... r = ufct.identity ... for v in r = ufct(r, v) ... return r and then use it as: >>> ufunc_reduce(np.add, a, b, c) array([[[15, 14, 16, 18, 13], [12, 11, 13, 15, 10], [11, 10, 12, 14, 9]], [[16, 15, 17, 19, 14], [13, 12, 14, 16, 11], [12, 11, 13, 15, 10]], [[17, 16, 18, 20, 15], [14, 13, 15, 17, 12], [13, 12, 14, 16, 11]], [[18, 17, 19, 21, 16], [15, 14, 16, 18, 13], [14, 13, 15, 17, 12]]]) The advantage of this version of reduce compared to the normal ufunc.reduce is that it makes use of the broadcasting rules in order to avoid creating a temporary array that needs as much memory as the output array multiplied by the number of vectors. Indexing with strings# See Structured arrays. Tricks and tips# Here we give a list of short and useful tips. “Automatic” reshaping# To change the dimensions of an array, you can omit one of the sizes which will then be deduced automatically: >>> a = np.arange(30) >>> b = a.reshape((2, -1, 3)) # -1 means \"whatever is needed\" >>> b.shape (2, 5, 3) >>> b array([[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]], [[15, 16, 17], [18, 19, 20], [21, 22, 23], [24, 25, 26], [27, 28, 29]]]) Vector stacking# How do we construct a 2D array from a list of equally-sized row vectors? In MATLAB this is quite x and y are two vectors of the same length you only need do m=[x;y]. In NumPy this works via the functions column_stack, dstack, hstack and vstack, depending on the dimension in which the stacking is to be done. For example: >>> x = np.arange(0, 10, 2) >>> y = np.arange(5) >>> m = np.vstack([x, y]) >>> m array([[0, 2, 4, 6, 8], [0, 1, 2, 3, 4]]) >>> xy = np.hstack([x, y]) >>> xy array([0, 2, 4, 6, 8, 0, 1, 2, 3, 4]) The logic behind those functions in more than two dimensions can be strange. See also NumPy for MATLAB users Histograms# The NumPy histogram function applied to an array returns a pair of histogram of the array and a vector of the bin edges. also has a function to build histograms (called hist, as in Matlab) that differs from the one in NumPy. The main difference is that pylab.hist plots the histogram automatically, while numpy.histogram only generates the data. >>> import numpy as np >>> rg = np.random.default_rng(1) >>> import matplotlib.pyplot as plt >>> # Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2 >>> mu, sigma = 2, 0.5 >>> v = rg.normal(mu, sigma, 10000) >>> # Plot a normalized histogram with 50 bins >>> plt.hist(v, bins=50, density=True) # matplotlib version (plot) (array...) >>> # Compute the histogram with numpy and then plot it >>> (n, bins) = np.histogram(v, bins=50, density=True) # NumPy version (no plot) >>> plt.plot(.5 * (bins[1:] + bins[:-1]), n) With Matplotlib >=3.4 you can also use plt.stairs(n, bins). Further reading# The Python tutorial NumPy reference SciPy Tutorial SciPy Lecture Notes A matlab, R, IDL, NumPy/SciPy dictionary tutorial-svd previous What is NumPy? next absolute basics for beginners On this page Prerequisites The basics An example Array creation Printing arrays Basic operations Universal functions Indexing, slicing and iterating Shape manipulation Changing the shape of an array Stacking together different arrays Splitting one array into several smaller ones Copies and views No copy at all View or shallow copy Deep copy Functions and methods overview Less basic Broadcasting rules Advanced indexing and index tricks Indexing with arrays of indices Indexing with boolean arrays The ix_() function Indexing with strings Tricks and tips “Automatic” reshaping Vector stacking Histograms Further reading\n\nExample:\n```text\n[[1., 0., 0.],\n [0., 1., 2.]]\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.arange(15).reshape(3, 5)\n>>> a\narray([[ 0,  1,  2,  3,  4],\n       [ 5,  6,  7,  8,  9],\n       [10, 11, 12, 13, 14]])\n>>> a.shape\n(3, 5)\n>>> a.ndim\n2\n>>> a.dtype.name\n'int64'\n>>> a.itemsize\n8\n>>> a.size\n15\n>>> type(a)\n<class 'numpy.ndarray'>\n>>> b = np.array([6, 7, 8])\n>>> b\narray([6, 7, 8])\n>>> type(b)\n<class 'numpy.ndarray'>\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> a = np.array([2, 3, 4])\n>>> a\narray([2, 3, 4])\n>>> a.dtype\ndtype('int64')\n>>> b = np.array([1.2, 3.5, 5.1])\n>>> b.dtype\ndtype('float64')\n```\n\nExample:\n```text\n>>> a = np.array(1, 2, 3, 4)    # WRONG\nTraceback (most recent call last):\n  ...\nTypeError: array() takes from 1 to 2 positional arguments but 4 were given\n>>> a = np.array([1, 2, 3, 4])  # RIGHT\n```\n\nExample:\n```text\n>>> b = np.array([(1.5, 2, 3), (4, 5, 6)])\n>>> b\narray([[1.5, 2. , 3. ],\n       [4. , 5. , 6. ]])\n```\n\nExample:\n```text\n>>> c = np.array([[1, 2], [3, 4]], dtype=np.complex128)\n>>> c\narray([[1.+0.j, 2.+0.j],\n       [3.+0.j, 4.+0.j]])\n```\n\nExample:\n```text\n>>> np.zeros((3, 4))\narray([[0., 0., 0., 0.],\n       [0., 0., 0., 0.],\n       [0., 0., 0., 0.]])\n>>> np.ones((2, 3, 4), dtype=np.int16)\narray([[[1, 1, 1, 1],\n        [1, 1, 1, 1],\n        [1, 1, 1, 1]],\n\n       [[1, 1, 1, 1],\n        [1, 1, 1, 1],\n        [1, 1, 1, 1]]], dtype=int16)\n>>> np.empty((2, 3)) \narray([[3.73603959e-262, 6.02658058e-154, 6.55490914e-260],  # may vary\n       [5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])\n```\n\nExample:\n```text\n>>> np.arange(10, 30, 5)\narray([10, 15, 20, 25])\n>>> np.arange(0, 2, 0.3)  # it accepts float arguments\narray([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])\n```\n\nExample:\n```text\n>>> from numpy import pi\n>>> np.linspace(0, 2, 9)                   # 9 numbers from 0 to 2\narray([0.  , 0.25, 0.5 , 0.75, 1.  , 1.25, 1.5 , 1.75, 2.  ])\n>>> x = np.linspace(0, 2 * pi, 100)        # useful to evaluate function at lots of points\n>>> f = np.sin(x)\n```\n\nExample:\n```text\n>>> a = np.arange(6)                    # 1d array\n>>> print(a)\n[0 1 2 3 4 5]\n>>>\n>>> b = np.arange(12).reshape(4, 3)     # 2d array\n>>> print(b)\n[[ 0  1  2]\n [ 3  4  5]\n [ 6  7  8]\n [ 9 10 11]]\n>>>\n>>> c = np.arange(24).reshape(2, 3, 4)  # 3d array\n>>> print(c)\n[[[ 0  1  2  3]\n  [ 4  5  6  7]\n  [ 8  9 10 11]]\n\n [[12 13 14 15]\n  [16 17 18 19]\n  [20 21 22 23]]]\n```\n\nExample:\n```text\n>>> print(np.arange(10000))\n[   0    1    2 ... 9997 9998 9999]\n>>>\n>>> print(np.arange(10000).reshape(100, 100))\n[[   0    1    2 ...   97   98   99]\n [ 100  101  102 ...  197  198  199]\n [ 200  201  202 ...  297  298  299]\n ...\n [9700 9701 9702 ... 9797 9798 9799]\n [9800 9801 9802 ... 9897 9898 9899]\n [9900 9901 9902 ... 9997 9998 9999]]\n```\n\nExample:\n```text\n>>> np.set_printoptions(threshold=sys.maxsize)  # sys module should be imported\n```\n\nExample:\n```text\n>>> a = np.array([20, 30, 40, 50])\n>>> b = np.arange(4)\n>>> b\narray([0, 1, 2, 3])\n>>> c = a - b\n>>> c\narray([20, 29, 38, 47])\n>>> b**2\narray([0, 1, 4, 9])\n>>> 10 * np.sin(a)\narray([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])\n>>> a < 35\narray([ True,  True, False, False])\n```\n\nExample:\n```text\n>>> A = np.array([[1, 1],\n...               [0, 1]])\n>>> B = np.array([[2, 0],\n...               [3, 4]])\n>>> A * B     # elementwise product\narray([[2, 0],\n       [0, 4]])\n>>> A @ B     # matrix product\narray([[5, 4],\n       [3, 4]])\n>>> A.dot(B)  # another matrix product\narray([[5, 4],\n       [3, 4]])\n```\n\nExample:\n```text\n>>> rg = np.random.default_rng(1)  # create instance of default random number generator\n>>> a = np.ones((2, 3), dtype=np.int_)\n>>> b = rg.random((2, 3))\n>>> a *= 3\n>>> a\narray([[3, 3, 3],\n       [3, 3, 3]])\n>>> b += a\n>>> b\narray([[3.51182162, 3.9504637 , 3.14415961],\n       [3.94864945, 3.31183145, 3.42332645]])\n>>> a += b  # b is not automatically converted to integer type\nTraceback (most recent call last):\n    ...\nnumpy._core._exceptions._UFuncOutputCastingError: Cannot cast ufunc 'add' output from dtype('float64') to dtype('int64') with casting rule 'same_kind'\n```\n\nExample:\n```text\n>>> a = np.ones(3, dtype=np.int32)\n>>> b = np.linspace(0, pi, 3)\n>>> b.dtype.name\n'float64'\n>>> c = a + b\n>>> c\narray([1.        , 2.57079633, 4.14159265])\n>>> c.dtype.name\n'float64'\n>>> d = np.exp(c * 1j)\n>>> d\narray([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,\n       -0.54030231-0.84147098j])\n>>> d.dtype.name\n'complex128'\n```\n\nExample:\n```text\n>>> a = rg.random((2, 3))\n>>> a\narray([[0.82770259, 0.40919914, 0.54959369],\n       [0.02755911, 0.75351311, 0.53814331]])\n>>> a.sum()\n3.1057109529998157\n>>> a.min()\n0.027559113243068367\n>>> a.max()\n0.8277025938204418\n```\n\nExample:\n```text\n>>> b = np.arange(12).reshape(3, 4)\n>>> b\narray([[ 0,  1,  2,  3],\n       [ 4,  5,  6,  7],\n       [ 8,  9, 10, 11]])\n>>>\n>>> b.sum(axis=0)     # sum of each column\narray([12, 15, 18, 21])\n>>>\n>>> b.min(axis=1)     # min of each row\narray([0, 4, 8])\n>>>\n>>> b.cumsum(axis=1)  # cumulative sum along each row\narray([[ 0,  1,  3,  6],\n       [ 4,  9, 15, 22],\n       [ 8, 17, 27, 38]])\n```\n\nExample:\n```text\n>>> B = np.arange(3)\n>>> B\narray([0, 1, 2])\n>>> np.exp(B)\narray([1.        , 2.71828183, 7.3890561 ])\n>>> np.sqrt(B)\narray([0.        , 1.        , 1.41421356])\n>>> C = np.array([2., -1., 4.])\n>>> np.add(B, C)\narray([2., 0., 6.])\n```\n\nExample:\n```text\n>>> a = np.arange(10)**3\n>>> a\narray([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])\n>>> a[2]\n8\n>>> a[2:5]\narray([ 8, 27, 64])\n>>> # equivalent to a[0:6:2] = 1000;\n>>> # from start to position 6, exclusive, set every 2nd element to 1000\n>>> a[:6:2] = 1000\n>>> a\narray([1000,    1, 1000,   27, 1000,  125,  216,  343,  512,  729])\n>>> a[::-1]  # reversed a\narray([ 729,  512,  343,  216,  125, 1000,   27, 1000,    1, 1000])\n>>> for i in a:\n...     print(i**(1 / 3.))\n...\n9.999999999999998  # may vary\n1.0\n9.999999999999998\n3.0\n9.999999999999998\n4.999999999999999\n5.999999999999999\n6.999999999999999\n7.999999999999999\n8.999999999999998\n```\n\nExample:\n```text\n>>> def f(x, y):\n...     return 10 * x + y\n...\n>>> b = np.fromfunction(f, (5, 4), dtype=np.int_)\n>>> b\narray([[ 0,  1,  2,  3],\n       [10, 11, 12, 13],\n       [20, 21, 22, 23],\n       [30, 31, 32, 33],\n       [40, 41, 42, 43]])\n>>> b[2, 3]\n23\n>>> b[0:5, 1]  # each row in the second column of b\narray([ 1, 11, 21, 31, 41])\n>>> b[:, 1]    # equivalent to the previous example\narray([ 1, 11, 21, 31, 41])\n>>> b[1:3, :]  # each column in the second and third row of b\narray([[10, 11, 12, 13],\n       [20, 21, 22, 23]])\n```\n\nExample:\n```text\n>>> b[-1]   # the last row. Equivalent to b[-1, :]\narray([40, 41, 42, 43])\n```\n\nExample:\n```text\n>>> c = np.array([[[  0,  1,  2],  # a 3D array (two stacked 2D arrays)\n...                [ 10, 12, 13]],\n...               [[100, 101, 102],\n...                [110, 112, 113]]])\n>>> c.shape\n(2, 2, 3)\n>>> c[1, ...]  # same as c[1, :, :] or c[1]\narray([[100, 101, 102],\n       [110, 112, 113]])\n>>> c[..., 2]  # same as c[:, :, 2]\narray([[  2,  13],\n       [102, 113]])\n```\n\nExample:\n```text\n>>> for row in b:\n...     print(row)\n...\n[0 1 2 3]\n[10 11 12 13]\n[20 21 22 23]\n[30 31 32 33]\n[40 41 42 43]\n```\n\nExample:\n```text\n>>> for element in b.flat:\n...     print(element)\n...\n0\n1\n2\n3\n10\n11\n12\n13\n20\n21\n22\n23\n30\n31\n32\n33\n40\n41\n42\n43\n```\n\nExample:\n```text\n>>> a = np.floor(10 * rg.random((3, 4)))\n>>> a\narray([[3., 7., 3., 4.],\n       [1., 4., 2., 2.],\n       [7., 2., 4., 9.]])\n>>> a.shape\n(3, 4)\n```\n\nExample:\n```text\n>>> a.ravel()  # returns the array, flattened\narray([3., 7., 3., 4., 1., 4., 2., 2., 7., 2., 4., 9.])\n>>> a.reshape(6, 2)  # returns the array with a modified shape\narray([[3., 7.],\n       [3., 4.],\n       [1., 4.],\n       [2., 2.],\n       [7., 2.],\n       [4., 9.]])\n>>> a.T  # returns the array, transposed\narray([[3., 1., 7.],\n       [7., 4., 2.],\n       [3., 2., 4.],\n       [4., 2., 9.]])\n>>> a.T.shape\n(4, 3)\n>>> a.shape\n(3, 4)\n```\n\nExample:\n```text\n>>> a\narray([[3., 7., 3., 4.],\n       [1., 4., 2., 2.],\n       [7., 2., 4., 9.]])\n>>> a.resize((2, 6))\n>>> a\narray([[3., 7., 3., 4., 1., 4.],\n       [2., 2., 7., 2., 4., 9.]])\n```\n\nExample:\n```text\n>>> a.reshape(3, -1)\narray([[3., 7., 3., 4.],\n       [1., 4., 2., 2.],\n       [7., 2., 4., 9.]])\n```\n\nExample:\n```text\n>>> a = np.floor(10 * rg.random((2, 2)))\n>>> a\narray([[9., 7.],\n       [5., 2.]])\n>>> b = np.floor(10 * rg.random((2, 2)))\n>>> b\narray([[1., 9.],\n       [5., 1.]])\n>>> np.vstack((a, b))\narray([[9., 7.],\n       [5., 2.],\n       [1., 9.],\n       [5., 1.]])\n>>> np.hstack((a, b))\narray([[9., 7., 1., 9.],\n       [5., 2., 5., 1.]])\n```\n\nExample:\n```text\n>>> from numpy import newaxis\n>>> np.column_stack((a, b))  # with 2D arrays\narray([[9., 7., 1., 9.],\n       [5., 2., 5., 1.]])\n>>> a = np.array([4., 2.])\n>>> b = np.array([3., 8.])\n>>> np.column_stack((a, b))  # returns a 2D array\narray([[4., 3.],\n       [2., 8.]])\n>>> np.hstack((a, b))        # the result is different\narray([4., 2., 3., 8.])\n>>> a[:, newaxis]  # view `a` as a 2D column vector\narray([[4.],\n       [2.]])\n>>> np.column_stack((a[:, newaxis], b[:, newaxis]))\narray([[4., 3.],\n       [2., 8.]])\n>>> np.hstack((a[:, newaxis], b[:, newaxis]))  # the result is the same\narray([[4., 3.],\n       [2., 8.]])\n```\n\nExample:\n```text\n>>> np.r_[1:4, 0, 4]\narray([1, 2, 3, 0, 4])\n```\n\nExample:\n```text\n>>> a = np.floor(10 * rg.random((2, 12)))\n>>> a\narray([[6., 7., 6., 9., 0., 5., 4., 0., 6., 8., 5., 2.],\n       [8., 5., 5., 7., 1., 8., 6., 7., 1., 8., 1., 0.]])\n>>> # Split `a` into 3\n>>> np.hsplit(a, 3)\n[array([[6., 7., 6., 9.],\n       [8., 5., 5., 7.]]), array([[0., 5., 4., 0.],\n       [1., 8., 6., 7.]]), array([[6., 8., 5., 2.],\n       [1., 8., 1., 0.]])]\n>>> # Split `a` after the third and the fourth column\n>>> np.hsplit(a, (3, 4))\n[array([[6., 7., 6.],\n       [8., 5., 5.]]), array([[9.],\n       [7.]]), array([[0., 5., 4., 0., 6., 8., 5., 2.],\n       [1., 8., 6., 7., 1., 8., 1., 0.]])]\n```\n\nExample:\n```text\n>>> a = np.array([[ 0,  1,  2,  3],\n...               [ 4,  5,  6,  7],\n...               [ 8,  9, 10, 11]])\n>>> b = a            # no new object is created\n>>> b is a           # a and b are two names for the same ndarray object\nTrue\n```\n\nExample:\n```text\n>>> def f(x):\n...     print(id(x))\n...\n>>> id(a)  # id is a unique identifier of an object \n148293216  # may vary\n>>> f(a)   \n148293216  # may vary\n```\n\nExample:\n```text\n>>> c = a.view()\n>>> c is a\nFalse\n>>> c.base is a            # c is a view of the data owned by a\nTrue\n>>> c.flags.owndata\nFalse\n>>>\n>>> c = c.reshape((2, 6))  # a's shape doesn't change, reassigned c is still a view of a\n>>> a.shape\n(3, 4)\n>>> c[0, 4] = 1234         # a's data changes\n>>> a\narray([[   0,    1,    2,    3],\n       [1234,    5,    6,    7],\n       [   8,    9,   10,   11]])\n```\n\nExample:\n```text\n>>> s = a[:, 1:3]\n>>> s[:] = 10  # s[:] is a view of s. Note the difference between s = 10 and s[:] = 10\n>>> a\narray([[   0,   10,   10,    3],\n       [1234,   10,   10,    7],\n       [   8,   10,   10,   11]])\n```\n\nExample:\n```text\n>>> d = a.copy()  # a new array object with new data is created\n>>> d is a\nFalse\n>>> d.base is a  # d doesn't share anything with a\nFalse\n>>> d[0, 0] = 9999\n>>> a\narray([[   0,   10,   10,    3],\n       [1234,   10,   10,    7],\n       [   8,   10,   10,   11]])\n```\n\nExample:\n```text\n>>> a = np.arange(int(1e8))\n>>> b = a[:100].copy()\n>>> del a  # the memory of ``a`` can be released.\n```\n\nExample:\n```text\n>>> a = np.arange(12)**2  # the first 12 square numbers\n>>> i = np.array([1, 1, 3, 8, 5])  # an array of indices\n>>> a[i]  # the elements of `a` at the positions `i`\narray([ 1,  1,  9, 64, 25])\n>>>\n>>> j = np.array([[3, 4], [9, 7]])  # a bidimensional array of indices\n>>> a[j]  # the same shape as `j`\narray([[ 9, 16],\n       [81, 49]])\n```\n\nExample:\n```text\n>>> palette = np.array([[0, 0, 0],         # black\n...                     [255, 0, 0],       # red\n...                     [0, 255, 0],       # green\n...                     [0, 0, 255],       # blue\n...                     [255, 255, 255]])  # white\n>>> image = np.array([[0, 1, 2, 0],  # each value corresponds to a color in the palette\n...                   [0, 3, 4, 0]])\n>>> palette[image]  # the (2, 4, 3) color image\narray([[[  0,   0,   0],\n        [255,   0,   0],\n        [  0, 255,   0],\n        [  0,   0,   0]],\n\n       [[  0,   0,   0],\n        [  0,   0, 255],\n        [255, 255, 255],\n        [  0,   0,   0]]])\n```\n\nExample:\n```text\n>>> a = np.arange(12).reshape(3, 4)\n>>> a\narray([[ 0,  1,  2,  3],\n       [ 4,  5,  6,  7],\n       [ 8,  9, 10, 11]])\n>>> i = np.array([[0, 1],  # indices for the first dim of `a`\n...               [1, 2]])\n>>> j = np.array([[2, 1],  # indices for the second dim\n...               [3, 3]])\n>>>\n>>> a[i, j]  # i and j must have equal shape\narray([[ 2,  5],\n       [ 7, 11]])\n>>>\n>>> a[i, 2]\narray([[ 2,  6],\n       [ 6, 10]])\n>>>\n>>> a[:, j]\narray([[[ 2,  1],\n        [ 3,  3]],\n\n       [[ 6,  5],\n        [ 7,  7]],\n\n       [[10,  9],\n        [11, 11]]])\n```\n\nExample:\n```text\n>>> l = (i, j)\n>>> # equivalent to a[i, j]\n>>> a[l]\narray([[ 2,  5],\n       [ 7, 11]])\n```\n\nExample:\n```text\n>>> s = np.array([i, j])\n>>> # not what we want\n>>> a[s]\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\nIndexError: index 3 is out of bounds for axis 0 with size 3\n>>> # same as `a[i, j]`\n>>> a[tuple(s)]\narray([[ 2,  5],\n       [ 7, 11]])\n```\n\nExample:\n```text\n>>> time = np.linspace(20, 145, 5)  # time scale\n>>> data = np.sin(np.arange(20)).reshape(5, 4)  # 4 time-dependent series\n>>> time\narray([ 20.  ,  51.25,  82.5 , 113.75, 145.  ])\n>>> data\narray([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],\n       [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],\n       [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],\n       [-0.53657292,  0.42016704,  0.99060736,  0.65028784],\n       [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])\n>>> # index of the maxima for each series\n>>> ind = data.argmax(axis=0)\n>>> ind\narray([2, 0, 3, 1])\n>>> # times corresponding to the maxima\n>>> time_max = time[ind]\n>>>\n>>> data_max = data[ind, range(data.shape[1])]  # => data[ind[0], 0], data[ind[1], 1]...\n>>> time_max\narray([ 82.5 ,  20.  , 113.75,  51.25])\n>>> data_max\narray([0.98935825, 0.84147098, 0.99060736, 0.6569866 ])\n>>> np.all(data_max == data.max(axis=0))\nTrue\n```\n\nExample:\n```text\n>>> a = np.arange(5)\n>>> a\narray([0, 1, 2, 3, 4])\n>>> a[[1, 3, 4]] = 0\n>>> a\narray([0, 0, 2, 0, 0])\n```\n\nExample:\n```text\n>>> a = np.arange(5)\n>>> a[[0, 0, 2]] = [1, 2, 3]\n>>> a\narray([2, 1, 3, 3, 4])\n```\n\nExample:\n```text\n>>> a = np.arange(5)\n>>> a[[0, 0, 2]] += 1\n>>> a\narray([1, 1, 3, 3, 4])\n```\n\nExample:\n```text\n>>> a = np.arange(12).reshape(3, 4)\n>>> b = a > 4\n>>> b  # `b` is a boolean with `a`'s shape\narray([[False, False, False, False],\n       [False,  True,  True,  True],\n       [ True,  True,  True,  True]])\n>>> a[b]  # 1d array with the selected elements\narray([ 5,  6,  7,  8,  9, 10, 11])\n```\n\nExample:\n```text\n>>> a[b] = 0  # All elements of `a` higher than 4 become 0\n>>> a\narray([[0, 1, 2, 3],\n       [4, 0, 0, 0],\n       [0, 0, 0, 0]])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> import matplotlib.pyplot as plt\n>>> def mandelbrot(h, w, maxit=20, r=2):\n...     \"\"\"Returns an image of the Mandelbrot fractal of size (h,w).\"\"\"\n...     x = np.linspace(-2.5, 1.5, 4*h+1)\n...     y = np.linspace(-1.5, 1.5, 3*w+1)\n...     A, B = np.meshgrid(x, y)\n...     C = A + B*1j\n...     z = np.zeros_like(C)\n...     divtime = maxit + np.zeros(z.shape, dtype=np.int_)\n...\n...     for i in range(maxit):\n...         z = z**2 + C\n...         diverge = abs(z) > r                    # who is diverging\n...         div_now = diverge & (divtime == maxit)  # who is diverging now\n...         divtime[div_now] = i                    # note when\n...         z[diverge] = r                          # avoid diverging too much\n...\n...     return divtime\n>>> plt.clf()\n>>> plt.imshow(mandelbrot(400, 400))\n```\n\nExample:\n```text\n>>> a = np.arange(12).reshape(3, 4)\n>>> b1 = np.array([False, True, True])         # first dim selection\n>>> b2 = np.array([True, False, True, False])  # second dim selection\n>>>\n>>> a[b1, :]                                   # selecting rows\narray([[ 4,  5,  6,  7],\n       [ 8,  9, 10, 11]])\n>>>\n>>> a[b1]                                      # same thing\narray([[ 4,  5,  6,  7],\n       [ 8,  9, 10, 11]])\n>>>\n>>> a[:, b2]                                   # selecting columns\narray([[ 0,  2],\n       [ 4,  6],\n       [ 8, 10]])\n>>>\n>>> a[b1, b2]                                  # a weird thing to do\narray([ 4, 10])\n```\n\nExample:\n```text\n>>> a = np.array([2, 3, 4, 5])\n>>> b = np.array([8, 5, 4])\n>>> c = np.array([5, 4, 6, 8, 3])\n>>> ax, bx, cx = np.ix_(a, b, c)\n>>> ax\narray([[[2]],\n\n       [[3]],\n\n       [[4]],\n\n       [[5]]])\n>>> bx\narray([[[8],\n        [5],\n        [4]]])\n>>> cx\narray([[[5, 4, 6, 8, 3]]])\n>>> ax.shape, bx.shape, cx.shape\n((4, 1, 1), (1, 3, 1), (1, 1, 5))\n>>> result = ax + bx * cx\n>>> result\narray([[[42, 34, 50, 66, 26],\n        [27, 22, 32, 42, 17],\n        [22, 18, 26, 34, 14]],\n\n       [[43, 35, 51, 67, 27],\n        [28, 23, 33, 43, 18],\n        [23, 19, 27, 35, 15]],\n\n       [[44, 36, 52, 68, 28],\n        [29, 24, 34, 44, 19],\n        [24, 20, 28, 36, 16]],\n\n       [[45, 37, 53, 69, 29],\n        [30, 25, 35, 45, 20],\n        [25, 21, 29, 37, 17]]])\n>>> result[3, 2, 4]\n17\n>>> a[3] + b[2] * c[4]\n17\n```\n\nExample:\n```text\n>>> def ufunc_reduce(ufct, *vectors):\n...    vs = np.ix_(*vectors)\n...    r = ufct.identity\n...    for v in vs:\n...        r = ufct(r, v)\n...    return r\n```\n\nExample:\n```text\n>>> ufunc_reduce(np.add, a, b, c)\narray([[[15, 14, 16, 18, 13],\n        [12, 11, 13, 15, 10],\n        [11, 10, 12, 14,  9]],\n\n       [[16, 15, 17, 19, 14],\n        [13, 12, 14, 16, 11],\n        [12, 11, 13, 15, 10]],\n\n       [[17, 16, 18, 20, 15],\n        [14, 13, 15, 17, 12],\n        [13, 12, 14, 16, 11]],\n\n       [[18, 17, 19, 21, 16],\n        [15, 14, 16, 18, 13],\n        [14, 13, 15, 17, 12]]])\n```\n\nExample:\n```text\n>>> a = np.arange(30)\n>>> b = a.reshape((2, -1, 3))  # -1 means \"whatever is needed\"\n>>> b.shape\n(2, 5, 3)\n>>> b\narray([[[ 0,  1,  2],\n        [ 3,  4,  5],\n        [ 6,  7,  8],\n        [ 9, 10, 11],\n        [12, 13, 14]],\n\n       [[15, 16, 17],\n        [18, 19, 20],\n        [21, 22, 23],\n        [24, 25, 26],\n        [27, 28, 29]]])\n```\n\nExample:\n```text\n>>> x = np.arange(0, 10, 2)\n>>> y = np.arange(5)\n>>> m = np.vstack([x, y])\n>>> m\narray([[0, 2, 4, 6, 8],\n       [0, 1, 2, 3, 4]])\n>>> xy = np.hstack([x, y])\n>>> xy\narray([0, 2, 4, 6, 8, 0, 1, 2, 3, 4])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> rg = np.random.default_rng(1)\n>>> import matplotlib.pyplot as plt\n>>> # Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2\n>>> mu, sigma = 2, 0.5\n>>> v = rg.normal(mu, sigma, 10000)\n>>> # Plot a normalized histogram with 50 bins\n>>> plt.hist(v, bins=50, density=True)       # matplotlib version (plot)\n(array...)\n>>> # Compute the histogram with numpy and then plot it\n>>> (n, bins) = np.histogram(v, bins=50, density=True)  # NumPy version (no plot)\n>>> plt.plot(.5 * (bins[1:] + bins[:-1]), n)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:56.005Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":58,"totalLines":919,"estimatedTokens":13359}}18{"id":"doc-numpy_the_absolute_basics_for_beginners_numpy_v2-ee9416b4","source":"documentation","title":"NumPy: the absolute basics for beginners — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/absolute_beginners.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide absolute basics for beginners absolute basics for beginners# Welcome to the absolute beginner’s guide to NumPy! NumPy (Numerical Python) is an open source Python library that’s widely used in science and engineering. The NumPy library contains multidimensional array data structures, such as the homogeneous, N-dimensional ndarray, and a large library of functions that operate efficiently on these data structures. Learn more about NumPy at What is NumPy, and if you have comments or suggestions, please reach out! How to import NumPy# After installing NumPy, it may be imported into Python code numpy as np This widespread convention allows access to NumPy features with a short, recognizable prefix (np.) while distinguishing NumPy features from others that have the same name. Reading the example code# Throughout the NumPy documentation, you will find blocks that look like: >>> a = np.array([[1, 2, 3], ... [4, 5, 6]]) >>> a.shape (2, 3) Text preceded by >>> or ... is input, the code that you would enter in a script or at a Python prompt. Everything else is output, the results of running your code. Note that >>> and ... are not part of the code and may cause an error if entered at a Python prompt. To run the code in the examples, you can copy and paste it into a Python script or REPL, or use the experimental interactive examples in the browser provided in various locations in the documentation. Why use NumPy?# Python lists are excellent, general-purpose containers. They can be “heterogeneous”, meaning that they can contain elements of a variety of types, and they are quite fast when used to perform individual operations on a handful of elements. Depending on the characteristics of the data and the types of operations that need to be performed, other containers may be more appropriate; by exploiting these characteristics, we can improve speed, reduce memory consumption, and offer a high-level syntax for performing a variety of common processing tasks. NumPy shines when there are large quantities of “homogeneous” (same-type) data to be processed on the CPU. What is an “array”?# In computer programming, an array is a structure for storing and retrieving data. We often talk about an array as if it were a grid in space, with each cell storing one element of the data. For instance, if each element of the data were a number, we might visualize a “one-dimensional” array like a list: \\[\\begin{split}\\begin{array}{|c||c|c|c|} \\hline 1 & 5 & 2 & 0 \\\\ \\hline \\end{array}\\end{split}\\] A two-dimensional array would be like a table: \\[\\begin{split}\\begin{array}{|c||c|c|c|} \\hline 1 & 5 & 2 & 0 \\\\ \\hline 8 & 3 & 6 & 1 \\\\ \\hline 1 & 7 & 2 & 9 \\\\ \\hline \\end{array}\\end{split}\\] A three-dimensional array would be like a set of tables, perhaps stacked as though they were printed on separate pages. In NumPy, this idea is generalized to an arbitrary number of dimensions, and so the fundamental array class is called represents an “N-dimensional array”. Most NumPy arrays have some restrictions. For elements of the array must be of the same type of data. Once created, the total size of the array can’t change. The shape must be “rectangular”, not “jagged”; e.g., each row of a two-dimensional array must have the same number of columns. When these conditions are met, NumPy exploits these characteristics to make the array faster, more memory efficient, and more convenient to use than less restrictive data structures. For the remainder of this document, we will use the word “array” to refer to an instance of ndarray. Array fundamentals# One way to initialize an array is using a Python sequence, such as a list. For example: >>> a = np.array([1, 2, 3, 4, 5, 6]) >>> a array([1, 2, 3, 4, 5, 6]) Elements of an array can be accessed in various ways. For instance, we can access an individual element of this array as we would access an element in the original the integer index of the element within square brackets. >>> a[0] 1 Note As with built-in Python sequences, NumPy arrays are “0-indexed”: the first element of the array is accessed using index 0, not 1. Like the original list, the array is mutable. >>> a[0] = 10 >>> a array([10, 2, 3, 4, 5, 6]) Also like the original list, Python slice notation can be used for indexing. >>> a[:3] array([10, 2, 3]) One major difference is that slice indexing of a list copies the elements into a new list, but slicing an array returns a object that refers to the data in the original array. The original array can be mutated using the view. >>> b = a[3:] >>> b array([4, 5, 6]) >>> b[0] = 40 >>> a array([ 10, 2, 3, 40, 5, 6]) See Copies and views for a more comprehensive explanation of when array operations return views rather than copies. Two- and higher-dimensional arrays can be initialized from nested Python sequences: >>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) >>> a array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) In NumPy, a dimension of an array is sometimes referred to as an “axis”. This terminology may be useful to disambiguate between the dimensionality of an array and the dimensionality of the data represented by the array. For instance, the array a could represent three points, each lying within a four-dimensional space, but a has only two “axes”. Another difference between an array and a list of lists is that an element of the array can be accessed by specifying the index along each axis within a single set of square brackets, separated by commas. For instance, the element 8 is in row 1 and column 3: >>> a[1, 3] 8 Note It is familiar practice in mathematics to refer to elements of a matrix by the row index first and the column index second. This happens to be true for two-dimensional arrays, but a better mental model is to think of the column index as coming last and the row index as second to last. This generalizes to arrays with any number of dimensions. Note You might hear of a 0-D (zero-dimensional) array referred to as a “scalar”, a 1-D (one-dimensional) array as a “vector”, a 2-D (two-dimensional) array as a “matrix”, or an N-D (N-dimensional, where “N” is typically an integer greater than 2) array as a “tensor”. For clarity, it is best to avoid the mathematical terms when referring to an array because the mathematical objects with these names behave differently than arrays (e.g. “matrix” multiplication is fundamentally different from “array” multiplication), and there are other objects in the scientific Python ecosystem that have these names (e.g. the fundamental data structure of PyTorch is the “tensor”). Array attributes# This section covers the ndim, shape, size, and dtype attributes of an array. The number of dimensions of an array is contained in the ndim attribute. >>> a.ndim 2 The shape of an array is a tuple of non-negative integers that specify the number of elements along each dimension. >>> a.shape (3, 4) >>> len(a.shape) == a.ndim True The fixed, total number of elements in array is contained in the size attribute. >>> a.size 12 >>> import math >>> a.size == math.prod(a.shape) True Arrays are typically “homogeneous”, meaning that they contain elements of only one “data type”. The data type is recorded in the dtype attribute. >>> a.dtype dtype('int64') # \"int\" for integer, \"64\" for 64-bit Read more about array attributes here and learn about array objects here. How to create a basic array# This section covers np.zeros(), np.ones(), np.empty(), np.arange(), np.linspace() Besides creating an array from a sequence of elements, you can easily create an array filled with 0’s: >>> np.zeros(2) array([0., 0.]) Or an array filled with 1’s: >>> np.ones(2) array([1., 1.]) Or even an empty array! The function empty creates an array whose initial content is random and depends on the state of the memory. The reason to use empty over zeros (or something similar) is speed - just make sure to fill every element afterwards! >>> # Create an empty array with 2 elements >>> np.empty(2) array([3.14, 42. ]) # may vary You can create an array with a range of elements: >>> np.arange(4) array([0, 1, 2, 3]) And even an array that contains a range of evenly spaced intervals. To do this, you will specify the first number, last number, and the step size. >>> np.arange(2, 9, 2) array([2, 4, 6, 8]) You can also use np.linspace() to create an array with values that are spaced linearly in a specified interval: >>> np.linspace(0, 10, num=5) array([ 0. , 2.5, 5. , 7.5, 10. ]) Specifying your data type While the default data type is floating point (np.float64), you can explicitly specify which data type you want using the dtype keyword. >>> x = np.ones(2, dtype=np.int64) >>> x array([1, 1]) Learn more about creating arrays here Adding, removing, and sorting elements# This section covers np.sort(), np.concatenate() Sorting an array is simple with np.sort(). You can specify the axis, kind, and order when you call the function. If you start with this array: >>> arr = np.array([2, 1, 5, 3, 7, 4, 6, 8]) You can quickly sort the numbers in ascending order with: >>> np.sort(arr) array([1, 2, 3, 4, 5, 6, 7, 8]) In addition to sort, which returns a sorted copy of an array, you can , which is an indirect sort along a specified axis, lexsort, which is an indirect stable sort on multiple keys, searchsorted, which will find elements in a sorted array, and partition, which is a partial sort. To read more about sorting an array, If you start with these arrays: >>> a = np.array([1, 2, 3, 4]) >>> b = np.array([5, 6, 7, 8]) You can concatenate them with np.concatenate(). >>> np.concatenate((a, b)) array([1, 2, 3, 4, 5, 6, 7, 8]) Or, if you start with these arrays: >>> x = np.array([[1, 2], [3, 4]]) >>> y = np.array([[5, 6]]) You can concatenate them with: >>> np.concatenate((x, y), axis=0) array([[1, 2], [3, 4], [5, 6]]) In order to remove elements from an array, it’s simple to use indexing to select the elements that you want to keep. To read more about concatenate, How do you know the shape and size of an array?# This section covers ndarray.ndim, ndarray.size, ndarray.shape ndarray.ndim will tell you the number of axes, or dimensions, of the array. ndarray.size will tell you the total number of elements of the array. This is the product of the elements of the array’s shape. ndarray.shape will display a tuple of integers that indicate the number of elements stored along each dimension of the array. If, for example, you have a 2-D array with 2 rows and 3 columns, the shape of your array is (2, 3). For example, if you create this array: >>> array_example = np.array([[[0, 1, 2, 3], ... [4, 5, 6, 7]], ... ... [[0, 1, 2, 3], ... [4, 5, 6, 7]], ... ... [[0 ,1 ,2, 3], ... [4, 5, 6, 7]]]) To find the number of dimensions of the array, run: >>> array_example.ndim 3 To find the total number of elements in the array, run: >>> array_example.size 24 And to find the shape of your array, run: >>> array_example.shape (3, 2, 4) Can you reshape an array?# This section covers arr.reshape() Yes! Using arr.reshape() will return a reshaped array without changing the data. Just remember that when you use the reshape method, the array you want to produce needs to have the same number of elements as the original array. If you start with an array with 12 elements, you’ll need to make sure that your new array also has a total of 12 elements. If you start with this array: >>> a = np.arange(6) >>> print(a) [0 1 2 3 4 5] You can use reshape() to reshape your array. For example, you can reshape this array to an array with three rows and two columns: >>> b = a.reshape(3, 2) >>> print(b) [[0 1] [2 3] [4 5]] With np.reshape, you can specify a few optional parameters: >>> np.reshape(a, shape=(1, 6), order='C') array([[0, 1, 2, 3, 4, 5]]) a is the array to be reshaped. shape is the new shape you want. You can specify an integer or a tuple of integers. If you specify an integer, the result will be an array of that length. The shape should be compatible with the original shape. means to read/write the elements using C-like index order, F means to read/write the elements using Fortran-like index order, A means to read/write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise. (This is an optional parameter and doesn’t need to be specified.) If you want to learn more about C and Fortran order, you can read more about the internal organization of NumPy arrays here. Essentially, C and Fortran orders have to do with how indices correspond to the order the array is stored in memory. In Fortran, when moving through the elements of a two-dimensional array as it is stored in memory, the first index is the most rapidly varying index. As the first index moves to the next row as it changes, the matrix is stored one column at a time. This is why Fortran is thought of as a Column-major language. In C on the other hand, the last index changes the most rapidly. The matrix is stored by rows, making it a Row-major language. What you do for C or Fortran depends on whether it’s more important to preserve the indexing convention or not reorder the data. Learn more about shape manipulation here. How to convert a 1D array into a 2D array (how to add a new axis to an array)# This section covers np.newaxis, np.expand_dims You can use np.newaxis and np.expand_dims to increase the dimensions of your existing array. Using np.newaxis will increase the dimensions of your array by one dimension when used once. This means that a 1D array will become a 2D array, a 2D array will become a 3D array, and so on. For example, if you start with this array: >>> a = np.array([1, 2, 3, 4, 5, 6]) >>> a.shape (6,) You can use np.newaxis to add a new axis: >>> a2 = a[np.newaxis, :] >>> a2.shape (1, 6) You can explicitly convert a 1D array to either a row vector or a column vector using np.newaxis. For example, you can convert a 1D array to a row vector by inserting an axis along the first dimension: >>> row_vector = a[np.newaxis, :] >>> row_vector.shape (1, 6) Or, for a column vector, you can insert an axis along the second dimension: >>> col_vector = a[:, np.newaxis] >>> col_vector.shape (6, 1) You can also expand an array by inserting a new axis at a specified position with np.expand_dims. For example, if you start with this array: >>> a = np.array([1, 2, 3, 4, 5, 6]) >>> a.shape (6,) You can use np.expand_dims to add an axis at index position 1 with: >>> b = np.expand_dims(a, axis=1) >>> b.shape (6, 1) You can add an axis at index position 0 with: >>> c = np.expand_dims(a, axis=0) >>> c.shape (1, 6) Find more information about newaxis here and expand_dims at expand_dims. Indexing and slicing# You can index and slice NumPy arrays in the same ways you can slice Python lists. >>> data = np.array([1, 2, 3]) >>> data[1] 2 >>> data[0:2] array([1, 2]) >>> data[1:] array([2, 3]) >>> data[-2:] array([2, 3]) You can visualize it this may want to take a section of your array or specific array elements to use in further analysis or additional operations. To do that, you’ll need to subset, slice, and/or index your arrays. If you want to select values from your array that fulfill certain conditions, it’s straightforward with NumPy. For example, if you start with this array: >>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) You can easily print all of the values in the array that are less than 5. >>> print(a[a < 5]) [1 2 3 4] You can also select, for example, numbers that are equal to or greater than 5, and use that condition to index an array. >>> five_up = (a >= 5) >>> print(a[five_up]) [ 5 6 7 8 9 10 11 12] You can select elements that are divisible by 2: >>> divisible_by_2 = a[a%2==0] >>> print(divisible_by_2) [ 2 4 6 8 10 12] Or you can select elements that satisfy two conditions using the & and | operators: >>> c = a[(a > 2) & (a < 11)] >>> print(c) [ 3 4 5 6 7 8 9 10] You can also make use of the logical operators & and | in order to return boolean values that specify whether or not the values in an array fulfill a certain condition. This can be useful with arrays that contain names or other categorical values. >>> five_up = (a > 5) | (a == 5) >>> print(five_up) [[False False False False] [ True True True True] [ True True True True]] You can also use np.nonzero() to select elements or indices from an array. Starting with this array: >>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) You can use np.nonzero() to print the indices of elements that are, for example, less than 5: >>> b = np.nonzero(a < 5) >>> print(b) (array([0, 0, 0, 0]), array([0, 1, 2, 3])) In this example, a tuple of arrays was for each dimension. The first array represents the row indices where these values are found, and the second array represents the column indices where the values are found. If you want to generate a list of coordinates where the elements exist, you can zip the arrays, iterate over the list of coordinates, and print them. For example: >>> list_of_coordinates= list(zip(b[0], b[1])) >>> for coord in print(coord) (np.int64(0), np.int64(0)) (np.int64(0), np.int64(1)) (np.int64(0), np.int64(2)) (np.int64(0), np.int64(3)) You can also use np.nonzero() to print the elements in an array that are less than 5 with: >>> print(a[b]) [1 2 3 4] If the element you’re looking for doesn’t exist in the array, then the returned array of indices will be empty. For example: >>> not_there = np.nonzero(a == 42) >>> print(not_there) (array([], dtype=int64), array([], dtype=int64)) Learn more about indexing and slicing here and here. Read more about using the nonzero function How to create an array from existing data# This section covers slicing and indexing, np.vstack(), np.hstack(), np.hsplit(), .view(), copy() You can easily create a new array from a section of an existing array. Let’s say you have this array: >>> a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) You can create a new array from a section of your array any time by specifying where you want to slice your array. >>> arr1 = a[3:8] >>> arr1 array([4, 5, 6, 7, 8]) Here, you grabbed a section of your array from index position 3 through index position 8 but not including position 8 itself. indexes begin at 0. This means the first element of the array is at index 0, the second element is at index 1, and so on. You can also stack two existing arrays, both vertically and horizontally. Let’s say you have two arrays, a1 and a2: >>> a1 = np.array([[1, 1], ... [2, 2]]) >>> a2 = np.array([[3, 3], ... [4, 4]]) You can stack them vertically with vstack: >>> np.vstack((a1, a2)) array([[1, 1], [2, 2], [3, 3], [4, 4]]) Or stack them horizontally with hstack: >>> np.hstack((a1, a2)) array([[1, 1, 3, 3], [2, 2, 4, 4]]) You can split an array into several smaller arrays using hsplit. You can specify either the number of equally shaped arrays to return or the columns after which the division should occur. Let’s say you have this array: >>> x = np.arange(1, 25).reshape(2, 12) >>> x array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]]) If you wanted to split this array into three equally shaped arrays, you would run: >>> np.hsplit(x, 3) [array([[ 1, 2, 3, 4], [13, 14, 15, 16]]), array([[ 5, 6, 7, 8], [17, 18, 19, 20]]), array([[ 9, 10, 11, 12], [21, 22, 23, 24]])] If you wanted to split your array after the third and fourth column, you’d run: >>> np.hsplit(x, (3, 4)) [array([[ 1, 2, 3], [13, 14, 15]]), array([[ 4], [16]]), array([[ 5, 6, 7, 8, 9, 10, 11, 12], [17, 18, 19, 20, 21, 22, 23, 24]])] Learn more about stacking and splitting arrays here. You can use the view method to create a new array object that looks at the same data as the original array (a shallow copy). Views are an important NumPy concept! NumPy functions, as well as operations like indexing and slicing, will return views whenever possible. This saves memory and is faster (no copy of the data has to be made). However it’s important to be aware of this - modifying data in a view also modifies the original array! Let’s say you create this array: >>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) Now we create an array b1 by slicing a and modify the first element of b1. This will modify the corresponding element in a as well! >>> b1 = a[0, :] >>> b1 array([1, 2, 3, 4]) >>> b1[0] = 99 >>> b1 array([99, 2, 3, 4]) >>> a array([[99, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) Using the copy method will make a complete copy of the array and its data (a deep copy). To use this on your array, you could run: >>> b2 = a.copy() Learn more about copies and views here. Basic array operations# This section covers addition, subtraction, multiplication, division, and more Once you’ve created your arrays, you can start to work with them. Let’s say, for example, that you’ve created two arrays, one called “data” and one called “ones” You can add the arrays together with the plus sign. >>> data = np.array([1, 2]) >>> ones = np.ones(2, dtype=np.int_) >>> data + ones array([2, 3]) You can, of course, do more than just addition! >>> data - ones array([0, 1]) >>> data * data array([1, 4]) >>> data / data array([1., 1.]) Basic operations are simple with NumPy. If you want to find the sum of the elements in an array, you’d use sum(). This works for 1D arrays, 2D arrays, and arrays in higher dimensions. >>> a = np.array([1, 2, 3, 4]) >>> a.sum() 10 To add the rows or the columns in a 2D array, you would specify the axis. If you start with this array: >>> b = np.array([[1, 1], [2, 2]]) You can sum over the axis of rows with: >>> b.sum(axis=0) array([3, 3]) You can sum over the axis of columns with: >>> b.sum(axis=1) array([2, 4]) Learn more about basic operations here. Broadcasting# There are times when you might want to carry out an operation between an array and a single number (also called an operation between a vector and a scalar) or between arrays of two different sizes. For example, your array (we’ll call it “data”) might contain information about distance in miles but you want to convert the information to kilometers. You can perform this operation with: >>> data = np.array([1.0, 2.0]) >>> data * 1.6 array([1.6, 3.2]) NumPy understands that the multiplication should happen with each cell. That concept is called broadcasting. Broadcasting is a mechanism that allows NumPy to perform operations on arrays of different shapes. The dimensions of your array must be compatible, for example, when the dimensions of both arrays are equal or when one of them is 1. If the dimensions are not compatible, you will get a ValueError. Learn more about broadcasting here. More useful array operations# This section covers maximum, minimum, sum, mean, product, standard deviation, and more NumPy also performs aggregation functions. In addition to min, max, and sum, you can easily run mean to get the average, prod to get the result of multiplying the elements together, std to get the standard deviation, and more. >>> data = np.array([1, 2, 3]) >>> data.max() 3 >>> data.min() 1 >>> data.sum() 6 Let’s start with this array, called “a” >>> a = np.array([[0.45053314, 0.17296777, 0.34376245, 0.5510652], ... [0.54627315, 0.05093587, 0.40067661, 0.55645993], ... [0.12697628, 0.82485143, 0.26590556, 0.56917101]]) It’s very common to want to aggregate along a row or column. By default, every NumPy aggregation function will return the aggregate of the entire array. To find the sum or the minimum of the elements in your array, run: >>> a.sum() 4.8595784 Or: >>> a.min() 0.05093587 You can specify on which axis you want the aggregation function to be computed. For example, you can find the minimum value within each column by specifying axis=0. >>> a.min(axis=0) array([0.12697628, 0.05093587, 0.26590556, 0.5510652 ]) The four values listed above correspond to the number of columns in your array. With a four-column array, you will get four values as your result. Read more about array methods here. Creating matrices# You can pass Python lists of lists to create a 2-D array (or “matrix”) to represent them in NumPy. >>> data = np.array([[1, 2], [3, 4], [5, 6]]) >>> data array([[1, 2], [3, 4], [5, 6]]) Indexing and slicing operations are useful when you’re manipulating matrices: >>> data[0, 1] 2 >>> data[1:3] array([[3, 4], [5, 6]]) >>> data[0:2, 0] array([1, 3]) You can aggregate matrices the same way you aggregated vectors: >>> data.max() 6 >>> data.min() 1 >>> data.sum() 21 You can aggregate all the values in a matrix and you can aggregate them across columns or rows using the axis parameter. To illustrate this point, let’s look at a slightly modified dataset: >>> data = np.array([[1, 2], [5, 3], [4, 6]]) >>> data array([[1, 2], [5, 3], [4, 6]]) >>> data.max(axis=0) array([5, 6]) >>> data.max(axis=1) array([2, 5, 6]) Once you’ve created your matrices, you can add and multiply them using arithmetic operators if you have two matrices that are the same size. >>> data = np.array([[1, 2], [3, 4]]) >>> ones = np.array([[1, 1], [1, 1]]) >>> data + ones array([[2, 3], [4, 5]]) You can do these arithmetic operations on matrices of different sizes, but only if one matrix has only one column or one row. In this case, NumPy will use its broadcast rules for the operation. >>> data = np.array([[1, 2], [3, 4], [5, 6]]) >>> ones_row = np.array([[1, 1]]) >>> data + ones_row array([[2, 3], [4, 5], [6, 7]]) Be aware that when NumPy prints N-dimensional arrays, the last axis is looped over the fastest while the first axis is the slowest. For instance: >>> np.ones((4, 3, 2)) array([[[1., 1.], [1., 1.], [1., 1.]], [[1., 1.], [1., 1.], [1., 1.]], [[1., 1.], [1., 1.], [1., 1.]], [[1., 1.], [1., 1.], [1., 1.]]]) There are often instances where we want NumPy to initialize the values of an array. NumPy offers functions like ones() and zeros(), and the random.Generator class for random number generation for that. All you need to do is pass in the number of elements you want it to generate: >>> np.ones(3) array([1., 1., 1.]) >>> np.zeros(3) array([0., 0., 0.]) >>> rng = np.random.default_rng() # the simplest way to generate random numbers >>> rng.random(3) array([0.63696169, 0.26978671, 0.04097352]) You can also use ones(), zeros(), and random() to create a 2D array if you give them a tuple describing the dimensions of the matrix: >>> np.ones((3, 2)) array([[1., 1.], [1., 1.], [1., 1.]]) >>> np.zeros((3, 2)) array([[0., 0.], [0., 0.], [0., 0.]]) >>> rng.random((3, 2)) array([[0.01652764, 0.81327024], [0.91275558, 0.60663578], [0.72949656, 0.54362499]]) # may vary Read more about creating arrays, filled with 0’s, 1’s, other values or uninitialized, at array creation routines. Generating random numbers# The use of random number generation is an important part of the configuration and evaluation of many numerical and machine learning algorithms. Whether you need to randomly initialize weights in an artificial neural network, split data into random sets, or randomly shuffle your dataset, being able to generate random numbers (actually, repeatable pseudo-random numbers) is essential. With Generator.integers, you can generate random integers from low (remember that this is inclusive with NumPy) to high (exclusive). You can set endpoint=True to make the high number inclusive. You can generate a 2 x 4 array of random integers between 0 and 4 with: >>> rng.integers(5, size=(2, 4)) array([[2, 1, 1, 0], [0, 0, 0, 4]]) # may vary Read more about random number generation here. How to get unique items and counts# This section covers np.unique() You can find the unique elements in an array easily with np.unique. For example, if you start with this array: >>> a = np.array([11, 11, 12, 13, 14, 15, 16, 17, 12, 13, 11, 14, 18, 19, 20]) you can use np.unique to print the unique values in your array: >>> unique_values = np.unique(a) >>> print(unique_values) [11 12 13 14 15 16 17 18 19 20] To get the indices of unique values in a NumPy array (an array of first index positions of unique values in the array), just pass the return_index argument in np.unique() as well as your array. >>> unique_values, indices_list = np.unique(a, return_index=True) >>> print(indices_list) [ 0 2 3 4 5 6 7 12 13 14] You can pass the return_counts argument in np.unique() along with your array to get the frequency count of unique values in a NumPy array. >>> unique_values, occurrence_count = np.unique(a, return_counts=True) >>> print(occurrence_count) [3 2 2 2 1 1 1 1 1 1] This also works with 2D arrays! If you start with this array: >>> a_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) You can find unique values with: >>> unique_values = np.unique(a_2d) >>> print(unique_values) [ 1 2 3 4 5 6 7 8 9 10 11 12] If the axis argument isn’t passed, your 2D array will be flattened. If you want to get the unique rows or columns, make sure to pass the axis argument. To find the unique rows, specify axis=0 and for columns, specify axis=1. >>> unique_rows = np.unique(a_2d, axis=0) >>> print(unique_rows) [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] To get the unique rows, index position, and occurrence count, you can use: >>> unique_rows, indices, occurrence_count = np.unique( ... a_2d, axis=0, return_counts=True, return_index=True) >>> print(unique_rows) [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] >>> print(indices) [0 1 2] >>> print(occurrence_count) [2 1 1] To learn more about finding the unique elements in an array, see unique. Transposing and reshaping a matrix# This section covers arr.reshape(), arr.transpose(), arr.T It’s common to need to transpose your matrices. NumPy arrays have the property T that allows you to transpose a matrix. You may also need to switch the dimensions of a matrix. This can happen when, for example, you have a model that expects a certain input shape that is different from your dataset. This is where the reshape method can be useful. You simply need to pass in the new dimensions that you want for the matrix. >>> data.reshape(2, 3) array([[1, 2, 3], [4, 5, 6]]) >>> data.reshape(3, 2) array([[1, 2], [3, 4], [5, 6]]) You can also use .transpose() to reverse or change the axes of an array according to the values you specify. If you start with this array: >>> arr = np.arange(6).reshape((2, 3)) >>> arr array([[0, 1, 2], [3, 4, 5]]) You can transpose your array with arr.transpose(). >>> arr.transpose() array([[0, 3], [1, 4], [2, 5]]) You can also use arr.T: >>> arr.T array([[0, 3], [1, 4], [2, 5]]) To learn more about transposing and reshaping arrays, see transpose and reshape. How to reverse an array# This section covers np.flip() NumPy’s np.flip() function allows you to flip, or reverse, the contents of an array along an axis. When using np.flip(), specify the array you would like to reverse and the axis. If you don’t specify the axis, NumPy will reverse the contents along all of the axes of your input array. Reversing a 1D array If you begin with a 1D array like this one: >>> arr = np.array([1, 2, 3, 4, 5, 6, 7, 8]) You can reverse it with: >>> reversed_arr = np.flip(arr) If you want to print your reversed array, you can run: >>> print('Reversed Array: ', reversed_arr) Reversed Array: [8 7 6 5 4 3 2 1] Reversing a 2D array A 2D array works much the same way. If you start with this array: >>> arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) You can reverse the content in all of the rows and all of the columns with: >>> reversed_arr = np.flip(arr_2d) >>> print(reversed_arr) [[12 11 10 9] [ 8 7 6 5] [ 4 3 2 1]] You can easily reverse only the rows with: >>> reversed_arr_rows = np.flip(arr_2d, axis=0) >>> print(reversed_arr_rows) [[ 9 10 11 12] [ 5 6 7 8] [ 1 2 3 4]] Or reverse only the columns with: >>> reversed_arr_columns = np.flip(arr_2d, axis=1) >>> print(reversed_arr_columns) [[ 4 3 2 1] [ 8 7 6 5] [12 11 10 9]] You can also reverse the contents of only one column or row. For example, you can reverse the contents of the row at index position 1 (the second row): >>> arr_2d[1] = np.flip(arr_2d[1]) >>> print(arr_2d) [[ 1 2 3 4] [ 8 7 6 5] [ 9 10 11 12]] You can also reverse the column at index position 1 (the second column): >>> arr_2d[:,1] = np.flip(arr_2d[:,1]) >>> print(arr_2d) [[ 1 10 3 4] [ 8 7 6 5] [ 9 2 11 12]] Read more about reversing arrays at flip. Reshaping and flattening multidimensional arrays# This section covers .flatten(), ravel() There are two popular ways to flatten an () and .ravel(). The primary difference between the two is that the new array created using ravel() is actually a reference to the parent array (i.e., a “view”). This means that any changes to the new array will affect the parent array as well. Since ravel does not create a copy, it’s memory efficient. If you start with this array: >>> x = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) You can use flatten to flatten your array into a 1D array. >>> x.flatten() array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) When you use flatten, changes to your new array won’t change the parent array. For example: >>> a1 = x.flatten() >>> a1[0] = 99 >>> print(x) # Original array [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] >>> print(a1) # New array [99 2 3 4 5 6 7 8 9 10 11 12] But when you use ravel, the changes you make to the new array will affect the parent array. For example: >>> a2 = x.ravel() >>> a2[0] = 98 >>> print(x) # Original array [[98 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] >>> print(a2) # New array [98 2 3 4 5 6 7 8 9 10 11 12] Read more about flatten at ndarray.flatten and ravel at ravel. How to access the docstring for more information# This section covers help(), ?, ?? When it comes to the data science ecosystem, Python and NumPy are built with the user in mind. One of the best examples of this is the built-in access to documentation. Every object contains the reference to a string, which is known as the docstring. In most cases, this docstring contains a quick and concise summary of the object and how to use it. Python has a built-in help() function that can help you access this information. This means that nearly any time you need more information, you can use help() to quickly find the information that you need. For example: >>> help(max) Help on built-in function max in module (...) max(iterable, *[, default=obj, key=func]) -> value max(arg1, arg2, *args, *[, key=func]) -> value With a single iterable argument, return its biggest item. The default keyword-only argument specifies an object to return if the provided iterable is empty. With two or more ...arguments, return the largest argument. Because access to additional information is so useful, IPython uses the ? character as a shorthand for accessing this documentation along with other relevant information. IPython is a command shell for interactive computing in multiple languages. You can find more information about IPython here. For [0]: max? max(iterable, *[, default=obj, key=func]) -> value max(arg1, arg2, *args, *[, key=func]) -> value With a single iterable argument, return its biggest item. The default keyword-only argument specifies an object to return if the provided iterable is empty. With two or more arguments, return the largest argument. You can even use this notation for object methods and objects themselves. Let’s say you create this array: >>> a = np.array([1, 2, 3, 4, 5, 6]) Then you can obtain a lot of useful information (first details about a itself, followed by the docstring of ndarray of which a is an instance): In [1]: a? String form: [1 2 3 4 5 6] File: ~/anaconda3/lib/python3.9/site-packages/numpy/__init__.py Docstring: <no docstring> Class (shape, dtype=float, buffer=None, offset=0, strides=None, order=None) An array object represents a multidimensional, homogeneous array of fixed-size items. An associated data-type object describes the format of each element in the array (its byte-order, how many bytes it occupies in memory, whether it is an integer, a floating point number, or something else, etc.) Arrays should be constructed using `array`, `zeros` or `empty` (refer to the See Also section below). The parameters given here refer to a low-level method (`ndarray(...)`) for instantiating an array. For more information, refer to the `numpy` module and examine the methods and attributes of an array. Parameters ---------- (for the __new__ method; see Notes below) of ints Shape of created array. ... This also works for functions and other objects that you create. Just remember to include a docstring with your function using a string literal (\"\"\" \"\"\" or ''' ''' around your documentation). For example, if you create this function: >>> def double(a): ... '''Return a * 2''' ... return a * 2 You can obtain information about the [2]: double? (a) a * 2 File: ~/Desktop/<ipython-input-23-b5adf20be596> You can reach another level of information by reading the source code of the object you’re interested in. Using a double question mark (??) allows you to access the source code. For [3]: double?? (a) double(a): '''Return a * 2''' return a * 2 File: ~/Desktop/<ipython-input-23-b5adf20be596> If the object in question is compiled in a language other than Python, using ?? will return the same information as ?. You’ll find this with a lot of built-in objects and types, for [4]: len? (obj, /) the number of items in a container. [5]: len?? (obj, /) the number of items in a container. have the same output because they were compiled in a programming language other than Python. Working with mathematical formulas# The ease of implementing mathematical formulas that work on arrays is one of the things that make NumPy so widely used in the scientific Python community. For example, this is the mean square error formula (a central formula used in supervised machine learning models that deal with regression): Implementing this formula is simple and straightforward in makes this work so well is that predictions and labels can contain one or a thousand values. They only need to be the same size. You can visualize it this this example, both the predictions and labels vectors contain three values, meaning n has a value of three. After we carry out subtractions the values in the vector are squared. Then NumPy sums the values, and your result is the error value for that prediction and a score for the quality of the model. How to save and load NumPy objects# This section covers np.save, np.savez, np.savetxt, np.load, np.loadtxt You will, at some point, want to save your arrays to disk and load them back without having to re-run the code. Fortunately, there are several ways to save and load objects with NumPy. The ndarray objects can be saved to and loaded from the disk files with loadtxt and savetxt functions that handle normal text files, load and save functions that handle NumPy binary files with a .npy file extension, and a savez function that handles NumPy files with a .npz file extension. The .npy and .npz files store data, shape, dtype, and other information required to reconstruct the ndarray in a way that allows the array to be correctly retrieved, even when the file is on another machine with different architecture. If you want to store a single ndarray object, store it as a .npy file using np.save. If you want to store more than one ndarray object in a single file, save it as a .npz file using np.savez. You can also save several arrays into a single file in compressed npz format with savez_compressed. It’s easy to save and load an array with np.save(). Just make sure to specify the array you want to save and a file name. For example, if you create this array: >>> a = np.array([1, 2, 3, 4, 5, 6]) You can save it as “filename.npy” with: >>> np.save('filename', a) You can use np.load() to reconstruct your array. >>> b = np.load('filename.npy') If you want to check your array, you can run: >>> print(b) [1 2 3 4 5 6] You can save a NumPy array as a plain text file like a .csv or .txt file with np.savetxt. For example, if you create this array: >>> csv_arr = np.array([1, 2, 3, 4, 5, 6, 7, 8]) You can easily save it as a .csv file with the name “new_file.csv” like this: >>> np.savetxt('new_file.csv', csv_arr) You can quickly and easily load your saved text file using loadtxt(): >>> np.loadtxt('new_file.csv') array([1., 2., 3., 4., 5., 6., 7., 8.]) The savetxt() and loadtxt() functions accept additional optional parameters such as header, footer, and delimiter. While text files can be easier for sharing, .npy and .npz files are smaller and faster to read. If you need more sophisticated handling of your text file (for example, if you need to work with lines that contain missing values), you will want to use the genfromtxt function. With savetxt, you can specify headers, footers, comments, and more. Learn more about input and output routines here. Importing and exporting a CSV# It’s simple to read in a CSV that contains existing information. The best and easiest way to do this is to use Pandas. >>> import pandas as pd >>> # If all of your columns are the same type: >>> x = pd.read_csv('music.csv', header=0).values >>> print(x) [['Billie Holiday' 'Jazz' 1300000 27000000] ['Jimmie Hendrix' 'Rock' 2700000 70000000] ['Miles Davis' 'Jazz' 1500000 48000000] ['SIA' 'Pop' 2000000 74000000]] >>> # You can also simply select the columns you need: >>> x = pd.read_csv('music.csv', usecols=['Artist', 'Plays']).values >>> print(x) [['Billie Holiday' 27000000] ['Jimmie Hendrix' 70000000] ['Miles Davis' 48000000] ['SIA' 74000000]] It’s simple to use Pandas in order to export your array as well. If you are new to NumPy, you may want to create a Pandas dataframe from the values in your array and then write the data frame to a CSV file with Pandas. If you created this array “a” >>> a = np.array([[-2.58289208, 0.43014843, -1.24082018, 1.59572603], ... [ 0.99027828, 1.17150989, 0.94125714, -0.14692469], ... [ 0.76989341, 0.81299683, -0.95068423, 0.11769564], ... [ 0.20484034, 0.34784527, 1.96979195, 0.51992837]]) You could create a Pandas dataframe >>> df = pd.DataFrame(a) >>> print(df) 0 1 2 3 0 -2.582892 0.430148 -1.240820 1.595726 1 0.990278 1.171510 0.941257 -0.146925 2 0.769893 0.812997 -0.950684 0.117696 3 0.204840 0.347845 1.969792 0.519928 You can easily save your dataframe with: >>> df.to_csv('pd.csv') And read your CSV with: >>> data = pd.read_csv('pd.csv') You can also save your array with the NumPy savetxt method. >>> np.savetxt('np.csv', a, fmt='%.2f', delimiter=',', header='1, 2, 3, 4') If you’re using the command line, you can read your saved CSV any time with a command such as: $ cat np.csv # 1, 2, 3, 4 -2.58,0.43,-1.24,1.60 0.99,1.17,0.94,-0.15 0.77,0.81,-0.95,0.12 0.20,0.35,1.97,0.52 Or you can open the file any time with a text editor! If you’re interested in learning more about Pandas, take a look at the official Pandas documentation. Learn how to install Pandas with the official Pandas installation information. Plotting arrays with Matplotlib# If you need to generate a plot for your values, it’s very simple with Matplotlib. For example, you may have an array like this one: >>> a = np.array([2, 1, 5, 7, 4, 6, 8, 14, 10, 9, 18, 20, 22]) If you already have Matplotlib installed, you can import it with: >>> import matplotlib.pyplot as plt # If you're using Jupyter Notebook, you may also want to run the following # line of code to display your code in the notebook: %matplotlib inline All you need to do to plot your values is run: >>> plt.plot(a) # If you are running from a command line, you may need to do this: # >>> plt.show() For example, you can plot a 1D array like this: >>> x = np.linspace(0, 5, 20) >>> y = np.linspace(0, 10, 20) >>> plt.plot(x, y, 'purple') # line >>> plt.plot(x, y, 'o') # dots With Matplotlib, you have access to an enormous number of visualization options. >>> fig = plt.figure() >>> ax = fig.add_subplot(projection='3d') >>> X = np.arange(-5, 5, 0.15) >>> Y = np.arange(-5, 5, 0.15) >>> X, Y = np.meshgrid(X, Y) >>> R = np.sqrt(X**2 + Y**2) >>> Z = np.sin(R) >>> ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='viridis') To read more about Matplotlib and what it can do, take a look at the official documentation. For directions regarding installing Matplotlib, see the official installation section. Image Alammar https://jalammar.github.io/ previous NumPy quickstart next NumPy fundamentals On this page How to import NumPy Reading the example code Why use NumPy? What is an “array”? Array fundamentals Array attributes How to create a basic array Adding, removing, and sorting elements How do you know the shape and size of an array? Can you reshape an array? How to convert a 1D array into a 2D array (how to add a new axis to an array) Indexing and slicing How to create an array from existing data Basic array operations Broadcasting More useful array operations Creating matrices Generating random numbers How to get unique items and counts Transposing and reshaping a matrix How to reverse an array Reshaping and flattening multidimensional arrays How to access the docstring for more information Working with mathematical formulas How to save and load NumPy objects Importing and exporting a CSV Plotting arrays with Matplotlib\n\nExample:\n```text\nimport numpy as np\n```\n\nExample:\n```text\n>>> a = np.array([[1, 2, 3],\n...               [4, 5, 6]])\n>>> a.shape\n(2, 3)\n```\n\nExample:\n```text\n>>> a = np.array([1, 2, 3, 4, 5, 6])\n>>> a\narray([1, 2, 3, 4, 5, 6])\n```\n\nExample:\n```text\n>>> a[0]\n1\n```\n\nExample:\n```text\n>>> a[0] = 10\n>>> a\narray([10,  2,  3,  4,  5,  6])\n```\n\nExample:\n```text\n>>> a[:3]\narray([10, 2, 3])\n```\n\nExample:\n```text\n>>> b = a[3:]\n>>> b\narray([4, 5, 6])\n>>> b[0] = 40\n>>> a\narray([ 10,  2,  3, 40,  5,  6])\n```\n\nExample:\n```text\n>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])\n>>> a\narray([[ 1,  2,  3,  4],\n       [ 5,  6,  7,  8],\n       [ 9, 10, 11, 12]])\n```\n\nExample:\n```text\n>>> a[1, 3]\n8\n```\n\nExample:\n```text\n>>> a.ndim\n2\n```\n\nExample:\n```text\n>>> a.shape\n(3, 4)\n>>> len(a.shape) == a.ndim\nTrue\n```\n\nExample:\n```text\n>>> a.size\n12\n>>> import math\n>>> a.size == math.prod(a.shape)\nTrue\n```\n\nExample:\n```text\n>>> a.dtype\ndtype('int64')  # \"int\" for integer, \"64\" for 64-bit\n```\n\nExample:\n```text\n>>> np.zeros(2)\narray([0., 0.])\n```\n\nExample:\n```text\n>>> np.ones(2)\narray([1., 1.])\n```\n\nExample:\n```text\n>>> # Create an empty array with 2 elements\n>>> np.empty(2) \narray([3.14, 42.  ])  # may vary\n```\n\nExample:\n```text\n>>> np.arange(4)\narray([0, 1, 2, 3])\n```\n\nExample:\n```text\n>>> np.arange(2, 9, 2)\narray([2, 4, 6, 8])\n```\n\nExample:\n```text\n>>> np.linspace(0, 10, num=5)\narray([ 0. ,  2.5,  5. ,  7.5, 10. ])\n```\n\nExample:\n```text\n>>> x = np.ones(2, dtype=np.int64)\n>>> x\narray([1, 1])\n```\n\nExample:\n```text\n>>> arr = np.array([2, 1, 5, 3, 7, 4, 6, 8])\n```\n\nExample:\n```text\n>>> np.sort(arr)\narray([1, 2, 3, 4, 5, 6, 7, 8])\n```\n\nExample:\n```text\n>>> a = np.array([1, 2, 3, 4])\n>>> b = np.array([5, 6, 7, 8])\n```\n\nExample:\n```text\n>>> np.concatenate((a, b))\narray([1, 2, 3, 4, 5, 6, 7, 8])\n```\n\nExample:\n```text\n>>> x = np.array([[1, 2], [3, 4]])\n>>> y = np.array([[5, 6]])\n```\n\nExample:\n```text\n>>> np.concatenate((x, y), axis=0)\narray([[1, 2],\n       [3, 4],\n       [5, 6]])\n```\n\nExample:\n```text\n>>> array_example = np.array([[[0, 1, 2, 3],\n...                            [4, 5, 6, 7]],\n...\n...                           [[0, 1, 2, 3],\n...                            [4, 5, 6, 7]],\n...\n...                           [[0 ,1 ,2, 3],\n...                            [4, 5, 6, 7]]])\n```\n\nExample:\n```text\n>>> array_example.ndim\n3\n```\n\nExample:\n```text\n>>> array_example.size\n24\n```\n\nExample:\n```text\n>>> array_example.shape\n(3, 2, 4)\n```\n\nExample:\n```text\n>>> a = np.arange(6)\n>>> print(a)\n[0 1 2 3 4 5]\n```\n\nExample:\n```text\n>>> b = a.reshape(3, 2)\n>>> print(b)\n[[0 1]\n [2 3]\n [4 5]]\n```\n\nExample:\n```text\n>>> np.reshape(a, shape=(1, 6), order='C')\narray([[0, 1, 2, 3, 4, 5]])\n```\n\nExample:\n```text\n>>> a = np.array([1, 2, 3, 4, 5, 6])\n>>> a.shape\n(6,)\n```\n\nExample:\n```text\n>>> a2 = a[np.newaxis, :]\n>>> a2.shape\n(1, 6)\n```\n\nExample:\n```text\n>>> row_vector = a[np.newaxis, :]\n>>> row_vector.shape\n(1, 6)\n```\n\nExample:\n```text\n>>> col_vector = a[:, np.newaxis]\n>>> col_vector.shape\n(6, 1)\n```\n\nExample:\n```text\n>>> b = np.expand_dims(a, axis=1)\n>>> b.shape\n(6, 1)\n```\n\nExample:\n```text\n>>> c = np.expand_dims(a, axis=0)\n>>> c.shape\n(1, 6)\n```\n\nExample:\n```text\n>>> data = np.array([1, 2, 3])\n\n>>> data[1]\n2\n>>> data[0:2]\narray([1, 2])\n>>> data[1:]\narray([2, 3])\n>>> data[-2:]\narray([2, 3])\n```\n\nExample:\n```text\n>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])\n```\n\nExample:\n```text\n>>> print(a[a < 5])\n[1 2 3 4]\n```\n\nExample:\n```text\n>>> five_up = (a >= 5)\n>>> print(a[five_up])\n[ 5  6  7  8  9 10 11 12]\n```\n\nExample:\n```text\n>>> divisible_by_2 = a[a%2==0]\n>>> print(divisible_by_2)\n[ 2  4  6  8 10 12]\n```\n\nExample:\n```text\n>>> c = a[(a > 2) & (a < 11)]\n>>> print(c)\n[ 3  4  5  6  7  8  9 10]\n```\n\nExample:\n```text\n>>> five_up = (a > 5) | (a == 5)\n>>> print(five_up)\n[[False False False False]\n [ True  True  True  True]\n [ True  True  True True]]\n```\n\nExample:\n```text\n>>> b = np.nonzero(a < 5)\n>>> print(b)\n(array([0, 0, 0, 0]), array([0, 1, 2, 3]))\n```\n\nExample:\n```text\n>>> list_of_coordinates= list(zip(b[0], b[1]))\n\n>>> for coord in list_of_coordinates:\n...     print(coord)\n(np.int64(0), np.int64(0))\n(np.int64(0), np.int64(1))\n(np.int64(0), np.int64(2))\n(np.int64(0), np.int64(3))\n```\n\nExample:\n```text\n>>> print(a[b])\n[1 2 3 4]\n```\n\nExample:\n```text\n>>> not_there = np.nonzero(a == 42)\n>>> print(not_there)\n(array([], dtype=int64), array([], dtype=int64))\n```\n\nExample:\n```text\n>>> a = np.array([1,  2,  3,  4,  5,  6,  7,  8,  9, 10])\n```\n\nExample:\n```text\n>>> arr1 = a[3:8]\n>>> arr1\narray([4, 5, 6, 7, 8])\n```\n\nExample:\n```text\n>>> a1 = np.array([[1, 1],\n...                [2, 2]])\n\n>>> a2 = np.array([[3, 3],\n...                [4, 4]])\n```\n\nExample:\n```text\n>>> np.vstack((a1, a2))\narray([[1, 1],\n       [2, 2],\n       [3, 3],\n       [4, 4]])\n```\n\nExample:\n```text\n>>> np.hstack((a1, a2))\narray([[1, 1, 3, 3],\n       [2, 2, 4, 4]])\n```\n\nExample:\n```text\n>>> x = np.arange(1, 25).reshape(2, 12)\n>>> x\narray([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12],\n       [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]])\n```\n\nExample:\n```text\n>>> np.hsplit(x, 3)\n  [array([[ 1,  2,  3,  4],\n         [13, 14, 15, 16]]), array([[ 5,  6,  7,  8],\n         [17, 18, 19, 20]]), array([[ 9, 10, 11, 12],\n         [21, 22, 23, 24]])]\n```\n\nExample:\n```text\n>>> np.hsplit(x, (3, 4))\n  [array([[ 1,  2,  3],\n         [13, 14, 15]]), array([[ 4],\n         [16]]), array([[ 5,  6,  7,  8,  9, 10, 11, 12],\n         [17, 18, 19, 20, 21, 22, 23, 24]])]\n```\n\nExample:\n```text\n>>> b1 = a[0, :]\n>>> b1\narray([1, 2, 3, 4])\n>>> b1[0] = 99\n>>> b1\narray([99,  2,  3,  4])\n>>> a\narray([[99,  2,  3,  4],\n       [ 5,  6,  7,  8],\n       [ 9, 10, 11, 12]])\n```\n\nExample:\n```text\n>>> b2 = a.copy()\n```\n\nExample:\n```text\n>>> data = np.array([1, 2])\n>>> ones = np.ones(2, dtype=np.int_)\n>>> data + ones\narray([2, 3])\n```\n\nExample:\n```text\n>>> data - ones\narray([0, 1])\n>>> data * data\narray([1, 4])\n>>> data / data\narray([1., 1.])\n```\n\nExample:\n```text\n>>> a = np.array([1, 2, 3, 4])\n\n>>> a.sum()\n10\n```\n\nExample:\n```text\n>>> b = np.array([[1, 1], [2, 2]])\n```\n\nExample:\n```text\n>>> b.sum(axis=0)\narray([3, 3])\n```\n\nExample:\n```text\n>>> b.sum(axis=1)\narray([2, 4])\n```\n\nExample:\n```text\n>>> data = np.array([1.0, 2.0])\n>>> data * 1.6\narray([1.6, 3.2])\n```\n\nExample:\n```text\n>>> data = np.array([1, 2, 3])\n>>> data.max()\n3\n>>> data.min()\n1\n>>> data.sum()\n6\n```\n\nExample:\n```text\n>>> a = np.array([[0.45053314, 0.17296777, 0.34376245, 0.5510652],\n...               [0.54627315, 0.05093587, 0.40067661, 0.55645993],\n...               [0.12697628, 0.82485143, 0.26590556, 0.56917101]])\n```\n\nExample:\n```text\n>>> a.sum()\n4.8595784\n```\n\nExample:\n```text\n>>> a.min()\n0.05093587\n```\n\nExample:\n```text\n>>> a.min(axis=0)\narray([0.12697628, 0.05093587, 0.26590556, 0.5510652 ])\n```\n\nExample:\n```text\n>>> data = np.array([[1, 2], [3, 4], [5, 6]])\n>>> data\narray([[1, 2],\n       [3, 4],\n       [5, 6]])\n```\n\nExample:\n```text\n>>> data[0, 1]\n2\n>>> data[1:3]\narray([[3, 4],\n       [5, 6]])\n>>> data[0:2, 0]\narray([1, 3])\n```\n\nExample:\n```text\n>>> data.max()\n6\n>>> data.min()\n1\n>>> data.sum()\n21\n```\n\nExample:\n```text\n>>> data = np.array([[1, 2], [5, 3], [4, 6]])\n>>> data\narray([[1, 2],\n       [5, 3],\n       [4, 6]])\n>>> data.max(axis=0)\narray([5, 6])\n>>> data.max(axis=1)\narray([2, 5, 6])\n```\n\nExample:\n```text\n>>> data = np.array([[1, 2], [3, 4]])\n>>> ones = np.array([[1, 1], [1, 1]])\n>>> data + ones\narray([[2, 3],\n       [4, 5]])\n```\n\nExample:\n```text\n>>> data = np.array([[1, 2], [3, 4], [5, 6]])\n>>> ones_row = np.array([[1, 1]])\n>>> data + ones_row\narray([[2, 3],\n       [4, 5],\n       [6, 7]])\n```\n\nExample:\n```text\n>>> np.ones((4, 3, 2))\narray([[[1., 1.],\n        [1., 1.],\n        [1., 1.]],\n\n       [[1., 1.],\n        [1., 1.],\n        [1., 1.]],\n\n       [[1., 1.],\n        [1., 1.],\n        [1., 1.]],\n\n       [[1., 1.],\n        [1., 1.],\n        [1., 1.]]])\n```\n\nExample:\n```text\n>>> np.ones(3)\narray([1., 1., 1.])\n>>> np.zeros(3)\narray([0., 0., 0.])\n>>> rng = np.random.default_rng()  # the simplest way to generate random numbers\n>>> rng.random(3) \narray([0.63696169, 0.26978671, 0.04097352])\n```\n\nExample:\n```text\n>>> np.ones((3, 2))\narray([[1., 1.],\n       [1., 1.],\n       [1., 1.]])\n>>> np.zeros((3, 2))\narray([[0., 0.],\n       [0., 0.],\n       [0., 0.]])\n>>> rng.random((3, 2)) \narray([[0.01652764, 0.81327024],\n       [0.91275558, 0.60663578],\n       [0.72949656, 0.54362499]])  # may vary\n```\n\nExample:\n```text\n>>> rng.integers(5, size=(2, 4)) \narray([[2, 1, 1, 0],\n       [0, 0, 0, 4]])  # may vary\n```\n\nExample:\n```text\n>>> a = np.array([11, 11, 12, 13, 14, 15, 16, 17, 12, 13, 11, 14, 18, 19, 20])\n```\n\nExample:\n```text\n>>> unique_values = np.unique(a)\n>>> print(unique_values)\n[11 12 13 14 15 16 17 18 19 20]\n```\n\nExample:\n```text\n>>> unique_values, indices_list = np.unique(a, return_index=True)\n>>> print(indices_list)\n[ 0  2  3  4  5  6  7 12 13 14]\n```\n\nExample:\n```text\n>>> unique_values, occurrence_count = np.unique(a, return_counts=True)\n>>> print(occurrence_count)\n[3 2 2 2 1 1 1 1 1 1]\n```\n\nExample:\n```text\n>>> a_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]])\n```\n\nExample:\n```text\n>>> unique_values = np.unique(a_2d)\n>>> print(unique_values)\n[ 1  2  3  4  5  6  7  8  9 10 11 12]\n```\n\nExample:\n```text\n>>> unique_rows = np.unique(a_2d, axis=0)\n>>> print(unique_rows)\n[[ 1  2  3  4]\n [ 5  6  7  8]\n [ 9 10 11 12]]\n```\n\nExample:\n```text\n>>> unique_rows, indices, occurrence_count = np.unique(\n...      a_2d, axis=0, return_counts=True, return_index=True)\n>>> print(unique_rows)\n[[ 1  2  3  4]\n [ 5  6  7  8]\n [ 9 10 11 12]]\n>>> print(indices)\n[0 1 2]\n>>> print(occurrence_count)\n[2 1 1]\n```\n\nExample:\n```text\n>>> data.reshape(2, 3)\narray([[1, 2, 3],\n       [4, 5, 6]])\n>>> data.reshape(3, 2)\narray([[1, 2],\n       [3, 4],\n       [5, 6]])\n```\n\nExample:\n```text\n>>> arr = np.arange(6).reshape((2, 3))\n>>> arr\narray([[0, 1, 2],\n       [3, 4, 5]])\n```\n\nExample:\n```text\n>>> arr.transpose()\narray([[0, 3],\n       [1, 4],\n       [2, 5]])\n```\n\nExample:\n```text\n>>> arr.T\narray([[0, 3],\n       [1, 4],\n       [2, 5]])\n```\n\nExample:\n```text\n>>> arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n```\n\nExample:\n```text\n>>> reversed_arr = np.flip(arr)\n```\n\nExample:\n```text\n>>> print('Reversed Array: ', reversed_arr)\nReversed Array:  [8 7 6 5 4 3 2 1]\n```\n\nExample:\n```text\n>>> arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])\n```\n\nExample:\n```text\n>>> reversed_arr = np.flip(arr_2d)\n>>> print(reversed_arr)\n[[12 11 10  9]\n [ 8  7  6  5]\n [ 4  3  2  1]]\n```\n\nExample:\n```text\n>>> reversed_arr_rows = np.flip(arr_2d, axis=0)\n>>> print(reversed_arr_rows)\n[[ 9 10 11 12]\n [ 5  6  7  8]\n [ 1  2  3  4]]\n```\n\nExample:\n```text\n>>> reversed_arr_columns = np.flip(arr_2d, axis=1)\n>>> print(reversed_arr_columns)\n[[ 4  3  2  1]\n [ 8  7  6  5]\n [12 11 10  9]]\n```\n\nExample:\n```text\n>>> arr_2d[1] = np.flip(arr_2d[1])\n>>> print(arr_2d)\n[[ 1  2  3  4]\n [ 8  7  6  5]\n [ 9 10 11 12]]\n```\n\nExample:\n```text\n>>> arr_2d[:,1] = np.flip(arr_2d[:,1])\n>>> print(arr_2d)\n[[ 1 10  3  4]\n [ 8  7  6  5]\n [ 9  2 11 12]]\n```\n\nExample:\n```text\n>>> x = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])\n```\n\nExample:\n```text\n>>> x.flatten()\narray([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])\n```\n\nExample:\n```text\n>>> a1 = x.flatten()\n>>> a1[0] = 99\n>>> print(x)  # Original array\n[[ 1  2  3  4]\n [ 5  6  7  8]\n [ 9 10 11 12]]\n>>> print(a1)  # New array\n[99  2  3  4  5  6  7  8  9 10 11 12]\n```\n\nExample:\n```text\n>>> a2 = x.ravel()\n>>> a2[0] = 98\n>>> print(x)  # Original array\n[[98  2  3  4]\n [ 5  6  7  8]\n [ 9 10 11 12]]\n>>> print(a2)  # New array\n[98  2  3  4  5  6  7  8  9 10 11 12]\n```\n\nExample:\n```text\n>>> help(max)\nHelp on built-in function max in module builtins:\n\nmax(...)\n    max(iterable, *[, default=obj, key=func]) -> value\n    max(arg1, arg2, *args, *[, key=func]) -> value\n\n    With a single iterable argument, return its biggest item. The\n    default keyword-only argument specifies an object to return if\n    the provided iterable is empty.\n    With two or more ...arguments, return the largest argument.\n```\n\nExample:\n```text\nIn [0]: max?\nmax(iterable, *[, default=obj, key=func]) -> value\nmax(arg1, arg2, *args, *[, key=func]) -> value\n\nWith a single iterable argument, return its biggest item. The\ndefault keyword-only argument specifies an object to return if\nthe provided iterable is empty.\nWith two or more arguments, return the largest argument.\nType:      builtin_function_or_method\n```\n\nExample:\n```text\n>>> a = np.array([1, 2, 3, 4, 5, 6])\n```\n\nExample:\n```text\nIn [1]: a?\nType:            ndarray\nString form:     [1 2 3 4 5 6]\nLength:          6\nFile:            ~/anaconda3/lib/python3.9/site-packages/numpy/__init__.py\nDocstring:       <no docstring>\nClass docstring:\nndarray(shape, dtype=float, buffer=None, offset=0,\n        strides=None, order=None)\n\nAn array object represents a multidimensional, homogeneous array\nof fixed-size items.  An associated data-type object describes the\nformat of each element in the array (its byte-order, how many bytes it\noccupies in memory, whether it is an integer, a floating point number,\nor something else, etc.)\n\nArrays should be constructed using `array`, `zeros` or `empty` (refer\nto the See Also section below).  The parameters given here refer to\na low-level method (`ndarray(...)`) for instantiating an array.\n\nFor more information, refer to the `numpy` module and examine the\nmethods and attributes of an array.\n\nParameters\n----------\n(for the __new__ method; see Notes below)\n\nshape : tuple of ints\n        Shape of created array.\n...\n```\n\nExample:\n```text\n>>> def double(a):\n...   '''Return a * 2'''\n...   return a * 2\n```\n\nExample:\n```text\nIn [2]: double?\nSignature: double(a)\nDocstring: Return a * 2\nFile:      ~/Desktop/<ipython-input-23-b5adf20be596>\nType:      function\n```\n\nExample:\n```text\nIn [3]: double??\nSignature: double(a)\nSource:\ndef double(a):\n    '''Return a * 2'''\n    return a * 2\nFile:      ~/Desktop/<ipython-input-23-b5adf20be596>\nType:      function\n```\n\nExample:\n```text\nIn [4]: len?\nSignature: len(obj, /)\nDocstring: Return the number of items in a container.\nType:      builtin_function_or_method\n```\n\nExample:\n```text\nIn [5]: len??\nSignature: len(obj, /)\nDocstring: Return the number of items in a container.\nType:      builtin_function_or_method\n```\n\nExample:\n```text\n>>> np.save('filename', a)\n```\n\nExample:\n```text\n>>> b = np.load('filename.npy')\n```\n\nExample:\n```text\n>>> print(b)\n[1 2 3 4 5 6]\n```\n\nExample:\n```text\n>>> csv_arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n```\n\nExample:\n```text\n>>> np.savetxt('new_file.csv', csv_arr)\n```\n\nExample:\n```text\n>>> np.loadtxt('new_file.csv')\narray([1., 2., 3., 4., 5., 6., 7., 8.])\n```\n\nExample:\n```text\n>>> import pandas as pd\n\n>>> # If all of your columns are the same type:\n>>> x = pd.read_csv('music.csv', header=0).values\n>>> print(x)\n[['Billie Holiday' 'Jazz' 1300000 27000000]\n ['Jimmie Hendrix' 'Rock' 2700000 70000000]\n ['Miles Davis' 'Jazz' 1500000 48000000]\n ['SIA' 'Pop' 2000000 74000000]]\n\n>>> # You can also simply select the columns you need:\n>>> x = pd.read_csv('music.csv', usecols=['Artist', 'Plays']).values\n>>> print(x)\n[['Billie Holiday' 27000000]\n ['Jimmie Hendrix' 70000000]\n ['Miles Davis' 48000000]\n ['SIA' 74000000]]\n```\n\nExample:\n```text\n>>> a = np.array([[-2.58289208,  0.43014843, -1.24082018, 1.59572603],\n...               [ 0.99027828, 1.17150989,  0.94125714, -0.14692469],\n...               [ 0.76989341,  0.81299683, -0.95068423, 0.11769564],\n...               [ 0.20484034,  0.34784527,  1.96979195, 0.51992837]])\n```\n\nExample:\n```text\n>>> df = pd.DataFrame(a)\n>>> print(df)\n          0         1         2         3\n0 -2.582892  0.430148 -1.240820  1.595726\n1  0.990278  1.171510  0.941257 -0.146925\n2  0.769893  0.812997 -0.950684  0.117696\n3  0.204840  0.347845  1.969792  0.519928\n```\n\nExample:\n```text\n>>> df.to_csv('pd.csv')\n```\n\nExample:\n```text\n>>> data = pd.read_csv('pd.csv')\n```\n\nExample:\n```text\n>>> np.savetxt('np.csv', a, fmt='%.2f', delimiter=',', header='1,  2,  3,  4')\n```\n\nExample:\n```text\n$ cat np.csv\n#  1,  2,  3,  4\n-2.58,0.43,-1.24,1.60\n0.99,1.17,0.94,-0.15\n0.77,0.81,-0.95,0.12\n0.20,0.35,1.97,0.52\n```\n\nExample:\n```text\n>>> a = np.array([2, 1, 5, 7, 4, 6, 8, 14, 10, 9, 18, 20, 22])\n```\n\nExample:\n```text\n>>> import matplotlib.pyplot as plt\n\n# If you're using Jupyter Notebook, you may also want to run the following\n# line of code to display your code in the notebook:\n\n%matplotlib inline\n```\n\nExample:\n```text\n>>> plt.plot(a)\n\n# If you are running from a command line, you may need to do this:\n# >>> plt.show()\n```\n\nExample:\n```text\n>>> x = np.linspace(0, 5, 20)\n>>> y = np.linspace(0, 10, 20)\n>>> plt.plot(x, y, 'purple') # line\n>>> plt.plot(x, y, 'o')      # dots\n```\n\nExample:\n```text\n>>> fig = plt.figure()\n>>> ax = fig.add_subplot(projection='3d')\n>>> X = np.arange(-5, 5, 0.15)\n>>> Y = np.arange(-5, 5, 0.15)\n>>> X, Y = np.meshgrid(X, Y)\n>>> R = np.sqrt(X**2 + Y**2)\n>>> Z = np.sin(R)\n\n>>> ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='viridis')\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:56.061Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":134,"totalLines":1091,"estimatedTokens":15681}}19{"id":"doc-structured_arrays_numpy_v2_5_manual-c029cfa6","source":"documentation","title":"Structured arrays — NumPy v2.5 Manual","url":"https://numpy.org/doc/stable/user/basics.rec.html","text":"User Guide API reference Building from source Development Release notes Learn NEPs Choose version GitHub Collapse Sidebar Expand Sidebar Section Navigation Getting started What is NumPy? Installation NumPy quickstart absolute basics for beginners Fundamentals and usage NumPy fundamentals Array creation Indexing on ndarrays I/O with NumPy Data types Broadcasting Copies and views Working with Arrays of Strings And Bytes Structured arrays Universal functions (ufunc) basics NumPy for MATLAB users NumPy tutorials NumPy how-tos Advanced usage and interoperability Using NumPy C-API F2PY user guide and reference manual Under-the-hood documentation for developers Interoperability with NumPy Writing Performant NumPy Code with Multi-Core CPUs Extras Glossary Release notes NumPy 2.0 migration guide NumPy license NumPy user guide NumPy fundamentals Structured arrays Structured arrays# Introduction# Structured arrays are ndarrays whose datatype is a composition of simpler datatypes organized as a sequence of named fields. For example, >>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)], ... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')]) >>> x array([('Rex', 9, 81.), ('Fido', 3, 27.)], dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')]) Here x is a one-dimensional array of length two whose datatype is a structure with three A string of length 10 or less named ‘name’, 2. a 32-bit integer named ‘age’, and 3. a 32-bit float named ‘weight’. If you index x at position 1 you get a structure: >>> x[1] np.void(('Fido', 3, 27.0), dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')]) You can access and modify individual fields of a structured array by indexing with the field name: >>> x['age'] array([9, 3], dtype=int32) >>> x['age'] = 5 >>> x array([('Rex', 5, 81.), ('Fido', 5, 27.)], dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')]) Structured datatypes are designed to be able to mimic ‘structs’ in the C language, and share a similar memory layout. They are meant for interfacing with C code and for low-level manipulation of structured buffers, for example for interpreting binary blobs. For these purposes they support specialized features such as subarrays, nested datatypes, and unions, and allow control over the memory layout of the structure. Users looking to manipulate tabular data, such as stored in csv files, may find other pydata projects more suitable, such as xarray, pandas, or DataArray. These provide a high-level interface for tabular data analysis and are better optimized for that use. For instance, the C-struct-like memory layout of structured arrays in numpy can lead to poor cache behavior in comparison. Structured datatypes# A structured datatype can be thought of as a sequence of bytes of a certain length (the structure’s itemsize) which is interpreted as a collection of fields. Each field has a name, a datatype, and a byte offset within the structure. The datatype of a field may be any numpy datatype including other structured datatypes, and it may also be a subarray data type which behaves like an ndarray of a specified shape. The offsets of the fields are arbitrary, and fields may even overlap. These offsets are usually determined automatically by numpy, but can also be specified. Structured datatype creation# Structured datatypes may be created using the function numpy.dtype. There are 4 alternative forms of specification which vary in flexibility and conciseness. These are further documented in the Data Type Objects reference page, and in summary they list of tuples, one tuple per field Each tuple has the form (fieldname, datatype, shape) where shape is optional. fieldname is a string (or tuple if titles are used, see Field Titles below), datatype may be any object convertible to a datatype, and shape is a tuple of integers specifying subarray shape. >>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))]) dtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))]) If fieldname is the empty string '', the field will be given a default name of the form f#, where # is the integer index of the field, counting from 0 from the left: >>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')]) dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')]) The byte offsets of the fields within the structure and the total structure itemsize are determined automatically. A string of comma-separated dtype specifications In this shorthand notation any of the string dtype specifications may be used in a string and separated by commas. The itemsize and byte offsets of the fields are determined automatically, and the field names are given the default names f0, f1, etc. >>> np.dtype('i8, f4, S3') dtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')]) >>> np.dtype('3int8, float32, (2, 3)float64') dtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))]) A dictionary of field parameter arrays This is the most flexible form of specification since it allows control over the byte-offsets of the fields and the itemsize of the structure. The dictionary has two required keys, ‘names’ and ‘formats’, and four optional keys, ‘offsets’, ‘itemsize’, ‘aligned’ and ‘titles’. The values for ‘names’ and ‘formats’ should respectively be a list of field names and a list of dtype specifications, of the same length. The optional ‘offsets’ value should be a list of integer byte-offsets, one for each field within the structure. If ‘offsets’ is not given the offsets are determined automatically. The optional ‘itemsize’ value should be an integer describing the total size in bytes of the dtype, which must be large enough to contain all the fields. >>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']}) dtype([('col1', '<i4'), ('col2', '<f4')]) >>> np.dtype({'names': ['col1', 'col2'], ... 'formats': ['i4', 'f4'], ... 'offsets': [0, 4], ... 'itemsize': 12}) dtype({'names': ['col1', 'col2'], 'formats': ['<i4', '<f4'], 'offsets': [0, 4], 'itemsize': 12}) Offsets may be chosen such that the fields overlap, though this will mean that assigning to one field may clobber any overlapping field’s data. As an exception, fields of numpy.object_ type cannot overlap with other fields, because of the risk of clobbering the internal object pointer and then dereferencing it. The optional ‘aligned’ value can be set to True to make the automatic offset computation use aligned offsets (see Automatic byte offsets and alignment), as if the ‘align’ keyword argument of numpy.dtype had been set to True. The optional ‘titles’ value should be a list of titles of the same length as ‘names’, see Field Titles below. A dictionary of field names The keys of the dictionary are the field names and the values are tuples specifying type and offset: >>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)}) dtype([('col1', 'i1'), ('col2', '<f4')]) This form was discouraged because Python dictionaries did not preserve order in Python versions before Python 3.6. Field Titles may be specified by using a 3-tuple, see below. Manipulating and displaying structured datatypes# The list of field names of a structured datatype can be found in the names attribute of the dtype object: >>> d = np.dtype([('x', 'i8'), ('y', 'f4')]) >>> d.names ('x', 'y') The dtype of each individual field can be looked up by name: >>> d['x'] dtype('int64') The field names may be modified by assigning to the names attribute using a sequence of strings of the same length. The dtype object also has a dictionary-like attribute, fields, whose keys are the field names (and Field Titles, see below) and whose values are tuples containing the dtype and byte offset of each field. >>> d.fields mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)}) Both the names and fields attributes will equal None for unstructured arrays. The recommended way to test if a dtype is structured is with if dt.names is not None rather than if dt.names, to account for dtypes with 0 fields. The string representation of a structured datatype is shown in the “list of tuples” form if possible, otherwise numpy falls back to using the more general dictionary form. Automatic byte offsets and alignment# Numpy uses one of two methods to automatically determine the field byte offsets and the overall itemsize of a structured datatype, depending on whether align=True was specified as a keyword argument to numpy.dtype. By default (align=False), numpy will pack the fields together such that each field starts at the byte offset the previous field ended, and the fields are contiguous in memory. >>> def print_offsets(d): ... print(\"offsets:\", [d.fields[name][1] for name in d.names]) ... print(\"itemsize:\", d.itemsize) >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2')) offsets: [0, 1, 2, 6, 7, 15] If align=True is set, numpy will pad the structure in the same way many C compilers would pad a C-struct. Aligned structures can give a performance improvement in some cases, at the cost of increased datatype size. Padding bytes are inserted between fields such that each field’s byte offset will be a multiple of that field’s alignment, which is usually equal to the field’s size in bytes for simple datatypes, see PyArray_Descr.alignment. The structure will also have trailing padding added so that its itemsize is a multiple of the largest field’s alignment. >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True)) offsets: [0, 1, 4, 8, 16, 24] Note that although almost all modern C compilers pad in this way by default, padding in C structs is C-implementation-dependent so this memory layout is not guaranteed to exactly match that of a corresponding struct in a C program. Some work may be needed, either on the numpy side or the C side, to obtain exact correspondence. If offsets were specified using the optional offsets key in the dictionary-based dtype specification, setting align=True will check that each field’s offset is a multiple of its size and that the itemsize is a multiple of the largest field size, and raise an exception if not. If the offsets of the fields and itemsize of a structured array satisfy the alignment conditions, the array will have the ALIGNED flag set. A convenience function numpy.lib.recfunctions.repack_fields converts an aligned dtype or array to a packed one and vice versa. It takes either a dtype or structured ndarray as an argument, and returns a copy with fields re-packed, with or without padding bytes. Field titles# In addition to field names, fields may also have an associated title, an alternate name, which is sometimes used as an additional description or alias for the field. The title may be used to index an array, just like a field name. To add titles when using the list-of-tuples form of dtype specification, the field name may be specified as a tuple of two strings instead of a single string, which will be the field’s title and field name respectively. For example: >>> np.dtype([(('my title', 'name'), 'f4')]) dtype([(('my title', 'name'), '<f4')]) When using the first form of dictionary-based specification, the titles may be supplied as an extra 'titles' key as described above. When using the second (discouraged) dictionary-based specification, the title can be supplied by providing a 3-element tuple (datatype, offset, title) instead of the usual 2-element tuple: >>> np.dtype({'name': ('i4', 0, 'my title')}) dtype([(('my title', 'name'), '<i4')]) The dtype.fields dictionary will contain titles as keys, if any titles are used. This means effectively that a field with a title will be represented twice in the fields dictionary. The tuple values for these fields will also have a third element, the field title. Because of this, and because the names attribute preserves the field order while the fields attribute may not, it is recommended to iterate through the fields of a dtype using the names attribute of the dtype, which will not list titles, as in: >>> for name in d.names: ... print(d.fields[name][:2]) (dtype('int64'), 0) (dtype('float32'), 8) Union types# Structured datatypes are implemented in numpy to have base type numpy.void by default, but it is possible to interpret other numpy types as structured types using the (base_dtype, dtype) form of dtype specification described in Data Type Objects. Here, base_dtype is the desired underlying dtype, and fields and flags will be copied from dtype. This dtype is similar to a ‘union’ in C. Indexing and assignment to structured arrays# Assigning data to a structured array# There are a number of ways to assign values to a structured python tuples, using scalar values, or using other structured arrays. Assignment from Python Native Types (Tuples)# The simplest way to assign values to a structured array is using python tuples. Each assigned value should be a tuple of length equal to the number of fields in the array, and not a list or array as these will trigger numpy’s broadcasting rules. The tuple’s elements are assigned to the successive fields of the array, from left to right: >>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8') >>> x[1] = (7, 8, 9) >>> x array([(1, 2., 3.), (7, 8., 9.)], dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')]) Assignment from Scalars# A scalar assigned to a structured element will be assigned to all fields. This happens when a scalar is assigned to a structured array, or when an unstructured array is assigned to a structured array: >>> x = np.zeros(2, dtype='i8, f4, ?, S1') >>> x[:] = 3 >>> x array([(3, 3., True, b'3'), (3, 3., True, b'3')], dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')]) >>> x[:] = np.arange(2) >>> x array([(0, 0., False, b'0'), (1, 1., True, b'1')], dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')]) Structured arrays can also be assigned to unstructured arrays, but only if the structured datatype has just a single field: >>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')]) >>> onefield = np.zeros(2, dtype=[('A', 'i4')]) >>> nostruct = np.zeros(2, dtype='i4') >>> nostruct[:] = twofield Traceback (most recent call last): ... cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe' Assignment from other Structured Arrays# Assignment between two structured arrays occurs as if the source elements had been converted to tuples and then assigned to the destination elements. That is, the first field of the source array is assigned to the first field of the destination array, and the second field likewise, and so on, regardless of field names. Structured arrays with a different number of fields cannot be assigned to each other. Bytes of the destination structure which are not included in any of the fields are unaffected. >>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')]) >>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')]) >>> b[:] = a >>> b array([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')], dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')]) Assignment involving subarrays# When assigning to fields which are subarrays, the assigned value will first be broadcast to the shape of the subarray. Indexing structured arrays# Accessing Individual Fields# Individual fields of a structured array may be accessed and modified by indexing the array with the field name. >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')]) >>> x['foo'] array([1, 3]) >>> x['foo'] = 10 >>> x array([(10, 2.), (10, 4.)], dtype=[('foo', '<i8'), ('bar', '<f4')]) The resulting array is a view into the original array. It shares the same memory locations and writing to the view will modify the original array. >>> y = x['bar'] >>> y[:] = 11 >>> x array([(10, 11.), (10, 11.)], dtype=[('foo', '<i8'), ('bar', '<f4')]) This view has the same dtype and itemsize as the indexed field, so it is typically a non-structured array, except in the case of nested structures. >>> y.dtype, y.shape, y.strides (dtype('float32'), (2,), (12,)) If the accessed field is a subarray, the dimensions of the subarray are appended to the shape of the result: >>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))]) >>> x['a'].shape (2, 2) >>> x['b'].shape (2, 2, 3, 3) Accessing Multiple Fields# One can index and assign to a structured array with a multi-field index, where the index is a list of field names. Warning The behavior of multi-field indexes changed from Numpy 1.15 to Numpy 1.16. The result of indexing with a multi-field index is a view into the original array, as follows: >>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')]) >>> a[['a', 'c']] array([(0, 0.), (0, 0.), (0, 0.)], dtype={'names': ['a', 'c'], 'formats': ['<i4', '<f4'], 'offsets': [0, 8], 'itemsize': 12}) Assignment to the view modifies the original array. The view’s fields will be in the order they were indexed. Note that unlike for single-field indexing, the dtype of the view has the same itemsize as the original array, and has fields at the same offsets as in the original array, and unindexed fields are merely missing. Warning In Numpy 1.15, indexing an array with a multi-field index returned a copy of the result above, but with fields packed together in memory as if passed through numpy.lib.recfunctions.repack_fields. The new behavior as of Numpy 1.16 leads to extra “padding” bytes at the location of unindexed fields compared to 1.15. You will need to update any code which depends on the data having a “packed” layout. For instance code such as: >>> a[['a', 'c']].view('i8') # Fails in Numpy 1.16 Traceback (most recent call last): File \"<stdin>\", line 1, in <module> changing to a smaller dtype, its size must be a divisor of the size of original dtype will need to be changed. This code has raised a FutureWarning since Numpy 1.12, and similar code has raised FutureWarning since 1.7. In 1.16 a number of functions have been introduced in the numpy.lib.recfunctions module to help users account for this change. These are numpy.lib.recfunctions.repack_fields. numpy.lib.recfunctions.structured_to_unstructured, numpy.lib.recfunctions.unstructured_to_structured, numpy.lib.recfunctions.apply_along_fields, numpy.lib.recfunctions.assign_fields_by_name, and numpy.lib.recfunctions.require_fields. The function numpy.lib.recfunctions.repack_fields can always be used to reproduce the old behavior, as it will return a packed copy of the structured array. The code above, for example, can be replaced with: >>> from numpy.lib.recfunctions import repack_fields >>> repack_fields(a[['a', 'c']]).view('i8') # supported in 1.16 array([0, 0, 0]) Furthermore, numpy now provides a new function numpy.lib.recfunctions.structured_to_unstructured which is a safer and more efficient alternative for users who wish to convert structured arrays to unstructured arrays, as the view above is often intended to do. This function allows safe conversion to an unstructured type taking into account padding, often avoids a copy, and also casts the datatypes as needed, unlike the view. Code such as: >>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')]) >>> b[['x', 'z']].view('f4') array([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32) can be made safer by replacing with: >>> from numpy.lib.recfunctions import structured_to_unstructured >>> structured_to_unstructured(b[['x', 'z']]) array([[0., 0.], [0., 0.], [0., 0.]], dtype=float32) Assignment to an array with a multi-field index modifies the original array: >>> a[['a', 'c']] = (2, 3) >>> a array([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)], dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')]) This obeys the structured array assignment rules described above. For example, this means that one can swap the values of two fields using appropriate multi-field indexes: >>> a[['a', 'c']] = a[['c', 'a']] Indexing with an Integer to get a Structured Scalar# Indexing a single element of a structured array (with an integer index) returns a structured scalar: >>> x = np.array([(1, 2., 3.)], dtype='i, f, f') >>> scalar = x[0] >>> scalar np.void((1, 2.0, 3.0), dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<f4')]) >>> type(scalar) <class 'numpy.void'> Unlike other numpy scalars, structured scalars are mutable and act like views into the original array, such that modifying the scalar will modify the original array. Structured scalars also support access and assignment by field name: >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')]) >>> s = x[0] >>> s['bar'] = 100 >>> x array([(1, 100.), (3, 4.)], dtype=[('foo', '<i8'), ('bar', '<f4')]) Similarly to tuples, structured scalars can also be indexed with an integer: >>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0] >>> scalar[0] np.int32(1) >>> scalar[1] = 4 Thus, tuples might be thought of as the native Python equivalent to numpy’s structured types, much like native python integers are the equivalent to numpy’s integer types. Structured scalars may be converted to a tuple by calling numpy.ndarray.item: >>> scalar.item(), type(scalar.item()) ((1, 4.0, 3.0), <class 'tuple'>) Viewing structured arrays containing objects# In order to prevent clobbering object pointers in fields of object type, numpy currently does not allow views of structured arrays containing objects. Structure comparison and promotion# If the dtypes of two void structured arrays are equal, testing the equality of the arrays will result in a boolean array with the dimensions of the original arrays, with elements set to True where all fields of the corresponding structures are equal: >>> a = np.array([(1, 1), (2, 2)], dtype=[('a', 'i4'), ('b', 'i4')]) >>> b = np.array([(1, 1), (2, 3)], dtype=[('a', 'i4'), ('b', 'i4')]) >>> a == b array([True, False]) NumPy will promote individual field datatypes to perform the comparison. So the following is also valid (note the 'f4' dtype for the 'a' field): >>> b = np.array([(1.0, 1), (2.5, 2)], dtype=[(\"a\", \"f4\"), (\"b\", \"i4\")]) >>> a == b array([True, False]) To compare two structured arrays, it must be possible to promote them to a common dtype as returned by numpy.result_type and numpy.promote_types. This enforces that the number of fields, the field names, and the field titles must match precisely. When promotion is not possible, for example due to mismatching field names, NumPy will raise an error. Promotion between two structured dtypes results in a canonical dtype that ensures native byte-order for all fields: >>> np.result_type(np.dtype(\"i,>i\")) dtype([('f0', '<i4'), ('f1', '<i4')]) >>> np.result_type(np.dtype(\"i,>i\"), np.dtype(\"i,i\")) dtype([('f0', '<i4'), ('f1', '<i4')]) The resulting dtype from promotion is also guaranteed to be packed, meaning that all fields are ordered contiguously and any unnecessary padding is removed: >>> dt = np.dtype(\"i1,V3,i4,V1\")[[\"f0\", \"f2\"]] >>> dt dtype({'names': ['f0', 'f2'], 'formats': ['i1', '<i4'], 'offsets': [0, 4], 'itemsize': 9}) >>> np.result_type(dt) dtype([('f0', 'i1'), ('f2', '<i4')]) Note that the result prints without offsets or itemsize indicating no additional padding. If a structured dtype is created with align=True ensuring that dtype.isalignedstruct is true, this property is preserved: >>> dt = np.dtype(\"i1,V3,i4,V1\", align=True)[[\"f0\", \"f2\"]] >>> dt dtype({'names': ['f0', 'f2'], 'formats': ['i1', '<i4'], 'offsets': [0, 4], 'itemsize': 12}, align=True) >>> np.result_type(dt) dtype([('f0', 'i1'), ('f2', '<i4')], align=True) >>> np.result_type(dt).isalignedstruct True When promoting multiple dtypes, the result is aligned if any of the inputs is: >>> np.result_type(np.dtype(\"i,i\"), np.dtype(\"i,i\", align=True)) dtype([('f0', '<i4'), ('f1', '<i4')], align=True) The < and > operators always return False when comparing void structured arrays, and arithmetic and bitwise operations are not supported. Changed in version 1.23: Before NumPy 1.23, a warning was given and False returned when promotion to a common dtype failed. Further, promotion was much more would reject the mixed float/integer comparison example above. Record arrays# As an optional convenience numpy provides an ndarray subclass, numpy.recarray that allows access to fields of structured arrays by attribute instead of only by index. Record arrays use a special datatype, numpy.record, that allows field access by attribute on the structured scalars obtained from the array. The numpy.rec module provides functions for creating recarrays from various objects. Additional helper functions for creating and manipulating structured arrays can be found in numpy.lib.recfunctions. The simplest way to create a record array is with numpy.rec.array: >>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., \"World\")], ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')]) >>> recordarr.bar array([2., 3.], dtype=float32) >>> recordarr[1:2] rec.array([(2, 3., b'World')], dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]) >>> recordarr[1:2].foo array([2], dtype=int32) >>> recordarr.foo[1:2] array([2], dtype=int32) >>> recordarr[1].baz b'World' numpy.rec.array can convert a wide variety of arguments into record arrays, including structured arrays: >>> arr = np.array([(1, 2., 'Hello'), (2, 3., \"World\")], ... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')]) >>> recordarr = np.rec.array(arr) The numpy.rec module provides a number of other convenience functions for creating record arrays, see record array creation routines. A record array representation of a structured array can be obtained using the appropriate view: >>> arr = np.array([(1, 2., 'Hello'), (2, 3., \"World\")], ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')]) >>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)), ... type=np.recarray) For convenience, viewing an ndarray as type numpy.recarray will automatically convert to numpy.record datatype, so the dtype can be left out of the view: >>> recordarr = arr.view(np.recarray) >>> recordarr.dtype dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])) To get back to a plain ndarray both the dtype and type must be reset. The following view does so, taking into account the unusual case that the recordarr was not a structured type: >>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray) Record array fields accessed by index or by attribute are returned as a record array if the field has a structured type but as a plain ndarray otherwise. >>> recordarr = np.rec.array([('Hello', (1, 2)), (\"World\", (3, 4))], ... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])]) >>> type(recordarr.foo) <class 'numpy.ndarray'> >>> type(recordarr.bar) <class 'numpy.rec.recarray'> Note that if a field has the same name as an ndarray attribute, the ndarray attribute takes precedence. Such fields will be inaccessible by attribute but will still be accessible by index. Recarray helper functions# Collection of utilities to manipulate structured arrays. Most of these functions were initially implemented by John Hunter for matplotlib. They have been rewritten and extended for convenience. numpy.lib.recfunctions.append_fields(base, names, data, dtypes=None, fill_value=-1, usemask=True, asrecarray=False)[source]# Add new fields to an existing array. The names of the fields are given with the names arguments, the corresponding values with the data arguments. If a single field is appended, names, data and dtypes do not have to be lists but just values. array to extend. namesstring, sequenceString or sequence of strings corresponding to the names of the new fields. dataarray or sequence of arraysArray or sequence of arrays storing the fields to add to the base. dtypessequence of datatypes, optionalDatatype or sequence of datatypes. If None, the datatypes are estimated from the data. fill_value{float}, optionalFilling value used to pad missing data on the shorter arrays. usemask{False, True}, optionalWhether to return a masked array or not. asrecarray{False, True}, optionalWhether to return a recarray (MaskedRecords) or not. numpy.lib.recfunctions.apply_along_fields(func, arr)[source]# Apply function ‘func’ as a reduction across fields of a structured array. This is similar to numpy.apply_along_axis, but treats the fields of a structured array as an extra axis. The fields are all first cast to a common type following the type-promotion rules from numpy.result_type applied to the field’s dtypes. to apply on the “field” dimension. This function must support an axis argument, like numpy.mean, numpy.sum, etc. arrndarrayStructured array for which to apply func. of the reduction operation Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)], ... dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')]) >>> rfn.apply_along_fields(np.mean, b) array([ 2.66666667, 5.33333333, 8.66666667, 11. ]) >>> rfn.apply_along_fields(np.mean, b[['x', 'z']]) array([ 3. , 5.5, 9. , 11. ]) Go BackOpen In Tab numpy.lib.recfunctions.assign_fields_by_name(dst, src, zero_unassigned=True)[source]# Assigns values from one structured array to another by field name. Normally in numpy >= 1.14, assignment of one structured array to another copies fields “by position”, meaning that the first field from the src is copied to the first field of the dst, and so on, regardless of field name. This function instead copies “by field name”, such that fields in the dst are assigned from the identically named field in the src. This applies recursively for nested structures. This is how structure assignment worked in numpy >= 1.6 to <= 1.13. srcndarrayThe source and destination arrays during assignment. zero_unassignedbool, optionalIf True, fields in the dst for which there was no matching field in the src are filled with the value 0 (zero). This was the behavior of numpy <= 1.13. If False, those fields are not modified. numpy.lib.recfunctions.drop_fields(base, drop_names, usemask=True, asrecarray=False)[source]# Return a new array with fields in drop_names dropped. Nested fields are supported. array drop_namesstring or sequenceString or sequence of strings corresponding to the names of the fields to drop. usemask{False, True}, optionalWhether to return a masked array or not. asrecarraystring or sequence, optionalWhether to return a recarray or a mrecarray (asrecarray=True) or a plain ndarray or masked array with flexible dtype. The default is False. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.array([(1, (2, 3.0)), (4, (5, 6.0))], ... dtype=[('a', np.int64), ('b', [('ba', np.double), ('bb', np.int64)])]) >>> rfn.drop_fields(a, 'a') array([((2., 3),), ((5., 6),)], dtype=[('b', [('ba', '<f8'), ('bb', '<i8')])]) >>> rfn.drop_fields(a, 'ba') array([(1, (3,)), (4, (6,))], dtype=[('a', '<i8'), ('b', [('bb', '<i8')])]) >>> rfn.drop_fields(a, ['ba', 'bb']) array([(1,), (4,)], dtype=[('a', '<i8')]) Go BackOpen In Tab numpy.lib.recfunctions.find_duplicates(a, key=None, ignoremask=True, return_index=False)[source]# Find the duplicates in a structured array along a given key array key{string, None}, optionalName of the fields along which to check the duplicates. If None, the search is performed by records ignoremask{True, False}, optionalWhether masked data should be discarded or considered as duplicates. return_index{False, True}, optionalWhether to return the indices of the duplicated values. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> ndtype = [('a', int)] >>> a = np.ma.array([1, 1, 1, 2, 2, 3, 3], ... mask=[0, 0, 1, 0, 0, 0, 1]).view(ndtype) >>> rfn.find_duplicates(a, ignoremask=True, return_index=True) (masked_array(data=[(1,), (1,), (2,), (2,)], mask=[(False,), (False,), (False,), (False,)], fill_value=(999999,), dtype=[('a', '<i8')]), array([0, 1, 3, 4])) Go BackOpen In Tab numpy.lib.recfunctions.flatten_descr(ndtype)[source]# Flatten a structured data-type description. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> ndtype = np.dtype([('a', '<i4'), ('b', [('ba', '<f8'), ('bb', '<i4')])]) >>> rfn.flatten_descr(ndtype) (('a', dtype('int32')), ('ba', dtype('float64')), ('bb', dtype('int32'))) Go BackOpen In Tab numpy.lib.recfunctions.get_fieldstructure(adtype, lastname=None, parents=None)[source]# Returns a dictionary with fields indexing lists of their parent fields. This function is used to simplify access to fields nested in other fields. datatype lastnameoptionalLast processed field name (used internally during recursion). parentsdictionaryDictionary of parent fields (used internally during recursion). Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> ndtype = np.dtype([('A', int), ... ('B', [('BA', int), ... ('BB', [('BBA', int), ('BBB', int)])])]) >>> rfn.get_fieldstructure(ndtype) ... # regression, order of BBA and BBB is swapped {'A': [], 'B': [], 'BA': ['B'], 'BB': ['B'], 'BBA': ['B', 'BB'], 'BBB': ['B', 'BB']} Go BackOpen In Tab numpy.lib.recfunctions.get_names(adtype)[source]# Returns the field names of the input datatype as a tuple. Input datatype must have fields otherwise error is raised. datatype Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> rfn.get_names(np.empty((1,), dtype=[('A', int)]).dtype) ('A',) >>> rfn.get_names(np.empty((1,), dtype=[('A',int), ('B', float)]).dtype) ('A', 'B') >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) >>> rfn.get_names(adtype) ('a', ('b', ('ba', 'bb'))) Go BackOpen In Tab numpy.lib.recfunctions.get_names_flat(adtype)[source]# Returns the field names of the input datatype as a tuple. Input datatype must have fields otherwise error is raised. Nested structure are flattened beforehand. datatype Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> rfn.get_names_flat(np.empty((1,), dtype=[('A', int)]).dtype) is None False >>> rfn.get_names_flat(np.empty((1,), dtype=[('A',int), ('B', str)]).dtype) ('A', 'B') >>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])]) >>> rfn.get_names_flat(adtype) ('a', 'b', 'ba', 'bb') Go BackOpen In Tab numpy.lib.recfunctions.join_by(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2', defaults=None, usemask=True, asrecarray=False)[source]# Join arrays r1 and r2 on key key. The key should be either a string or a sequence of string corresponding to the fields used to join the array. An exception is raised if the key field cannot be found in the two input arrays. Neither r1 nor r2 should have any duplicates along presence of duplicates will make the output quite unreliable. Note that duplicates are not looked for by the algorithm. {string, sequence}A string or a sequence of strings corresponding to the fields used for comparison. r1, r2arraysStructured arrays. jointype{‘inner’, ‘outer’, ‘leftouter’}, optionalIf ‘inner’, returns the elements common to both r1 and r2. If ‘outer’, returns the common elements as well as the elements of r1 not in r2 and the elements of not in r2. If ‘leftouter’, returns the common elements and the elements of r1 not in r2. r1postfixstring, optionalString appended to the names of the fields of r1 that are present in r2 but absent of the key. r2postfixstring, optionalString appended to the names of the fields of r2 that are present in r1 but absent of the key. defaults{dictionary}, optionalDictionary mapping field names to the corresponding default values. usemask{True, False}, optionalWhether to return a MaskedArray (or MaskedRecords is asrecarray==True) or an ndarray. asrecarray{False, True}, optionalWhether to return a recarray (or MaskedRecords if usemask==True) or just a flexible-type ndarray. Notes The output is sorted along the key. A temporary array is formed by dropping the fields not in the key for the two arrays and concatenating the result. This array is then sorted, and the common entries selected. The output is constructed by filling the fields with the selected entries. Matching is not preserved if there are some duplicates… numpy.lib.recfunctions.merge_arrays(seqarrays, fill_value=-1, flatten=False, usemask=False, asrecarray=False)[source]# Merge arrays field by field. of ndarraysSequence of arrays fill_value{float}, optionalFilling value used to pad missing data on the shorter arrays. flatten{False, True}, optionalWhether to collapse nested fields. usemask{False, True}, optionalWhether to return a masked array or not. asrecarray{False, True}, optionalWhether to return a recarray (MaskedRecords) or not. Notes Without a mask, the missing value will be filled with something, depending on what its corresponding for integers -1.0 for floating point numbers '-' for characters '-1' for strings True for boolean values just obtained these values empirically Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> rfn.merge_arrays((np.array([1, 2]), np.array([10., 20., 30.]))) array([( 1, 10.), ( 2, 20.), (-1, 30.)], dtype=[('f0', '<i8'), ('f1', '<f8')]) >>> rfn.merge_arrays((np.array([1, 2], dtype=np.int64), ... np.array([10., 20., 30.])), usemask=False) array([(1, 10.0), (2, 20.0), (-1, 30.0)], dtype=[('f0', '<i8'), ('f1', '<f8')]) >>> rfn.merge_arrays((np.array([1, 2]).view([('a', np.int64)]), ... np.array([10., 20., 30.])), ... usemask=False, asrecarray=True) rec.array([( 1, 10.), ( 2, 20.), (-1, 30.)], dtype=[('a', '<i8'), ('f1', '<f8')]) Go BackOpen In Tab numpy.lib.recfunctions.rec_append_fields(base, names, data, dtypes=None)[source]# Add new fields to an existing array. The names of the fields are given with the names arguments, the corresponding values with the data arguments. If a single field is appended, names, data and dtypes do not have to be lists but just values. array to extend. namesstring, sequenceString or sequence of strings corresponding to the names of the new fields. dataarray or sequence of arraysArray or sequence of arrays storing the fields to add to the base. dtypessequence of datatypes, optionalDatatype or sequence of datatypes. If None, the datatypes are estimated from the data. See also append_fields numpy.lib.recfunctions.rec_drop_fields(base, drop_names)[source]# Returns a new numpy.recarray with fields in drop_names dropped. numpy.lib.recfunctions.rec_join(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2', defaults=None)[source]# Join arrays r1 and r2 on keys. Alternative to join_by, that always returns a np.recarray. See also join_byequivalent function numpy.lib.recfunctions.recursive_fill_fields(input, output)[source]# Fills fields from output with fields from input, with support for nested structures. array. outputndarrayOutput array. Notes output should be at least the same size as input Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.array([(1, 10.), (2, 20.)], dtype=[('A', np.int64), ('B', np.float64)]) >>> b = np.zeros((3,), dtype=a.dtype) >>> rfn.recursive_fill_fields(a, b) array([(1, 10.), (2, 20.), (0, 0.)], dtype=[('A', '<i8'), ('B', '<f8')]) Go BackOpen In Tab numpy.lib.recfunctions.rename_fields(base, namemapper)[source]# Rename the fields from a flexible-datatype ndarray or recarray. Nested fields are supported. array whose fields must be modified. namemapperdictionaryDictionary mapping old field names to their new version. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.array([(1, (2, [3.0, 30.])), (4, (5, [6.0, 60.]))], ... dtype=[('a', int),('b', [('ba', float), ('bb', (float, 2))])]) >>> rfn.rename_fields(a, {'a':'A', 'bb':'BB'}) array([(1, (2., [ 3., 30.])), (4, (5., [ 6., 60.]))], dtype=[('A', '<i8'), ('b', [('ba', '<f8'), ('BB', '<f8', (2,))])]) Go BackOpen In Tab numpy.lib.recfunctions.repack_fields(a, align=False, recurse=False)[source]# Re-pack the fields of a structured array or dtype in memory. The memory layout of structured datatypes allows fields at arbitrary byte offsets. This means the fields can be separated by padding bytes, their offsets can be non-monotonically increasing, and they can overlap. This method removes any overlaps and reorders the fields in memory so they have increasing byte offsets, and adds or removes padding bytes depending on the align option, which behaves like the align option to numpy.dtype. If align=False, this method produces a “packed” memory layout in which each field starts at the byte the previous field ended, and any padding bytes are removed. If align=True, this methods produces an “aligned” memory layout in which each field’s offset is a multiple of its alignment, and the total itemsize is a multiple of the largest alignment, by adding padding bytes as needed. or dtypearray or dtype for which to repack the fields. alignbooleanIf true, use an “aligned” memory layout, otherwise use a “packed” layout. recursebooleanIf True, also repack nested structures. or dtypeCopy of a with fields repacked, or a itself if no repacking was needed. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> def print_offsets(d): ... print(\"offsets:\", [d.fields[name][1] for name in d.names]) ... print(\"itemsize:\", d.itemsize) ... >>> dt = np.dtype('u1, <i8, <f8', align=True) >>> dt dtype({'names': ['f0', 'f1', 'f2'], 'formats': ['u1', '<i8', '<f8'], 'offsets': [0, 8, 16], 'itemsize': 24}, align=True) >>> print_offsets(dt) offsets: [0, 8, 16] >>> packed_dt = rfn.repack_fields(dt) >>> packed_dt dtype([('f0', 'u1'), ('f1', '<i8'), ('f2', '<f8')]) >>> print_offsets(packed_dt) offsets: [0, 1, 9] Go BackOpen In Tab numpy.lib.recfunctions.require_fields(array, required_dtype)[source]# Casts a structured array to a new dtype using assignment by field-name. This function assigns from the old to the new array by name, so the value of a field in the output array is the value of the field with the same name in the source array. This has the effect of creating a new ndarray containing only the fields “required” by the required_dtype. If a field name in the required_dtype does not exist in the input array, that field is created and set to 0 in the output array. to cast required_dtypedtypedatatype for output array with the new dtype, with field values copied from the fields in the input array with the same name Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.ones(4, dtype=[('a', 'i4'), ('b', 'f8'), ('c', 'u1')]) >>> rfn.require_fields(a, [('b', 'f4'), ('c', 'u1')]) array([(1., 1), (1., 1), (1., 1), (1., 1)], dtype=[('b', '<f4'), ('c', 'u1')]) >>> rfn.require_fields(a, [('b', 'f4'), ('newf', 'u1')]) array([(1., 0), (1., 0), (1., 0), (1., 0)], dtype=[('b', '<f4'), ('newf', 'u1')]) Go BackOpen In Tab numpy.lib.recfunctions.stack_arrays(arrays, defaults=None, usemask=True, asrecarray=False, autoconvert=False)[source]# Superposes arrays fields by fields or sequenceSequence of input arrays. defaultsdictionary, optionalDictionary mapping field names to the corresponding default values. usemask{True, False}, optionalWhether to return a MaskedArray (or MaskedRecords is asrecarray==True) or an ndarray. asrecarray{False, True}, optionalWhether to return a recarray (or MaskedRecords if usemask==True) or just a flexible-type ndarray. autoconvert{False, True}, optionalWhether automatically cast the type of the field to the maximum. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> x = np.array([1, 2,]) >>> rfn.stack_arrays(x) is x True >>> z = np.array([('A', 1), ('B', 2)], dtype=[('A', '|S3'), ('B', float)]) >>> zz = np.array([('a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)], ... dtype=[('A', '|S3'), ('B', np.double), ('C', np.double)]) >>> test = rfn.stack_arrays((z,zz)) >>> test masked_array(data=[(b'A', 1.0, --), (b'B', 2.0, --), (b'a', 10.0, 100.0), (b'b', 20.0, 200.0), (b'c', 30.0, 300.0)], mask=[(False, False, True), (False, False, True), (False, False, False), (False, False, False), (False, False, False)], fill_value=(b'N/A', 1e+20, 1e+20), dtype=[('A', 'S3'), ('B', '<f8'), ('C', '<f8')]) Go BackOpen In Tab numpy.lib.recfunctions.structured_to_unstructured(arr, dtype=None, copy=False, casting='unsafe')[source]# Converts an n-D structured array into an (n+1)-D unstructured array. The new array will have a new last dimension equal in size to the number of field-elements of the input array. If not supplied, the output datatype is determined from the numpy type promotion rules applied to all the field datatypes. Nested fields, as well as each element of any subarray fields, all count as a single field-elements. array or dtype to convert. Cannot contain object datatype. dtypedtype, optionalThe dtype of the output unstructured array. copybool, optionalIf true, always return a copy. If false, a view is returned if possible, such as when the dtype and strides of the fields are suitable and the array subtype is one of numpy.ndarray, numpy.recarray or numpy.memmap. Changed in version 1.25.0: A view can now be returned if the fields are separated by a uniform stride. casting{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optionalSee casting argument of numpy.ndarray.astype. Controls what kind of data casting may occur. array with one more dimension. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> a = np.zeros(4, dtype=[('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)]) >>> a array([(0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.])], dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))]) >>> rfn.structured_to_unstructured(a) array([[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]]) >>> b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)], ... dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')]) >>> np.mean(rfn.structured_to_unstructured(b[['x', 'z']]), axis=-1) array([ 3. , 5.5, 9. , 11. ]) Go BackOpen In Tab numpy.lib.recfunctions.unstructured_to_structured(arr, dtype=None, names=None, align=False, copy=False, casting='unsafe')[source]# Converts an n-D unstructured array into an (n-1)-D structured array. The last dimension of the input array is converted into a structure, with number of field-elements equal to the size of the last dimension of the input array. By default all output fields have the input array’s dtype, but an output structured dtype with an equal number of fields-elements can be supplied instead. Nested fields, as well as each element of any subarray fields, all count towards the number of field-elements. array or dtype to convert. dtypedtype, optionalThe structured dtype of the output array nameslist of strings, optionalIf dtype is not supplied, this specifies the field names for the output dtype, in order. The field dtypes will be the same as the input array. alignboolean, optionalWhether to create an aligned memory layout. copybool, optionalSee copy argument to numpy.ndarray.astype. If true, always return a copy. If false, and dtype requirements are satisfied, a view is returned. casting{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optionalSee casting argument of numpy.ndarray.astype. Controls what kind of data casting may occur. array with fewer dimensions. Examples Try it in your browser! >>> import numpy as np >>> from numpy.lib import recfunctions as rfn >>> dt = np.dtype([('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)]) >>> a = np.arange(20).reshape((4,5)) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) >>> rfn.unstructured_to_structured(a, dt) array([( 0, ( 1., 2), [ 3., 4.]), ( 5, ( 6., 7), [ 8., 9.]), (10, (11., 12), [13., 14.]), (15, (16., 17), [18., 19.])], dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))]) Go BackOpen In Tab previous Working with Arrays of Strings And Bytes next Universal functions (ufunc) basics On this page Introduction Structured datatypes Structured datatype creation Manipulating and displaying structured datatypes Automatic byte offsets and alignment Field titles Union types Indexing and assignment to structured arrays Assigning data to a structured array Assignment from Python Native Types (Tuples) Assignment from Scalars Assignment from other Structured Arrays Assignment involving subarrays Indexing structured arrays Accessing Individual Fields Accessing Multiple Fields Indexing with an Integer to get a Structured Scalar Viewing structured arrays containing objects Structure comparison and promotion Record arrays Recarray helper functions append_fields apply_along_fields assign_fields_by_name drop_fields find_duplicates flatten_descr get_fieldstructure get_names get_names_flat join_by merge_arrays rec_append_fields rec_drop_fields rec_join recursive_fill_fields rename_fields repack_fields require_fields stack_arrays structured_to_unstructured unstructured_to_structured\n\nExample:\n```text\n>>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)],\n...              dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])\n>>> x\narray([('Rex', 9, 81.), ('Fido', 3, 27.)],\n      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])\n```\n\nExample:\n```text\n>>> x[1]\nnp.void(('Fido', 3, 27.0), dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])\n```\n\nExample:\n```text\n>>> x['age']\narray([9, 3], dtype=int32)\n>>> x['age'] = 5\n>>> x\narray([('Rex', 5, 81.), ('Fido', 5, 27.)],\n      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])\n```\n\nExample:\n```text\n>>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))])\ndtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))])\n```\n\nExample:\n```text\n>>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')])\ndtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])\n```\n\nExample:\n```text\n>>> np.dtype('i8, f4, S3')\ndtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')])\n>>> np.dtype('3int8, float32, (2, 3)float64')\ndtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])\n```\n\nExample:\n```text\n>>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})\ndtype([('col1', '<i4'), ('col2', '<f4')])\n>>> np.dtype({'names': ['col1', 'col2'],\n...           'formats': ['i4', 'f4'],\n...           'offsets': [0, 4],\n...           'itemsize': 12})\ndtype({'names': ['col1', 'col2'], 'formats': ['<i4', '<f4'], 'offsets': [0, 4], 'itemsize': 12})\n```\n\nExample:\n```text\n>>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)})\ndtype([('col1', 'i1'), ('col2', '<f4')])\n```\n\nExample:\n```text\n>>> d = np.dtype([('x', 'i8'), ('y', 'f4')])\n>>> d.names\n('x', 'y')\n```\n\nExample:\n```text\n>>> d['x']\ndtype('int64')\n```\n\nExample:\n```text\n>>> d.fields\nmappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})\n```\n\nExample:\n```text\n>>> def print_offsets(d):\n...     print(\"offsets:\", [d.fields[name][1] for name in d.names])\n...     print(\"itemsize:\", d.itemsize)\n>>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2'))\noffsets: [0, 1, 2, 6, 7, 15]\nitemsize: 17\n```\n\nExample:\n```text\n>>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True))\noffsets: [0, 1, 4, 8, 16, 24]\nitemsize: 32\n```\n\nExample:\n```text\n>>> np.dtype([(('my title', 'name'), 'f4')])\ndtype([(('my title', 'name'), '<f4')])\n```\n\nExample:\n```text\n>>> np.dtype({'name': ('i4', 0, 'my title')})\ndtype([(('my title', 'name'), '<i4')])\n```\n\nExample:\n```text\n>>> for name in d.names:\n...     print(d.fields[name][:2])\n(dtype('int64'), 0)\n(dtype('float32'), 8)\n```\n\nExample:\n```text\n>>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8')\n>>> x[1] = (7, 8, 9)\n>>> x\narray([(1, 2., 3.), (7, 8., 9.)],\n     dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')])\n```\n\nExample:\n```text\n>>> x = np.zeros(2, dtype='i8, f4, ?, S1')\n>>> x[:] = 3\n>>> x\narray([(3, 3., True, b'3'), (3, 3., True, b'3')],\n      dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])\n>>> x[:] = np.arange(2)\n>>> x\narray([(0, 0., False, b'0'), (1, 1., True, b'1')],\n      dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])\n```\n\nExample:\n```text\n>>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')])\n>>> onefield = np.zeros(2, dtype=[('A', 'i4')])\n>>> nostruct = np.zeros(2, dtype='i4')\n>>> nostruct[:] = twofield\nTraceback (most recent call last):\n...\nTypeError: Cannot cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'\n```\n\nExample:\n```text\n>>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])\n>>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])\n>>> b[:] = a\n>>> b\narray([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')],\n      dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')])\n```\n\nExample:\n```text\n>>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])\n>>> x['foo']\narray([1, 3])\n>>> x['foo'] = 10\n>>> x\narray([(10, 2.), (10, 4.)],\n      dtype=[('foo', '<i8'), ('bar', '<f4')])\n```\n\nExample:\n```text\n>>> y = x['bar']\n>>> y[:] = 11\n>>> x\narray([(10, 11.), (10, 11.)],\n      dtype=[('foo', '<i8'), ('bar', '<f4')])\n```\n\nExample:\n```text\n>>> y.dtype, y.shape, y.strides\n(dtype('float32'), (2,), (12,))\n```\n\nExample:\n```text\n>>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])\n>>> x['a'].shape\n(2, 2)\n>>> x['b'].shape\n(2, 2, 3, 3)\n```\n\nExample:\n```text\n>>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])\n>>> a[['a', 'c']]\narray([(0, 0.), (0, 0.), (0, 0.)],\n     dtype={'names': ['a', 'c'], 'formats': ['<i4', '<f4'], 'offsets': [0, 8], 'itemsize': 12})\n```\n\nExample:\n```text\n>>> a[['a', 'c']].view('i8')  # Fails in Numpy 1.16\nTraceback (most recent call last):\n   File \"<stdin>\", line 1, in <module>\nValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype\n```\n\nExample:\n```text\n>>> from numpy.lib.recfunctions import repack_fields\n>>> repack_fields(a[['a', 'c']]).view('i8')  # supported in 1.16\narray([0, 0, 0])\n```\n\nExample:\n```text\n>>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])\n>>> b[['x', 'z']].view('f4')\narray([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)\n```\n\nExample:\n```text\n>>> from numpy.lib.recfunctions import structured_to_unstructured\n>>> structured_to_unstructured(b[['x', 'z']])\narray([[0., 0.],\n       [0., 0.],\n       [0., 0.]], dtype=float32)\n```\n\nExample:\n```text\n>>> a[['a', 'c']] = (2, 3)\n>>> a\narray([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)],\n      dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])\n```\n\nExample:\n```text\n>>> a[['a', 'c']] = a[['c', 'a']]\n```\n\nExample:\n```text\n>>> x = np.array([(1, 2., 3.)], dtype='i, f, f')\n>>> scalar = x[0]\n>>> scalar\nnp.void((1, 2.0, 3.0), dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<f4')])\n>>> type(scalar)\n<class 'numpy.void'>\n```\n\nExample:\n```text\n>>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])\n>>> s = x[0]\n>>> s['bar'] = 100\n>>> x\narray([(1, 100.), (3, 4.)],\n      dtype=[('foo', '<i8'), ('bar', '<f4')])\n```\n\nExample:\n```text\n>>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0]\n>>> scalar[0]\nnp.int32(1)\n>>> scalar[1] = 4\n```\n\nExample:\n```text\n>>> scalar.item(), type(scalar.item())\n((1, 4.0, 3.0), <class 'tuple'>)\n```\n\nExample:\n```text\n>>> a = np.array([(1, 1), (2, 2)], dtype=[('a', 'i4'), ('b', 'i4')])\n>>> b = np.array([(1, 1), (2, 3)], dtype=[('a', 'i4'), ('b', 'i4')])\n>>> a == b\narray([True, False])\n```\n\nExample:\n```text\n>>> b = np.array([(1.0, 1), (2.5, 2)], dtype=[(\"a\", \"f4\"), (\"b\", \"i4\")])\n>>> a == b\narray([True, False])\n```\n\nExample:\n```text\n>>> np.result_type(np.dtype(\"i,>i\"))\ndtype([('f0', '<i4'), ('f1', '<i4')])\n>>> np.result_type(np.dtype(\"i,>i\"), np.dtype(\"i,i\"))\ndtype([('f0', '<i4'), ('f1', '<i4')])\n```\n\nExample:\n```text\n>>> dt = np.dtype(\"i1,V3,i4,V1\")[[\"f0\", \"f2\"]]\n>>> dt\ndtype({'names': ['f0', 'f2'], 'formats': ['i1', '<i4'], 'offsets': [0, 4], 'itemsize': 9})\n>>> np.result_type(dt)\ndtype([('f0', 'i1'), ('f2', '<i4')])\n```\n\nExample:\n```text\n>>> dt = np.dtype(\"i1,V3,i4,V1\", align=True)[[\"f0\", \"f2\"]]\n>>> dt\ndtype({'names': ['f0', 'f2'], 'formats': ['i1', '<i4'], 'offsets': [0, 4], 'itemsize': 12}, align=True)\n\n>>> np.result_type(dt)\ndtype([('f0', 'i1'), ('f2', '<i4')], align=True)\n>>> np.result_type(dt).isalignedstruct\nTrue\n```\n\nExample:\n```text\n>>> np.result_type(np.dtype(\"i,i\"), np.dtype(\"i,i\", align=True))\ndtype([('f0', '<i4'), ('f1', '<i4')], align=True)\n```\n\nExample:\n```text\n>>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., \"World\")],\n...                    dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])\n>>> recordarr.bar\narray([2., 3.], dtype=float32)\n>>> recordarr[1:2]\nrec.array([(2, 3., b'World')],\n      dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])\n>>> recordarr[1:2].foo\narray([2], dtype=int32)\n>>> recordarr.foo[1:2]\narray([2], dtype=int32)\n>>> recordarr[1].baz\nb'World'\n```\n\nExample:\n```text\n>>> arr = np.array([(1, 2., 'Hello'), (2, 3., \"World\")],\n...             dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])\n>>> recordarr = np.rec.array(arr)\n```\n\nExample:\n```text\n>>> arr = np.array([(1, 2., 'Hello'), (2, 3., \"World\")],\n...                dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])\n>>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)),\n...                      type=np.recarray)\n```\n\nExample:\n```text\n>>> recordarr = arr.view(np.recarray)\n>>> recordarr.dtype\ndtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))\n```\n\nExample:\n```text\n>>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)\n```\n\nExample:\n```text\n>>> recordarr = np.rec.array([('Hello', (1, 2)), (\"World\", (3, 4))],\n...                 dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])])\n>>> type(recordarr.foo)\n<class 'numpy.ndarray'>\n>>> type(recordarr.bar)\n<class 'numpy.rec.recarray'>\n```\n\nExample:\n```text\n>>> import numpy as np\n```\n\nExample:\n```text\n>>> from numpy.lib import recfunctions as rfn\n>>> b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)],\n...              dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')])\n>>> rfn.apply_along_fields(np.mean, b)\narray([ 2.66666667,  5.33333333,  8.66666667, 11.        ])\n>>> rfn.apply_along_fields(np.mean, b[['x', 'z']])\narray([ 3. ,  5.5,  9. , 11. ])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> a = np.array([(1, (2, 3.0)), (4, (5, 6.0))],\n...   dtype=[('a', np.int64), ('b', [('ba', np.double), ('bb', np.int64)])])\n>>> rfn.drop_fields(a, 'a')\narray([((2., 3),), ((5., 6),)],\n      dtype=[('b', [('ba', '<f8'), ('bb', '<i8')])])\n>>> rfn.drop_fields(a, 'ba')\narray([(1, (3,)), (4, (6,))], dtype=[('a', '<i8'), ('b', [('bb', '<i8')])])\n>>> rfn.drop_fields(a, ['ba', 'bb'])\narray([(1,), (4,)], dtype=[('a', '<i8')])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> ndtype = [('a', int)]\n>>> a = np.ma.array([1, 1, 1, 2, 2, 3, 3],\n...         mask=[0, 0, 1, 0, 0, 0, 1]).view(ndtype)\n>>> rfn.find_duplicates(a, ignoremask=True, return_index=True)\n(masked_array(data=[(1,), (1,), (2,), (2,)],\n             mask=[(False,), (False,), (False,), (False,)],\n       fill_value=(999999,),\n            dtype=[('a', '<i8')]), array([0, 1, 3, 4]))\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> ndtype = np.dtype([('a', '<i4'), ('b', [('ba', '<f8'), ('bb', '<i4')])])\n>>> rfn.flatten_descr(ndtype)\n(('a', dtype('int32')), ('ba', dtype('float64')), ('bb', dtype('int32')))\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> ndtype =  np.dtype([('A', int),\n...                     ('B', [('BA', int),\n...                            ('BB', [('BBA', int), ('BBB', int)])])])\n>>> rfn.get_fieldstructure(ndtype)\n... # XXX: possible regression, order of BBA and BBB is swapped\n{'A': [], 'B': [], 'BA': ['B'], 'BB': ['B'], 'BBA': ['B', 'BB'], 'BBB': ['B', 'BB']}\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> rfn.get_names(np.empty((1,), dtype=[('A', int)]).dtype)\n('A',)\n>>> rfn.get_names(np.empty((1,), dtype=[('A',int), ('B', float)]).dtype)\n('A', 'B')\n>>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])])\n>>> rfn.get_names(adtype)\n('a', ('b', ('ba', 'bb')))\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> rfn.get_names_flat(np.empty((1,), dtype=[('A', int)]).dtype) is None\nFalse\n>>> rfn.get_names_flat(np.empty((1,), dtype=[('A',int), ('B', str)]).dtype)\n('A', 'B')\n>>> adtype = np.dtype([('a', int), ('b', [('ba', int), ('bb', int)])])\n>>> rfn.get_names_flat(adtype)\n('a', 'b', 'ba', 'bb')\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> rfn.merge_arrays((np.array([1, 2]), np.array([10., 20., 30.])))\narray([( 1, 10.), ( 2, 20.), (-1, 30.)],\n      dtype=[('f0', '<i8'), ('f1', '<f8')])\n```\n\nExample:\n```text\n>>> rfn.merge_arrays((np.array([1, 2], dtype=np.int64),\n...         np.array([10., 20., 30.])), usemask=False)\n array([(1, 10.0), (2, 20.0), (-1, 30.0)],\n         dtype=[('f0', '<i8'), ('f1', '<f8')])\n>>> rfn.merge_arrays((np.array([1, 2]).view([('a', np.int64)]),\n...               np.array([10., 20., 30.])),\n...              usemask=False, asrecarray=True)\nrec.array([( 1, 10.), ( 2, 20.), (-1, 30.)],\n          dtype=[('a', '<i8'), ('f1', '<f8')])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> a = np.array([(1, 10.), (2, 20.)], dtype=[('A', np.int64), ('B', np.float64)])\n>>> b = np.zeros((3,), dtype=a.dtype)\n>>> rfn.recursive_fill_fields(a, b)\narray([(1, 10.), (2, 20.), (0,  0.)], dtype=[('A', '<i8'), ('B', '<f8')])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> a = np.array([(1, (2, [3.0, 30.])), (4, (5, [6.0, 60.]))],\n...   dtype=[('a', int),('b', [('ba', float), ('bb', (float, 2))])])\n>>> rfn.rename_fields(a, {'a':'A', 'bb':'BB'})\narray([(1, (2., [ 3., 30.])), (4, (5., [ 6., 60.]))],\n      dtype=[('A', '<i8'), ('b', [('ba', '<f8'), ('BB', '<f8', (2,))])])\n```\n\nExample:\n```text\n>>> from numpy.lib import recfunctions as rfn\n>>> def print_offsets(d):\n...     print(\"offsets:\", [d.fields[name][1] for name in d.names])\n...     print(\"itemsize:\", d.itemsize)\n...\n>>> dt = np.dtype('u1, <i8, <f8', align=True)\n>>> dt\ndtype({'names': ['f0', 'f1', 'f2'], 'formats': ['u1', '<i8', '<f8'], 'offsets': [0, 8, 16], 'itemsize': 24}, align=True)\n>>> print_offsets(dt)\noffsets: [0, 8, 16]\nitemsize: 24\n>>> packed_dt = rfn.repack_fields(dt)\n>>> packed_dt\ndtype([('f0', 'u1'), ('f1', '<i8'), ('f2', '<f8')])\n>>> print_offsets(packed_dt)\noffsets: [0, 1, 9]\nitemsize: 17\n```\n\nExample:\n```text\n>>> from numpy.lib import recfunctions as rfn\n>>> a = np.ones(4, dtype=[('a', 'i4'), ('b', 'f8'), ('c', 'u1')])\n>>> rfn.require_fields(a, [('b', 'f4'), ('c', 'u1')])\narray([(1., 1), (1., 1), (1., 1), (1., 1)],\n  dtype=[('b', '<f4'), ('c', 'u1')])\n>>> rfn.require_fields(a, [('b', 'f4'), ('newf', 'u1')])\narray([(1., 0), (1., 0), (1., 0), (1., 0)],\n  dtype=[('b', '<f4'), ('newf', 'u1')])\n```\n\nExample:\n```text\n>>> import numpy as np\n>>> from numpy.lib import recfunctions as rfn\n>>> x = np.array([1, 2,])\n>>> rfn.stack_arrays(x) is x\nTrue\n>>> z = np.array([('A', 1), ('B', 2)], dtype=[('A', '|S3'), ('B', float)])\n>>> zz = np.array([('a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)],\n...   dtype=[('A', '|S3'), ('B', np.double), ('C', np.double)])\n>>> test = rfn.stack_arrays((z,zz))\n>>> test\nmasked_array(data=[(b'A', 1.0, --), (b'B', 2.0, --), (b'a', 10.0, 100.0),\n                   (b'b', 20.0, 200.0), (b'c', 30.0, 300.0)],\n             mask=[(False, False,  True), (False, False,  True),\n                   (False, False, False), (False, False, False),\n                   (False, False, False)],\n       fill_value=(b'N/A', 1e+20, 1e+20),\n            dtype=[('A', 'S3'), ('B', '<f8'), ('C', '<f8')])\n```\n\nExample:\n```text\n>>> from numpy.lib import recfunctions as rfn\n>>> a = np.zeros(4, dtype=[('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)])\n>>> a\narray([(0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.]),\n       (0, (0., 0), [0., 0.]), (0, (0., 0), [0., 0.])],\n      dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))])\n>>> rfn.structured_to_unstructured(a)\narray([[0., 0., 0., 0., 0.],\n       [0., 0., 0., 0., 0.],\n       [0., 0., 0., 0., 0.],\n       [0., 0., 0., 0., 0.]])\n```\n\nExample:\n```text\n>>> b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)],\n...              dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')])\n>>> np.mean(rfn.structured_to_unstructured(b[['x', 'z']]), axis=-1)\narray([ 3. ,  5.5,  9. , 11. ])\n```\n\nExample:\n```text\n>>> from numpy.lib import recfunctions as rfn\n>>> dt = np.dtype([('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)])\n>>> a = np.arange(20).reshape((4,5))\n>>> a\narray([[ 0,  1,  2,  3,  4],\n       [ 5,  6,  7,  8,  9],\n       [10, 11, 12, 13, 14],\n       [15, 16, 17, 18, 19]])\n>>> rfn.unstructured_to_structured(a, dt)\narray([( 0, ( 1.,  2), [ 3.,  4.]), ( 5, ( 6.,  7), [ 8.,  9.]),\n       (10, (11., 12), [13., 14.]), (15, (16., 17), [18., 19.])],\n      dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))])\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:56.119Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":65,"totalLines":617,"estimatedTokens":16346}}20