记录生活中的点点滴滴

0%

NumPy学习

这些天开始学习机器学习了,先从 NumPy 开始起来,这篇博客就来记录一下学习过程,我的参考网站就是 NumPy 的官网:NumPy中文网

理解 NumPy

什么是 NumPy?

NumPy是一个功能强大的Python库,主要用于对多维数组执行计算。NumPy这个词来源于两个单词– NumericalPython

NumPy 的安装

shell终端输入:pip install numpy

这样会有点慢,我们可以用清华大学的镜像:

1
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

NumPy 中的数组

定义一维NumPy数组:

1
2
3
import numpy as np
my_array = np.array([1,2,3,4,5])
print(my_array) # [1 2 3 4 5]

我们创建了一个包含5个整数的简单NumPy数组,然后我们将其打印出来。

1
2
3
4
print(my_array.shape) # (5,)
print(my_array[1]) # 2
my_array[1] = 20
print(my_array[1]) # 20

如上,我们可以用数组那样进行操作

现在假设,我们要创建一个长度为5的NumPy数组,但所有元素都为0,我们可以这样做吗?是的。NumPy提供了一种简单的方法来做同样的事情。

1
2
my_array2 = np.zeros((5))
print(my_array2) # [0. 0. 0. 0. 0.]

np.zeros 类似,我们也有 np.ones

1
2
my_array4 = np.ones((5))
print(my_array4) # [1. 1. 1. 1. 1.]

如果我们想创建一个随机值数组怎么办?

1
2
my_array3 = np.random.random((5))
print(my_array3) # [0.43683803 0.18979663 0.88895514 0.01269009 0.32726712]

基本上,当你使用函数np.zeros()np.ones()时,你可以指定讨论数组大小的元组。在上面的两个例子中,我们使用以下元组,(2, 3) 和(2, 4) 分别表示2行,3列和4列。像上面那样的多维数组可以用 my_array[i][j] 符号来索引,其中i表示行号,j表示列号。i和j都从0开始。

1
2
3
my_array5 = np.ones((2,3))
print(my_array5) # [[1. 1. 1.]
# [1. 1. 1.]]

NumPy提供了一种提取多维数组的行/列的强大方法。

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

结果为:[[1 2] [3 4]]

1
2
my_column_array6 = my_array6[:,1]
print(my_column_array6) # [2 4]

NumPy中的数组操作

使用NumPy,你可以轻松地在数组上执行数学运算。例如,你可以添加NumPy数组,你可以减去它们,你可以将它们相乘,甚至可以将它们分开。 以下是一些例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np 
a = np.array([[1.0, 2.0], [3.0, 4.0]])
b = np.array([[5.0, 6.0], [7.0, 8.0]])
sum = a + b
difference = a - b
product = a * b
quotient = a / b
print "Sum = \n", sum
print "Difference = \n", difference
print "Product = \n", product
print "Quotient = \n", quotient

# The output will be as follows:

Sum = [[ 6. 8.] [10. 12.]]
Difference = [[-4. -4.] [-4. -4.]]
Product = [[ 5. 12.] [21. 32.]]
Quotient = [[0.2 0.33333333] [0.42857143 0.5 ]]

如你所见,乘法运算符执行逐元素乘法而不是矩阵乘法。 要执行矩阵乘法,你可以执行以下操作:

1
2
matrix_product = a.dot(b) 
print "Matrix Product = ", matrix_product

输出将是:

1
2
3
[[19. 22.]

[43. 50.]]

NumPy 简单入门教程

数组基础

创建一个数组

NumPy围绕这些称为数组的事物展开。实际上它被称之为 ndarrays。使用NumPy提供的这些数组,我们就可以以闪电般的速度执行各种有用的操作,如矢量和矩阵、线性代数等数学运算!

1
2
3
4
5
6
7
8
9
10
# 创建一维数组
a = np.array([0,1,2,3,4])
b = np.array((0,1,2,3,4))
c = np.arange(5)
d = np.linspace(0, 5*np.pi, 5)

print(a) # [0 1 2 3 4]
print(b) # [0 1 2 3 4]
print(c) # [0 1 2 3 4]
print(d) # [ 0. 3.14159265 6.28318531 9.42477796 12.56637061]

上面的代码显示了创建数组的4种不同方法。最基本的方法是将序列传递给NumPy的array()函数; 你可以传递任何序列(类数组),而不仅仅是常见的列表(list)数据类型。

多维数组切片
1
2
3
4
5
6
7
8
9
10
11
12
a = np.array([[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]])

print(a[0, 1:4]) # >>>[12 13 14]
print(a[1:4, 0]) # >>>[16 21 26]
print(a[::2,::2]) # >>>[[11 13 15]
# [21 23 25]
# [31 33 35]]
print(a[:, 1]) # >>>[12 17 22 27 32]

下面的图表说明了给定的示例切片是如何进行工作的。

数组属性
1
2
3
4
5
6
7
8
9
10
11
12
13
print(type(a)) # <class 'numpy.ndarray'>
# 数据类型
print(a.dtype) # int32
# 数据数量
print(a.size) # 25
# 形状
print(a.shape) # (5,5)
# 每个项占用的字节数
print(a.itemsize) # 4
# 维数
print(a.ndim) # 2
# 数组中的所有数据消耗掉的字节数
print(a.nbytes) # 100

使用数组

基本操作符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = np.arange(25)
a = a.reshape((5, 5))

b = np.array([10, 62, 1, 14, 2, 56, 79, 2, 1, 45,
4, 92, 5, 55, 63, 43, 35, 6, 53, 24,
56, 3, 56, 44, 78])
b = b.reshape((5,5))

print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a ** 2)
print(a < b) print(a > b)

print(a.dot(b))

除了 dot() 之外,这些操作符都是对数组进行逐元素运算。比如 (a, b, c) + (d, e, f) 的结果就是 (a+d, b+e, c+f)。它将分别对每一个元素进行配对,然后对它们进行运算。它返回的结果是一个数组。注意,当使用逻辑运算符比如 “<” 和 “>” 的时候,返回的将是一个布尔型数组,这点有一个很好的用处,后边我们会提到。

数组特殊运算符
1
2
3
4
5
6
7
a = np.arange(10)
print(a) # [0 1 2 3 4 5 6 7 8 9]

print(a.sum()) # 45
print(a.max()) # 9
print(a.min()) # 0
print(a.cumsum()) # [ 0 1 3 6 10 15 21 28 36 45]

索引进阶

花式索引

花式索引 是获取数组中我们想要的特定元素的有效方法。

1
2
3
4
5
6
# Fancy indexing
a = np.arange(0, 100, 10)
indices = [1, 5, -1]
b = a[indices]
print(a) # >>>[ 0 10 20 30 40 50 60 70 80 90]
print(b) # >>>[10 50 90]

正如你在上面的示例中所看到的,我们使用我们想要检索的特定索引序列对数组进行索引。这反过来返回我们索引的元素的列表。

布尔屏蔽

布尔屏蔽是一个有用的功能,它允许我们根据我们指定的条件检索数组中的元素。

缺省索引

不完全索引是从多维数组的第一个维度获取索引或切片的一种方便方法。例如,如果数组a=[1,2,3,4,5],[6,7,8,9,10],那么[3]将在数组的第一个维度中给出索引为3的元素,这里是值4。

1
2
3
4
5
a = np.arange(0, 100, 10)
b = a[:5]
c = a[a >= 50]
print(b) # >>>[ 0 10 20 30 40]
print(c) # >>>[50 60 70 80 90]
where函数

where() 函数是另外一个根据条件返回数组中的值的有效方法。只需要把条件传递给它,它就会返回一个使得条件为真的元素的列表。

1
2
3
4
5
a = np.arange(0, 100, 10)
b = np.where(a < 50)
c = np.where(a >= 50)[0]
print(b) # >>>(array([0, 1, 2, 3, 4], dtype=int64),)
print(c) # >>>[5 6 7 8 9]

NumPy继续学习

广播(Broadcasting)

广播是一种强大的机制,它允许numpy在执行算术运算时使用不同形状的数组。通常,我们有一个较小的数组和一个较大的数组,我们希望多次使用较小的数组来对较大的数组执行一些操作。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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)

for i in range(4):
y[i,:] = x[i,:] + v
print(y)

# Now y is the following
# [[ 2 2 2]
# [ 5 5 5]
# [ 8 8 8]
# [11 11 11]]

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

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

如上面那个例子,其实直接 x+v 则就是我们要的那个矩阵

NumPy文档

NumPy 参考手册