0%

【机器学习与数据科学之旅】1 Numpy 实例指南

本文通过许多实际的例子来介绍 Numpy 的用法,磨刀不误砍柴工。相关代码参考 我的 github 库

注:善用搜索和导航效率会更高。


更新历史

  • 2020.06.16: 完成初稿

基本操作

直接上代码,不特别说明了

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import numpy as np

print('列表转为矩阵')
one_list = [1, 2, 3, 4, 5]
array = np.array(one_list)
print(type(array), array)

print('矩阵维度', array.ndim)
print('行数和列数', array.shape)
print('元素个数', array.size)
print('查看元素类型', array.dtype, array.dtype.name)
float_array = array.astype(np.float64)
print('转换数据类型', float_array.dtype)

another_list = [[1,2,3],[4,5,6]]
array = np.array(another_list)
print(type(array), array)

print('矩阵维度', array.ndim)
print('行数和列数', array.shape)
print('元素个数', array.size)

print('创建全 0 矩阵')
all_zero = np.zeros((3,4))
print(all_zero)

print('创建全 1 矩阵并指定类型')
all_one = np.ones((3, 4), dtype=np.int)
print(all_one)

print('创建连续矩阵')
serial_array = np.arange(1,12,2)
print(serial_array)

print('改变上一个矩阵形状')
shape_array = serial_array.reshape((2,3))
print(shape_array)

print('创建插值矩阵')
lin_array = np.linspace(1,20,10)
print(lin_array)

print('改变上一个矩阵形状')
shape_lin_array = lin_array.reshape((5,2))
print(shape_lin_array)

print('一维矩阵运算')
a = np.array([5, 10, 15, 20])
b = np.arange(4)
print('a', a)
print('b', b)
print('a + b', a + b)
print('a - b', a - b)
print('a * b', a * b)
print('a / b', a / b)
print('b^2', b**2)
print('sin(a)', np.sin(a))
print('b < 2', b<2)
print('a == b', a == b)

print('多维矩阵运算')
a = np.array([[1,2], [3,4]])
b = np.arange(4).reshape((2,2))
print('a', a)
print('b', b)
print('a·b', a.dot(b))
print('a·b', np.dot(a,b))
print('sum(a)', np.sum(a))
print('min(a)', np.min(a))
print('max(a)', np.max(a))
print('a 按行求和', np.sum(a, axis=1))
print('a 按列求和', np.sum(a, axis=0))
print('a 按行 max', np.max(a, axis=1))
print('a 按列 min', np.min(a, axis=0))
print('a 最小元素索引', np.argmin(a))
print('a 最大元素索引', np.argmax(a))
print('a 均值(三种方式)', np.mean(a), np.average(a), a.mean())
print('a 中位数', np.median(a))
print('a 累加', np.cumsum(a))
print('a 累差', np.diff(a))
print('固定随机数种子', np.random.seed(0))
print('随机数', np.random.rand(3, 3))
print('固定随机数种子', np.random.seed(0))
print('再次随机,一样的', np.random.rand(3, 3))

矩阵复杂操作

包括排序、索引、切片、分割等

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
43
44
45
46
47
48
49
50
51
52
53
import numpy as np

a = np.arange(20,0,-1).reshape((5,4))
print('a', a)
print('每个元素排序', np.sort(a))
print('转置(两种方法)', np.transpose(a), a.T)
print('限定最大最小值', np.clip(a, 5, 15))
print('选取第二行', a[1])
print('选取第二行第二个元素(两种方式)', a[1][1], a[1, 1])
print('选取第三行前两个元素',a[2, 0:2])
print('打印行')
for row in a:
print(row)
print('打印列')
for col in a.T:
print(col)
print('多维转一维', a.flatten())

print('数组合并')
a = np.array([1,1,1])
b = np.array([2,2,2])
print('a', a)
print('b', b)
c = np.vstack((a,b))
print('c = a 和 b 上下合并', c)
print('a b c 的 shape', a.shape, b.shape, c.shape)
d = np.hstack((a,b))
print('d = a 和 b 左右合并', d)
print('a b d 的 shape', a.shape, b.shape, d.shape)
new_a = a[np.newaxis, :]
print('数组 a 转为矩阵', new_a, new_a.shape)
new_b = b[:, np.newaxis]
print('数组 b 转为矩阵', new_b, new_b.shape)

print('多个矩阵合并')
a = a[:, np.newaxis]
b = b[:, np.newaxis]
print('a', a)
print('b', b)
c = np.concatenate([a, b, b, a], axis=0)
print('纵向合并', c)
d = np.concatenate([b, a, a, b], axis=1)
print('横向合并', d)

print('切分矩阵')
a = np.arange(24).reshape((4,6))
print('a', a)
b = np.split(a, 2, axis=1)
new_b = np.hsplit(a, 2)
print('纵向切分(两种写法)', b, new_b)
c = np.split(a, 2, axis=0)
new_c = np.vsplit(a, 2)
print('横向切分(两种写法)', c, new_c)

复制与广播

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import numpy as np

print('= 赋值是引用赋值,修改会影响其他变量')
a = np.arange(6)
print('a', a)
b = a
c = a
d = c
print('赋值 b = a, c = a, d = c, a[0] = 12')
print('a', a)
print('b', b)
print('c', c)
print('d', d)
print('b is a', b is a)
print('b is c', b is c)
print('d is a', d is a)
print('赋值 d[1:3] = [66, 77]')
d[1:3] = [66, 77]
print('a', a)
print('b', b)
print('c', c)
print('d', d)
print('可以看到全部都变化了')

print('copy 是值复制,不会关联')
new_a = a.copy()
a[3] = 66
print('a', a)
print('new_a', new_a)

print('广播机制')
a = np.array([[0, 0, 0], [10, 10, 10], [20, 20, 20]])
b = np.array([6, 7, 8])
print('a', a.shape, a)
print('b', b.shape, b)
print('a+b', a+b)

print('统计元素个数')
a = np.array([1, 2, 3, 3, 4, 4, 4, 0, 0, 2, 2])
print('a', a)
print('各个元素个数', np.bincount(a))
a = np.array([-0.6, 1.234, 2.345, 3.456])
print('a', a)
print('取 0 位小数', np.around(a, decimals=0))
print('取 1 位小数', np.around(a, decimals=1))
print('floor 取整', np.floor(a))
print('ceil 取上限', np.ceil(a))
print('通过 where 来条件填充,第一个参数是不填充的条件', np.where(a > 0, a, 666))
a = np.array([4, 9, 16, 25])
b = np.array([1, 10, 15, 30])
print('a', a)
print('b', b)
print('a 开方', np.sqrt(a))
print('a 平方', np.square(a))
print('a 和 b 取大的', np.maximum(a, b))
print('元素比较 a 和 b', np.greater(a, b))

Numpy 实战题目

来自 rougier/numpy-100的习题,这里简单翻译并给出答案,部分题目因为比较简单就合并到一起了。直接看代码:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import numpy as np
import time

print('1. 创建大小为 10 的空向量')
a = np.zeros(10)
print(a)

print('2. 查看矩阵占据的内存大小')
print('用元素个数乘以每个元素的大小')
print(f'占据 {a.size * a.itemsize} 字节')

print('3. 创建一个向量,值从 10 到 49')
a = np.arange(10, 50)
print(a)

print('4. 翻转一个向量')
a = a[::-1]
print(a)

print('5. 创建一个 3x3 的矩阵,值从 0 到 8')
a = np.arange(9).reshape(3,3)
print(a)

print('6. 从 [1, 2, 0, 0, 4, 0] 中寻找非零元素索引')
nz = np.nonzero([1, 2, 0, 0, 4, 0])
print(nz)

print('7. 创建 3x3 单位矩阵(对角线元素为 1 的方阵)')
a = np.eye(3)
print(a)

print('8. 创建一个 3x3x3 的随机矩阵')
a = np.random.random((3, 3, 3))
print(a)

print('9. 创建一个 10x10 的矩阵并寻找最大最小值')
a = np.random.random((10, 10))
a_min, a_max = a.min(), a.max()
print('min', a_min, ', max', a_max)

print('10. 创建一个长度为 30 的向量,并求均值')
a = np.random.random(30)
print('mean', a.mean())

print('11. 创建一个边界为 1 其他为 0 的二维矩阵')
a = np.ones((10, 10))
a[1:-1,1:-1] = 0
print(a)

print('12. 为已经存在的矩阵填充 0 的边界')
a = np.ones((5, 5))
print(a)
a = np.pad(a, pad_width=1, mode='constant', constant_values=0)
print(a)

print('13. 给出下列计算的结果')
print('0 * np.nan =', 0 * np.nan)
print('np.nan == np.nan =', np.nan == np.nan)
print('np.inf > np.nan =', np.inf > np.nan)
print('np.nan - np.nan =', np.nan - np.nan)
print('np.nan in set([np.nan]) =', np.nan in set([np.nan]))
print('0.3 == 3 * 0.1 =', 0.3 == 3 * 0.1)

print('14. 创建一个 5x5 的矩阵,对角线下的数值为 1 2 3 4')
a = np.diag(1 + np.arange(4), k=-1)
print(a)

print('15. 创建一个 8x8 矩阵,其中 0 和 1 间隔分布')
a = np.zeros((8, 8), dtype=int)
a[1::2, ::2] = 1
a[::2, 1::2] = 1
print(a)

print('16. 使用 tile 函数创建一个 8x8 矩阵,其中 0 和 1 间隔分布')
a = np.tile(np.array([[0, 1], [1, 0]]), (4, 4))
print(a)

print('17. 假设有一个 (6, 7, 8) 大小的矩阵,那么第 100 个元素的索引是多少')
print(np.unravel_index(100, (6, 7, 8)))

print('18. 归一化一个随机 5x5 矩阵')
a = np.random.random((5, 5))
a = (a - np.mean(a)) / np.std(a)
print(a)

print('19. 点乘一个 5x3 和 3x2 的矩阵')
a = np.dot(np.ones((5, 3)), np.ones((3, 2)))
print(a)

print('20. 给定一个一维数组,不新增空间,把 3~8 之间的数字变成负数')
a = np.arange(10)
a[(3 < a) & (a <= 8)] *= -1
print(a)

print('21. 两个数组求交集')
a1 = np.random.randint(0, 10, 10)
a2 = np.random.randint(0, 10, 10)
print(np.intersect1d(a1, a2))

print('22. 获取 2020 年 6 月的所有日期')
a = np.arange('2020-06', '2020-07', dtype='datetime64[D]')
print(a)

print('23. 用 5 种方法去掉小数部分')
a = np.random.uniform(0, 10, 10)
print('a', a)
print('1:', a - a%1)
print('2:', np.floor(a))
print('3:', np.ceil(a) - 1)
print('4:', a.astype(int))
print('5:', np.trunc(a))

print('24. 创建一个 5x5 的矩阵,每一行都是从 0 到 4')
a = np.zeros((5, 5))
a += np.arange(5)
print(a)

print('25. 创建一个大小为 10,值从 0 到 1 的向量(不包括 0 和 1)')
a = np.linspace(0, 1, 11, endpoint=False)[1:]
print(a)

print('26. 创建一个大小为 10 的随机向量并排序')
a = np.random.random(10)
a.sort()
print(a)

print('27. 如何用比 np.sum 更快的方法对一个小数组求和')
a = np.arange(10)
print('a', a)
start = time.time()
print('add.reduct', np.add.reduce(a))
end = time.time()
print('add.reduce time:', end-start)
start = time.time()
print('np.sum', np.sum(a))
end = time.time()
print('np.sum time:', end - start)

print('28. 比较两个数组是否相等')
a = np.random.randint(0, 10, 10)
b = np.random.randint(0, 10, 10)
print(np.allclose(a, b))
print(np.array_equal(a, b))

print('29. 将一个 10x2 的笛卡尔坐标系的点转成极坐标')
a = np.random.random((10, 2))
x, y = a[:, 0], a[:, 1]
r = np.sqrt(x**2 + y**2)
t = np.arctan2(y, x)
print(r)
print(t)

print('30. 创建一个大小为 10 的随机向量,并将最大的替换成 0')
a = np.random.random(10)
print('before', a)
a[a.argmax()] = 0
print('after', a)

print('31. 不用额外空间将 float 矩阵变成 int 矩阵')
a = np.arange(10, dtype=np.float32)
a = a.astype(np.int32, copy=False)
print(a)

print('32. 在一个 2 维矩阵中随机放 p 个元素')
n, p = 10, 3
a = np.zeros((n, n))
np.put(a, np.random.choice(range(n*n), p, replace=False), 1)
print(a)

print('33. 矩阵的每行减去每行的均值')
a = np.random.randint(0, 10, (5, 10))
print('before', a)
b = a - a.mean(axis=1, keepdims=True)
print('after', b)

print('34. 根据第 i 列给矩阵排序')
a = np.random.randint(0, 10, (3, 3))
print('before', a)
print('after', a[a[:, 1].argsort()])

print('35. 交换矩阵的两行')
a = np.arange(25).reshape(5, 5)
a[[0,1]] = a[[1, 0]]
print(a)

print('36. 如何计算一个数组的滑动窗口')
def moving_averate(a, n=3):
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n-1:] / n
a = np.arange(20)
print(moving_averate(a, n=4))

print('37. 如何找到数组中出现次数最多的元素')
a = np.random.randint(0, 10, 50)
print(np.bincount(a).argmax())

print('38. 如何获取数组中最大的 n 个数')
a = np.arange(1000)
np.random.shuffle(a)
n = 5
start = time.time()
print('slow', a[np.argsort(a)[-n:]])
end = time.time()
print('slow time', end - start)
start = time.time()
print('fast', a[np.argpartition(-a, n)[:n]])
end = time.time()
print('fast time', end - start)