每天开心一点

NumPy 百题大冲关

2020-11-25 08:36:00    六月    4718    来源: https://www.lanqiao.cn/courses/1090/learning/?id=6137

NumPy 是 Python 语言的一个第三方库,其支持大量高维度数组与矩阵运算。此外,NumPy 也针对数组运算提供大量的数学函数。机器学习涉及到大量对数组的变换和运算,NumPy 就成了必不可少的工具之一。NumPy 百题大冲关分为基础篇和进阶篇,每部分各有 50 道练习题。基础部分的练习题在于熟悉 NumPy 常用方法的使用,而进阶部分则侧重于 NumPy 方法的组合应用。

练习 NumPy 之前,首先需要导入 NumPy 模块,并约定简称为 np。

教学代码:

1. 导入 NumPy:

import numpy as np

2. 查看 NumPy 版本信息:

np.__version__

创建数组

NumPy 的主要对象是多维数组 Ndarray。在 NumPy 中维度 Dimensions 叫做轴 Axes,轴的个数叫做秩 Rank。注意,numpy.array 和 Python 标准库 array.array 并不相同,前者更为强大,这也就是我们学习 NumPy 的重要原因之一。

3. 通过列表创建一维数组:

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

4. 通过列表创建二维数组:

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

5. 创建全为 0 的二维数组:

np.zeros((3, 3))

6. 创建全为 1 的三维数组:

np.ones((2, 3, 4))

7. 创建一维等差数组:

np.arange(5)

8. 创建二维等差数组:

np.arange(6).reshape(2, 3)

9. 创建单位矩阵(二维数组):

np.eye(3)

10. 创建等间隔一维数组:

np.linspace(1, 10, num=6)

11. 创建二维随机数组:

np.random.rand(2, 3)

12. 创建二维随机整数数组(数值小于 5):

np.random.randint(5, size=(2, 3))

13. 依据自定义函数创建数组:

np.fromfunction(lambda i, j: i + j, (3, 3))

数组运算

生成一维示例数组:

a = np.array([10, 20, 30, 40, 50])

b = np.arange(1, 6)

a, b

14. 一维数组加法运算:

a + b

15. 一维数组减法运算:

a - b

16. 一维数组乘法运算:

a * b

17. 一维数组除法运算:

a / b

生成二维示例数组(可以看作矩阵):

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

B = np.array([[5, 6], [7, 8]])

A, B

18. 矩阵加法运算:

A + B

19. 矩阵减法运算:

A - B

20. 矩阵元素间乘法运算:

A * B

21. 矩阵乘法运算(注意与上题的区别):

np.dot(A, B)

如果使用 np.mat 将二维数组准确定义为矩阵,就可以直接使用 * 完成矩阵乘法计算。

np.mat(A) * np.mat(B)

22. 数乘矩阵:

2 * A

23. 矩阵的转置:

A.T

24. 矩阵求逆:

np.linalg.inv(A)

数学函数

25. 三角函数:

print(a)

np.sin(a)

26. 以自然对数函数为底数的指数函数:

np.exp(a)

27. 数组的方根的运算(开平方):

np.sqrt(a)

28. 数组的方根的运算(立方):

np.power(a, 3)

数组切片和索引

29. 一维数组索引:

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

a[0], a[-1]

30. 一维数组切片:

a[0:2], a[:-1]

31. 二维数组索引:

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

a[0], a[-1]

32. 二维数组切片(取第 2 列):

print(a)

a[:, 1]

33. 二维数组切片(取第 2,3 行):

a[1:3, :]

数组形状操作

生成二维示例数组:

a = np.random.random((3, 2))

a

34. 查看数组形状:

a.shape

35. 更改数组形状(不改变原始数组):

a.reshape(2, 3)  # reshape 并不改变原始数组

a

36. 更改数组形状(改变原始数组):

a.resize(2, 3)  # resize 会改变原始数组

a

37. 展平数组:

a.ravel()

38. 垂直拼合数组:

# 生成示例数组

a = np.random.randint(10, size=(3, 3))

b = np.random.randint(10, size=(3, 3))

a, b

np.vstack((a, b))

39. 水平拼合数组:

np.hstack((a, b))

40. 沿横轴分割数组:

np.hsplit(a, 3)

41. 沿纵轴分割数组:

np.vsplit(a, 3)

数组排序

# 生成示例数组

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

a

42. 返回每列最大值:

np.max(a, axis=0)

43. 返回每行最小值:

np.min(a, axis=1)

44. 返回每列最大值索引:

np.argmax(a, axis=0)

45. 返回每行最小值索引:

np.argmin(a, axis=1)

数组统计

46. 统计数组各列的中位数:

# 继续使用上面的 a 数组

np.median(a, axis=0)

47. 统计数组各行的算术平均值:

np.mean(a, axis=1)

48. 统计数组各列的加权平均值:

np.average(a, axis=0)

49. 统计数组各行的方差:

np.var(a, axis=1)

50. 统计数组各列的标准偏差:

np.std(a, axis=0)

进阶部分

51. 创建一个 5x5 的二维数组,其中边界值为1,其余值为0:

Z = np.ones((5, 5))

Z[1:-1, 1:-1] = 0

Z

52. 使用数字 0 将一个全为 1 的 5x5 二维数组包围:

Z = np.ones((5, 5))

Z = np.pad(Z, pad_width=1, mode='constant', constant_values=0)

Z

53. 创建一个 5x5 的二维数组,并设置值 1, 2, 3, 4 落在其对角线下方:

Z = np.diag(1+np.arange(4), k=-1)

Z

54. 创建一个 10x10 的二维数组,并使得 1 和 0 沿对角线间隔放置:

Z = np.zeros((10, 10), dtype=int)

Z[1::2, ::2] = 1

Z[::2, 1::2] = 1

Z

55. 创建一个 0-10 的一维数组,并将 (1, 9] 之间的数全部反转成负数:

Z = np.arange(11)

Z[(1 < Z) & (Z <= 9)] *= -1

Z

56. 找出两个一维数组中相同的元素:

Z1 = np.random.randint(0, 10, 10)

Z2 = np.random.randint(0, 10, 10)

print("Z1:", Z1)

print("Z2:", Z2)

np.intersect1d(Z1, Z2)

57. 使用 NumPy 打印昨天、今天、明天的日期:

yesterday = np.datetime64('today', 'D') - np.timedelta64(1, 'D')

today = np.datetime64('today', 'D')

tomorrow = np.datetime64('today', 'D') + np.timedelta64(1, 'D')

print("yesterday: ", yesterday)

print("today: ", today)

print("tomorrow: ", tomorrow)

58. 使用五种不同的方法去提取一个随机数组的整数部分:

Z = np.random.uniform(0, 10, 10)

print("原始值: ", Z)

print("方法 1: ", Z - Z % 1)

print("方法 2: ", np.floor(Z))

print("方法 3: ", np.ceil(Z)-1)

print("方法 4: ", Z.astype(int))

print("方法 5: ", np.trunc(Z))

59. 创建一个 5x5 的矩阵,其中每行的数值范围从 1 到 5:

Z = np.zeros((5, 5))

Z += np.arange(1, 6)

Z

60. 创建一个长度为 5 的等间隔一维数组,其值域范围从 0 到 1,但是不包括 0 和 1:

Z = np.linspace(0, 1, 6, endpoint=False)[1:]

Z

61. 创建一个长度为10的随机一维数组,并将其按升序排序:

Z = np.random.random(10)

Z.sort()

Z

62. 创建一个 3x3 的二维数组,并将列按升序排序:

Z = np.array([[7, 4, 3], [3, 1, 2], [4, 2, 6]])

print("原始数组: \n", Z)

Z.sort(axis=0)

Z

63. 创建一个长度为 5 的一维数组,并将其中最大值替换成 0:

Z = np.random.random(5)

print("原数组: ", Z)

Z[Z.argmax()] = 0

Z

64. 打印每个 NumPy 标量类型的最小值和最大值:

for dtype in [np.int8, np.int32, np.int64]:

    print("The minimum value of {}: ".format(dtype), np.iinfo(dtype).min)

    print("The maximum value of {}: ".format(dtype), np.iinfo(dtype).max)

for dtype in [np.float32, np.float64]:

    print("The minimum value of {}: ".format(dtype), np.finfo(dtype).min)

    print("The maximum value of {}: ".format(dtype), np.finfo(dtype).max)

65. 将 float32 转换为整型:

Z = np.arange(10, dtype=np.float32)

print(Z)

Z = Z.astype(np.int32, copy=False)

Z

66. 将随机二维数组按照第 3 列从上到下进行升序排列:

Z = np.random.randint(0, 10, (5, 5))

print("排序前:\n", Z)

Z[Z[:, 2].argsort()]

67. 从随机一维数组中找出距离给定数值(0.5)最近的数:

Z = np.random.uniform(0, 1, 20)

print("随机数组: \n", Z)

z = 0.5

m = Z.flat[np.abs(Z - z).argmin()]

m

68. 将二维数组的前两行进行顺序交换:

A = np.arange(25).reshape(5, 5)

print(A)

A[[0, 1]] = A[[1, 0]]

print(A)

69. 找出随机一维数组中出现频率最高的值:

Z = np.random.randint(0, 10, 50)

print("随机一维数组:", Z)

np.bincount(Z).argmax()

70. 找出给定一维数组中非 0 元素的位置索引:

Z = np.nonzero([1, 0, 2, 0, 1, 0, 4, 0])

Z

71. 对于给定的 5x5 二维数组,在其内部随机放置 p 个值为 1 的数:

p = 3

Z = np.zeros((5, 5))

np.put(Z, np.random.choice(range(5*5), p, replace=False), 1)

Z

72. 对于随机的 3x3 二维数组,减去数组每一行的平均值:

X = np.random.rand(3, 3)

print(X)

Y = X - X.mean(axis=1, keepdims=True)

Y

73. 获得二维数组点积结果的对角线数组:

A = np.random.uniform(0, 1, (3, 3))

B = np.random.uniform(0, 1, (3, 3))

print(np.dot(A, B))

# 较慢的方法

np.diag(np.dot(A, B))

np.sum(A * B.T, axis=1)  # 较快的方法

np.einsum("ij, ji->i", A, B)  # 更快的方法

74. 找到随机一维数组中前 p 个最大值:

Z = np.random.randint(1, 100, 100)

print(Z)

p = 5

Z[np.argsort(Z)[-p:]]

75. 计算随机一维数组中每个元素的 4 次方数值:

x = np.random.randint(2, 5, 5)

print(x)

np.power(x, 4)

76. 对于二维随机数组中各元素,保留其 2 位小数:

Z = np.random.random((5, 5))

print(Z)

np.set_printoptions(precision=2)

Z

77. 使用科学记数法输出 NumPy 数组:

Z = np.random.random([5, 5])

print(Z)

Z/1e3

78. 使用 NumPy 找出百分位数(25%,50%,75%):

a = np.arange(15)

print(a)

np.percentile(a, q=[25, 50, 75])

79. 找出数组中缺失值的总数及所在位置:

# 生成含缺失值的 2 维数组

Z = np.random.rand(10, 10)

Z[np.random.randint(10, size=5), np.random.randint(10, size=5)] = np.nan

Z

print("缺失值总数: \n", np.isnan(Z).sum())

print("缺失值索引: \n", np.where(np.isnan(Z)))

80. 从随机数组中删除包含缺失值的行:

# 沿用 79 题中的含缺失值的 2 维数组

Z[np.sum(np.isnan(Z), axis=1) == 0]

81. 统计随机数组中的各元素的数量:

Z = np.random.randint(0, 100, 25).reshape(5, 5)

print(Z)

np.unique(Z, return_counts=True)  # 返回值中,第 2 个数组对应第 1 个数组元素的数量

82. 将数组中各元素按指定分类转换为文本值:

# 指定类别如下

# 1 → 汽车

# 2 → 公交车

# 3 → 火车

Z = np.random.randint(1, 4, 10)

print(Z)

label_map = {1: "汽车", 2: "公交车", 3: "火车"}

[label_map[x] for x in Z]

83. 将多个 1 维数组拼合为单个 Ndarray:

Z1 = np.arange(3)

Z2 = np.arange(3, 7)

Z3 = np.arange(7, 10)

Z = np.array([Z1, Z2, Z3])

print(Z)

np.concatenate(Z)

84. 打印各元素在数组中升序排列的索引:

a = np.random.randint(100, size=10)

print('Array: ', a)

a.argsort()

85. 得到二维随机数组各行的最大值:

Z = np.random.randint(1, 100, [5, 5])

print(Z)

np.amax(Z, axis=1)

86. 得到二维随机数组各行的最小值(区别上面的方法):

Z = np.random.randint(1, 100, [5, 5])

print(Z)

np.apply_along_axis(np.min, arr=Z, axis=1)

87. 计算两个数组之间的欧氏距离:

a = np.array([1, 2])

b = np.array([7, 8])

# 数学计算方法

print(np.sqrt(np.power((8-2), 2) + np.power((7-1), 2)))

# NumPy 计算

np.linalg.norm(b-a)

88. 打印复数的实部和虚部:

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

print("实部:", a.real)

print("虚部:", a.imag)

89. 求解给出矩阵的逆矩阵并验证:

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

inverse_matrix = np.linalg.inv(matrix)

# 验证原矩阵和逆矩阵的点积是否为单位矩阵

assert np.allclose(np.dot(matrix, inverse_matrix), np.eye(2))

inverse_matrix

90. 使用 Z-Score 标准化算法对数据进行标准化处理:

Z-Score 标准化公式:

# 根据公式定义函数

def zscore(x, axis=None):

    xmean = x.mean(axis=axis, keepdims=True)

    xstd = np.std(x, axis=axis, keepdims=True)

    zscore = (x-xmean)/xstd

    return zscore

# 生成随机数据

Z = np.random.randint(10, size=(5, 5))

print(Z)

zscore(Z)

91. 使用 Min-Max 标准化算法对数据进行标准化处理:

Min-Max 标准化公式:

# 根据公式定义函数

def min_max(x, axis=None):

    min = x.min(axis=axis, keepdims=True)

    max = x.max(axis=axis, keepdims=True)

    result = (x-min)/(max-min)

    return result

# 生成随机数据

Z = np.random.randint(10, size=(5, 5))

print(Z)

min_max(Z)

92. 使用 L2 范数对数据进行标准化处理:

L2 范数计算公式:

# 根据公式定义函数

def l2_normalize(v, axis=-1, order=2):

    l2 = np.linalg.norm(v, ord=order, axis=axis, keepdims=True)

    l2[l2 == 0] = 1

    return v/l2

# 生成随机数据

Z = np.random.randint(10, size=(5, 5))

print(Z)

l2_normalize(Z)

93. 使用 NumPy 计算变量直接的相关性系数:

Z = np.array([

    [1, 2, 1, 9, 10, 3, 2, 6, 7],  # 特征 A

    [2, 1, 8, 3, 7, 5, 10, 7, 2],  # 特征 B

    [2, 1, 1, 8, 9, 4, 3, 5, 7]])  # 特征 C

np.corrcoef(Z)

相关性系数取值从 [-1, 1][−1,1] 变换,靠近 11 则代表正相关性较强,-1−1 则代表负相关性较强。结果如下所示,变量 A 与变量 A 直接的相关性系数为 1,因为是同一个变量。变量 A 与变量 C 之间的相关性系数为 0.97,说明相关性较强。

94. 使用 NumPy 计算矩阵的特征值和特征向量:

M = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

w, v = np.linalg.eig(M)

# w 对应特征值,v 对应特征向量

w, v

我们可以通过 P'AP=MP′

 AP=M 公式反算,验证是否能得到原矩阵。

v * np.diag(w) * np.linalg.inv(v)

95. 使用 NumPy 计算 Ndarray 两相邻元素差值:

Z = np.random.randint(1, 10, 10)

print(Z)

# 计算 Z 两相邻元素差值

print(np.diff(Z, n=1))

# 重复计算 2 次

print(np.diff(Z, n=2))

# 重复计算 3 次

print(np.diff(Z, n=3))

96. 使用 NumPy 将 Ndarray 相邻元素依次累加:

Z = np.random.randint(1, 10, 10)

print(Z)

"""

[第一个元素, 第一个元素 + 第二个元素, 第一个元素 + 第二个元素 + 第三个元素, ...]

"""

np.cumsum(Z)

97. 使用 NumPy 按列连接两个数组:

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

M2 = np.array([4, 5, 6])

np.c_[M1, M2]

98. 使用 NumPy 按行连接两个数组:

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

M2 = np.array([4, 5, 6])

np.r_[M1, M2]

99. 使用 NumPy 打印九九乘法表:

np.fromfunction(lambda i, j: (i + 1) * (j + 1), (9, 9))

100. 使用 NumPy 将实验楼 LOGO 转换为 Ndarray 数组:

from io import BytesIO

from PIL import Image

import PIL

import requests

# 通过链接下载图像

URL = 'https://static.shiyanlou.com/img/logo-black.png'

response = requests.get(URL)

# 将内容读取为图像

I = Image.open(BytesIO(response.content))

# 将图像转换为 Ndarray

shiyanlou = np.asarray(I)

shiyanlou

# 将转换后的 Ndarray 重新绘制成图像

from matplotlib import pyplot as plt

%matplotlib inline

plt.imshow(shiyanlou)


参考: https://www.lanqiao.cn/courses/1090/learning/?id=6137