This is an excerpt from the Python Data Science Handbook by Jake VanderPlas; Jupyter notebooks are available on GitHub.

The text is released under the CC-BY-NC-ND license, and code is released under the MIT license. If you find this content useful, please consider supporting the work by buying the book!

Basicos de NumPy: arreglos

Categorias de manipulaciones básicas de arreglos:

  • Atributos de arrays
  • Indexado de arrays
  • Rebanadas de arrays
  • Reformado de arrays
  • Union y separación de arrays

Atributos de Arrays

In [1]:
import numpy as np
np.random.seed(0)  # seed for reproducibility

x1 = np.random.randint(10, size=6)  # One-dimensional array
x2 = np.random.randint(10, size=(3, 4))  # Two-dimensional array
x3 = np.random.randint(10, size=(3, 4, 5))  # Three-dimensional array
In [2]:
print("x3 ndim: ", x3.ndim)
print("x3 shape:", x3.shape)
print("x3 size: ", x3.size)
x3 ndim:  3
x3 shape: (3, 4, 5)
x3 size:  60
In [3]:
print("dtype:", x3.dtype)
dtype: int64
In [4]:
print("itemsize:", x3.itemsize, "bytes")
print("nbytes:", x3.nbytes, "bytes")
itemsize: 8 bytes
nbytes: 480 bytes

Indexado de Arrays : Acceso a elementos individuales

In [5]:
x1
Out[5]:
array([5, 0, 3, 3, 7, 9])
In [6]:
x1[0]
Out[6]:
5
In [7]:
x1[4]
Out[7]:
7
In [8]:
x1[-1]
Out[8]:
9
In [9]:
x1[-2]
Out[9]:
7
In [10]:
x2
Out[10]:
array([[3, 5, 2, 4],
       [7, 6, 8, 8],
       [1, 6, 7, 7]])
In [11]:
x2[0, 0]
Out[11]:
3
In [12]:
x2[2, 0]
Out[12]:
1
In [13]:
x2[2, -1]
Out[13]:
7
In [14]:
x2[0, 0] = 12
x2
Out[14]:
array([[12,  5,  2,  4],
       [ 7,  6,  8,  8],
       [ 1,  6,  7,  7]])
In [15]:
x1[0] = 3.14159  # this will be truncated!
x1
Out[15]:
array([3, 0, 3, 3, 7, 9])

Rebanadas de Arrays: Accesa a partes (subarrays)

x[start:stop:step]

Uni-dimensionales

In [16]:
x = np.arange(10)
x
Out[16]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [17]:
x[:5]  # first five elements
Out[17]:
array([0, 1, 2, 3, 4])
In [18]:
x[5:]  # elements after index 5
Out[18]:
array([5, 6, 7, 8, 9])
In [19]:
x[4:7]  # middle sub-array
Out[19]:
array([4, 5, 6])
In [20]:
x[::2]  # every other element
Out[20]:
array([0, 2, 4, 6, 8])
In [21]:
x[1::2]  # every other element, starting at index 1
Out[21]:
array([1, 3, 5, 7, 9])
In [22]:
x[::-1]  # all elements, reversed
Out[22]:
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
In [23]:
x[5::-2]  # reversed every other from index 5
Out[23]:
array([5, 3, 1])

Multi-dimensionales

In [24]:
x2
Out[24]:
array([[12,  5,  2,  4],
       [ 7,  6,  8,  8],
       [ 1,  6,  7,  7]])
In [25]:
x2[:2, :3]  # two rows, three columns
Out[25]:
array([[12,  5,  2],
       [ 7,  6,  8]])
In [26]:
x2[:3, ::2]  # all rows, every other column
Out[26]:
array([[12,  2],
       [ 7,  8],
       [ 1,  7]])
In [27]:
x2[::-1, ::-1]
Out[27]:
array([[ 7,  7,  6,  1],
       [ 8,  8,  6,  7],
       [ 4,  2,  5, 12]])

Accesando renglones y columnas del array

In [28]:
print(x2[:, 0])  # first column of x2
[12  7  1]
In [29]:
print(x2[0, :])  # first row of x2
[12  5  2  4]
In [30]:
print(x2[0])  # equivalent to x2[0, :]
[12  5  2  4]

Subarrays son vistas y no copias

  • Es importante, y práctico, entender que las rebanadas de arrays son vistas del trozo y no copias del subarray
In [31]:
print(x2)
[[12  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

extraer un subarray de $2 \times 2$ de éste:

In [32]:
x2_sub = x2[:2, :2]
print(x2_sub)
[[12  5]
 [ 7  6]]

Ahora si modificamos este subarray, el array original también cambia! Miren:

In [33]:
x2_sub[0, 0] = 99
print(x2_sub)
[[99  5]
 [ 7  6]]
In [34]:
print(x2)
[[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]
  • Este comportamiento es de utilidad pues se pueden acceder y procesar partes de los arrays sin tener que hacer copias de ellos

Creando copias de arrays

  • En ocasiones será práctico crear copias explícitas de los datos
  • Esto se hace con el método copy():
In [35]:
x2_sub_copy = x2[:2, :2].copy()
print(x2_sub_copy)
[[99  5]
 [ 7  6]]

Si ahora modificamos este subarray, el original no cambia:

In [36]:
x2_sub_copy[0, 0] = 42
print(x2_sub_copy)
[[42  5]
 [ 7  6]]
In [37]:
print(x2)
[[99  5  2  4]
 [ 7  6  8  8]
 [ 1  6  7  7]]

Reformado (reshaping) de Arrays

  • Podemos cambiar la forma (reformar) de un array usando el método reshape Por ejemplo, si queremos los número del 1 al 9 en un array de $3 \times 3$, podemos hacer lo siguiente:
In [38]:
grid = np.arange(1, 10).reshape((3, 3))
print(grid)
[[1 2 3]
 [4 5 6]
 [7 8 9]]
In [39]:
x = np.array([1, 2, 3])

# row vector via reshape
x.reshape((1, 3))
Out[39]:
array([[1, 2, 3]])
In [40]:
# row vector via newaxis
x[np.newaxis, :]
Out[40]:
array([[1, 2, 3]])
In [41]:
# column vector via reshape
x.reshape((3, 1))
Out[41]:
array([[1],
       [2],
       [3]])
In [42]:
# column vector via newaxis
x[:, np.newaxis]
Out[42]:
array([[1],
       [2],
       [3]])

Concatenación y Separación de Arrays

  • Es posible combinar multiples arrays en uno
  • Es posible separar un array a multiples arrays

Concatenación de arrays

Concatenacion, o unión de dos arrays en NumPy, se puede hacer con np.concatenate, np.vstack, y np.hstack. np.concatenate toma una tupla o lista de arrays como primer argumento:

In [43]:
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
np.concatenate([x, y])
Out[43]:
array([1, 2, 3, 3, 2, 1])
In [44]:
z = [99, 99, 99]
print(np.concatenate([x, y, z]))
[ 1  2  3  3  2  1 99 99 99]
In [45]:
grid = np.array([[1, 2, 3],
                 [4, 5, 6]])
In [46]:
# concatenate along the first axis
np.concatenate([grid, grid])
Out[46]:
array([[1, 2, 3],
       [4, 5, 6],
       [1, 2, 3],
       [4, 5, 6]])
In [47]:
# concatenate along the second axis (zero-indexed)
np.concatenate([grid, grid], axis=1)
Out[47]:
array([[1, 2, 3, 1, 2, 3],
       [4, 5, 6, 4, 5, 6]])
In [48]:
x = np.array([1, 2, 3])
grid = np.array([[9, 8, 7],
                 [6, 5, 4]])

# vertically stack the arrays
np.vstack([x, grid])
Out[48]:
array([[1, 2, 3],
       [9, 8, 7],
       [6, 5, 4]])
In [49]:
# horizontally stack the arrays
y = np.array([[99],
              [99]])
np.hstack([grid, y])
Out[49]:
array([[ 9,  8,  7, 99],
       [ 6,  5,  4, 99]])

Separación de arrays

El opuesto a la concatenación es la sepación, implementada en las funciones np.split, np.hsplit, y np.vsplit. Para cada una de éstas podemos pasar una lista de índices en donde se quiere hacer la separación:

In [50]:
x = [1, 2, 3, 99, 99, 3, 2, 1]
x1, x2, x3 = np.split(x, [3, 5])
print(x1, x2, x3)
[1 2 3] [99 99] [3 2 1]

N puntos-de-separación, crean N + 1 subarrays.

In [51]:
grid = np.arange(16).reshape((4, 4))
grid
Out[51]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
In [52]:
upper, lower = np.vsplit(grid, [2])
print(upper)
print(lower)
[[0 1 2 3]
 [4 5 6 7]]
[[ 8  9 10 11]
 [12 13 14 15]]
In [53]:
left, right = np.hsplit(grid, [2])
print(left)
print(right)
[[ 0  1]
 [ 4  5]
 [ 8  9]
 [12 13]]
[[ 2  3]
 [ 6  7]
 [10 11]
 [14 15]]