--- jupyter: jupytext: text_representation: extension: .md format_name: markdown format_version: '1.1' jupytext_version: 1.1.0-rc0 kernelspec: display_name: Python 3 language: python name: python3 --- ```raw_mimetype="text/restructuredtext" .. meta:: :description: Topic: Indexing into multi-dimensional numpy arrays, Difficulty: Easy, Category: Section :keywords: numpy array, multidimensional, index, slice, negative index, rows, columns ``` # Accessing Data Along Multiple Dimensions in an Array In this section, we will: - Define the "dimensionality" of an array. - Discuss the usefulness of ND-arrays. - Introduce the indexing and slicing scheme for accessing a multi-dimensional array's contents We will encounter arrays of varying dimensionalities: ```python # A 0-D array np.array(8) # A 1-D array, shape-(3,) np.array([2.3, 0.1, -9.1]) # A 2-D array, shape-(3, 2) np.array([[93, 95], [84, 100], [99, 87]]) # A 3-D array, shape-(2, 2, 2) np.array([[[0, 1], [2, 3]], [[4, 5], [6, 7]]]) ``` Similar to Python's sequences, we use 0-based indices and slicing to access the content of an array. However, we must specify an index/slice for *each* dimension of an array: ```python >>> import numpy as np # A 3-D array >>> x = np.array([[[0, 1], ... [2, 3]], ... ... [[4, 5], ... [6, 7]]]) # get: sheet-0, both rows, flip order of columns >>> x[0, :, ::-1] array([[1, 0], [3, 2]]) ``` ## One-dimensional Arrays Let's begin our discussion by constructing a simple ND-array containing three floating-point numbers. ```python >>> simple_array = np.array([2.3, 0.1, -9.1]) ``` This array supports the same indexing scheme as Python's sequences (lists, tuples, and strings): ``` +------+------+------+ | 2.3 | 0.1 | -9.1 | +------+------+------+ 0 1 2 -3 -2 -1 ``` The first row of numbers gives the position of the indices 0…3 in the array; the second row gives the corresponding negative indices. The slice from \$i\$ to \$j\$ returns an array containing of all numbers between the edges labeled \$i\$ and \$j\$, respectively: ```python >>> simple_array[0] 2.3 >>> simple_array[-2] 0.1 >>> simple_array[1:3] array([ 0.1, -9.1]) >>> simple_array[3] IndexError: index 3 is out of bounds for axis 0 with size 3 ``` Given this indexing scheme, only *one* integer is needed to specify a unique entry in the array. Similarly only *one* slice is needed to uniquely specify a subsequence of entries in the array. For this reason, we say that this is a *1-dimensional array*. In general, the *dimensionality* of an array specifies the number of indices that are required to uniquely specify one of its entries.
**Definition**: The **dimensionality** of an array specifies the number of indices that are required to uniquely specify one of its entries.
This definition of dimensionality is common far beyond NumPy; one must use three numbers to uniquely specify a point in physical space, which is why it is said that space consists of three dimensions. ## Two-dimensional Arrays Before proceeding further down the path of high-dimensional arrays, let's briefly consider a very simple dataset where the desire to access the data along multiple dimensions is manifestly desirable. Consider the following table from a gradebook: | | Exam 1 (%) | Exam 2 (%) | | ------------- |:-------------:| -----:| | Ashley | \$93\$ | \$95\$ | | Brad | \$84\$ | \$100\$ | | Cassie | \$99\$ | \$87\$ | This dataset contains 6 grade-values. It is almost immediately clear that storing these in a 1-dimensional array is not ideal: ```python # using a 1-dimensional array to store the grades >>> grades = np.array([93, 95, 84, 100, 99, 87]) ``` While no data has been lost, accessing this data using a single index is less than convenient; we want to be able to specify both the student and the exam when accessing a grade - it is natural to ascribe *two dimensions* to this data. Let's construct a 2D array containing these grades: ```python # using a 2-dimensional array to store the grades >>> grades = np.array([[93, 95], ... [84, 100], ... [99, 87]]) ``` NumPy is able to see the repeated structure among the list-of-lists-of-numbers passed to `np.array`, and resolve the two dimensions of data, which we deem the 'student' dimension and the 'exam' dimension, respectively.
**Axis vs Dimension**: Although NumPy does formally recognize the concept of dimensionality precisely in the way that it is discussed here, its documentation refers to an individual dimension of an array as an **axis**. Thus you will see "axes" (pronounced "aks-ēz") used in place of "dimensions"; however, they mean the same thing.