基于伯克利ds100和cs231n的numpy笔记

Numpy 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。

数组

numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组

1
2
3
b = np.array([[1,2,3],[4,5,6]])    # Create a rank 2 array
print(b.shape) # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"

官方数组创建教程 ds100的numpy教程 cs231n的python numpy教程

创建数组的方法

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
>>>np.array([[1.,2.], [3.,4.]])

array([[ 1., 2.],
[ 3., 4.]])

>>>np.array([x for x in range(5)])

array([0, 1, 2, 3, 4])

>>>np.array([["A", "matrix"], ["of", "words."]])

array([['A', 'matrix'],
['of', 'words.']],
dtype='<U6')

>>>np.ones([3,2])

array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.]])

>>>np.random.randn(3,2)

array([[ 0.3601399 , 1.31206686],
[-0.95112397, 0.62475726],
[-1.24179768, 1.63392069]])

1
2
3
4
5
6
7
>>>c = np.full((2,2), 7)  # Create a constant array
print(c) # Prints "[[ 7. 7.]
# [ 7. 7.]]"

>>>d = np.eye(2) # Create a 2x2 identity matrix
print(d) # Prints "[[ 1. 0.]
# [ 0. 1.]]"

数组属性

  • dtype
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>>np.arange(1,5).dtype

dtype('int64')

>>>np.array(["Hello", "Worlddddd!"]).dtype

dtype('<U10')
/*
What does `<U6` mean?
- `<` Little Endian
- `U` Unicode
- `6` length of longest string
*/

>>> np.array([1,2,3]).astype(float)

array([ 1., 2., 3.])

数组的类型与其包含的数据类型相对应,可以用.astype改变类型

数组编辑

重组和展开

1
2
3
4
5
6
7
8
9
>>>np.arange(1,13).reshape(4,3)

array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])

>>>A.flatten()
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

切片索引和整数索引

切片时,第一个参数是行,第二个是列,切片形成的是对原来数组的引用,修改子数组也会影响原数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
# [6 7]]
b = a[:2, 1:3]

# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1]) # Prints "2"
b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1]) # Prints "77"

可以混合整数索引和切片索引,这样做会产生一个比原始数组的秩更低的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :] # Rank 1 view of the second row of a
row_r2 = a[1:2, :] # Rank 2 view of the second row of a
print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)"

# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) # Prints "[ 2 6 10] (3,)"
print(col_r2, col_r2.shape) # Prints "[[ 2]
# [ 6]
# [10]] (3, 1)"

整数数组 索引允许你使用另一个数组的数据构造任意数组 大批。 这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

# An example of integer array indexing.
# The returned array will have shape (3,) and
print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]"

# The above example of integer array indexing is equivalent to this:
print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]"

# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]]) # Prints "[2 2]"

# Equivalent to the previous integer array indexing example
print(np.array([a[0, 1], a[0, 1]])) # Prints "[2 2]"

可以用整数数组索引修改数组部分值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np

# Create a new array from which we will select elements
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

print(a) # prints "array([[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9],
# [10, 11, 12]])"

# Create an array of indices
b = np.array([0, 2, 0, 1])

# Select one element from each row of a using the indices in b
print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]"

# Mutate one element from each row of a using the indices in b
a[np.arange(4), b] += 10

print(a) # prints "array([[11, 2, 3],
# [ 4, 5, 16],
# [17, 8, 9],
# [10, 21, 12]])

数组的数学运算

numpy 提供的数学函数的完整列表 文档 Numpy 提供了更多用于操作数组的函数; 完整的列表 文档

Numpy 提供了许多有用的函数来执行计算 数组; 最有用的之一是 sum:

1
2
3
4
5
6
7
import numpy as np

x = np.array([[1,2],[3,4]])

print(np.sum(x)) # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0)) # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1)) # Compute sum of each row; prints "[3 7]"

转置矩阵, 只需使用 T数组对象的属性:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

x = np.array([[1,2], [3,4]])
print(x) # Prints "[[1 2]
# [3 4]]"
print(x.T) # Prints "[[1 3]
# [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v) # Prints "[1 2 3]"
print(v.T) # Prints "[1 2 3]"

广播

我们有一个较小的数组和一个 较大的数组,并且我们想多次使用较小的数组来执行某些操作 在更大的阵列上。

例如,假设我们要向每个添加一个常数向量 矩阵的行。 我们可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) # Create an empty matrix with the same shape as x

# Add the vector v to each row of the matrix x with an explicit loop
for i in range(4):
y[i, :] = x[i, :] + v

# Now y is the following
# [[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]
print(y)

Numpy 广播允许我们执行此计算,而无需实际执行 创建多个副本 v。 考虑这个版本,使用广播:

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v # Add v to each row of x using broadcasting
print(y) # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"

线路 y = x + v尽管有效 x有形状 (4, 3)v有形状 (3,)由于广播; 这条线的工作原理就像 v实际上有形状 (4, 3), 其中每一行都是一个副本 v,并且按元素求和。

一起广播两个数组遵循以下规则:

  1. 如果数组没有相同的秩,则在前面添加较低秩数组的形状 1s 直到两个形状具有相同的长度。
  2. 如果两个数组具有相同的维度,则称 兼容 它们在维度上 维度中的大小,或者如果其中一个数组在该维度中的大小为 1。
  3. 如果数组在所有维度上都兼容,则可以一起广播。
  4. 广播后,每个数组的行为就好像它的形状等于元素方向 两个输入数组的形状的最大值。
  5. 在一个数组的大小为 1 而另一个数组的大小大于 1 的任何维度中, 第一个数组的行为就好像它是沿着该维度复制的

一些应用

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
35
36
37
38
39
40
41
42
import numpy as np

# Compute outer product of vectors
v = np.array([1,2,3]) # v has shape (3,)
w = np.array([4,5]) # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4 5]
# [ 8 10]
# [12 15]]
print(np.reshape(v, (3, 1)) * w)

# Add a vector to each row of a matrix
x = np.array([[1,2,3], [4,5,6]])
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
# giving the following matrix:
# [[2 4 6]
# [5 7 9]]
print(x + v)

# Add a vector to each column of a matrix
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5 6 7]
# [ 9 10 11]]
print((x.T + w).T)
# Another solution is to reshape w to be a column vector of shape (2, 1);
# we can then broadcast it directly against x to produce the same
# output.
print(x + np.reshape(w, (2, 1)))

# Multiply a matrix by a constant:
# x has shape (2, 3). Numpy treats scalars as arrays of shape ();
# these can be broadcast together to shape (2, 3), producing the
# following array:
# [[ 2 4 6]
# [ 8 10 12]]
print(x * 2)