NumPy-Exercises
第一部分:创建数组 (Array Creation)
1. 将 NumPy 库导入为 np
这是使用 NumPy 的标准约定。
import numpy as np
2. 创建一个包含10个0的数组
NumPy 提供了专门的函数来创建全0或全1的数组。
代码:
np.zeros(10)
解释:
np.zeros()
函数会创建一个指定形状、并用0填充的数组。参数 10
定义了这是一个包含10个元素的一维数组。请注意,默认的数据类型是浮点数 (0.
)。
3. 创建一个包含10个1的数组
这与创建全0数组非常类似。
代码:
np.ones(10)
解释:
np.ones()
函数会创建一个指定形状、并用1填充的数组。与 np.zeros()
类似,默认的数据类型也是浮点数 (1.
)。
4. 创建一个包含10个5的数组
NumPy 没有直接的 np.fives()
函数,但这可以通过简单的运算实现。
代码方法一:
np.ones(10) * 5
代码方法二(更直接):
np.full(10, 5)
解释:
- 方法一: 我们先创建一个包含10个1的数组
[1., 1., ..., 1.]
,然后利用 NumPy 的向量化操作,将数组中的每个元素都乘以5。 - 方法二:
np.full(shape, fill_value)
函数是更直接的方式,它可以创建一个指定shape
(形状) 并用fill_value
(填充值) 填充的数组。对于这个任务,此方法更佳。
5. 创建一个从10到50的整数数组
要创建连续的数字序列,NumPy 的 arange
函数是首选。
代码:
np.arange(10, 51)
解释:
np.arange(start, stop)
的功能类似于 Python 内置的 range()
函数,但它返回的是一个 NumPy 数组。start
参数是包含的,而 stop
参数是不包含的(也就是常说的“包头不包尾”)。因此,为了让数组包含 50
,stop
参数必须设置为 51
。
6. 创建一个从10到50的所有偶数整数数组
np.arange
还可以接受第三个参数 step
(步长)。
代码:
np.arange(10, 51, 2)
解释:
np.arange(start, stop, step)
会生成一个从 start
开始,每次递增 step
,并在到达 stop
之前结束的序列。这里我们指定步长为 2
,从而只获取偶数。
7. 创建一个3x3的矩阵,其值范围从0到8
这通常需要两步操作:先创建一维数组,然后将其重塑为二维矩阵。
代码:
np.arange(9).reshape(3, 3)
解释:
np.arange(9)
创建一个包含0到8整数的一维数组:[0, 1, 2, 3, 4, 5, 6, 7, 8]
。.reshape(rows, cols)
方法被调用,将这个一维数组的形状改变为一个3行3列的矩阵。数组的元素总数必须与新形状的容量相匹配(9个元素 = 3 * 3)。
8. 创建一个3x3的单位矩阵
单位矩阵是一个特殊的方阵,其主对角线上的值为1,其余位置为0。
代码:
np.eye(3)
解释:
np.eye(N)
函数用于创建一个 N x N 的单位矩阵。
9. 使用 NumPy 生成一个0到1之间的随机数
NumPy 拥有一个强大的 random
子模块用于生成随机数据。
代码:
np.random.rand(1)
解释:
np.random.rand()
会创建一个指定形状的数组,并用来自 [0, 1)
区间上均匀分布的随机样本填充它。参数 1
表示我们想要一个值(它会被返回在一个数组里)。
10. 使用 NumPy 生成一个由25个标准正态分布样本组成的数组
代码:
np.random.randn(25)
解释:
np.random.randn()
会创建一个指定形状的数组,并用来自标准正态分布(均值为0,方差为1)的样本填充。这与 rand()
(均匀分布)是不同的。
11. 创建指定的10x10矩阵
这需要结合 arange
、reshape
和向量化运算。
代码:
np.arange(1, 101).reshape(10, 10) / 100
解释:
np.arange(1, 101)
创建从1到100的整数。.reshape(10, 10)
将其变为10x10的矩阵。/ 100
是一个向量化操作,它会将矩阵中的每一个元素都除以100,从而得到最终结果。
12. 创建一个在0和1之间线性等分的20个点的数组
“线性等分”是这里的关键词,它指向一个特定的函数。
代码:
np.linspace(0, 1, 20)
解释:
np.linspace(start, stop, num)
会创建一个包含 num
个点的数组,这些点在 [start
, stop
] 区间内均匀分布。与 arange
不同,它的 stop
值默认是包含在内的。这个函数非常适合此类任务。
第二部分:NumPy 索引和选择 (Indexing and Selection)
首先,请确保你已经运行了定义 mat
变量的那个单元格,因为后面的所有问题都依赖于它。
# 运行此单元格 - 这是我们的起始矩阵
mat = np.arange(1,26).reshape(5,5)
13. 重现输出 [[12, 13, 14, 15], [17, 18, 19, 20], [22, 23, 24, 25]]
代码:
mat[2:, 1:]
解释:
NumPy 的二维数组索引格式为 mat[rows, columns]
。切片 (start:stop
) 可用于两个维度。
2:
用于行,表示“从索引2开始选择到末尾的所有行”。(这会得到[11, ...]
、[16, ...]
和[21, ...]
这三行)。1:
用于列,表示“从索引1开始选择到末尾的所有列”。 这两个切片的交集就是我们想要的子矩阵。
14. 重现输出 20
代码:
mat[3, 4]
解释:
要选择单个元素,只需提供其精确的坐标 mat[row_index, column_index]
。元素 20
位于第3行(索引从0开始)和第4列。
15. 重现输出 [[2], [7], [12]]
代码:
mat[:3, 1:2]
解释: 这展示了索引和切片之间的一个关键区别。
- 如果使用
mat[:3, 1]
,虽然会选中正确的数字,但它会返回一个一维数组[2, 7, 12]
。 - 为了保持二维的列向量形状,我们必须对列进行切片。
1:2
选择了索引为1的列,并保持结果为二维数组的格式。
16. 重现输出 [21, 22, 23, 24, 25]
代码:
mat[4]
或者:
mat[-1]
解释:
要选择一整行,你只需提供该行的索引。同时也支持负数索引(-1
代表最后一个元素),这通常很方便。
17. 重现输出 [[16, 17, 18, 19, 20], [21, 22, 23, 24, 25]]
代码:
mat[3:]
解释:
这是一个简单的行切片操作。3:
表示选择从索引3开始到矩阵末尾的所有行。
第三部分:NumPy 运算 (Operations)
18. 获取 mat
矩阵中所有值的总和
代码:
mat.sum()
或者:
np.sum(mat)
解释:
可以直接在 NumPy 数组上调用 .sum()
方法来计算其所有元素的和。
19. 获取 mat
矩阵中所有值的标准差
代码:
mat.std()
解释:
与 .sum()
类似,.std()
方法用于计算数组中所有元素的标准差。
20. 获取 mat
矩阵中所有列的总和
代码:
mat.sum(axis=0)
解释:
像 sum
这样的运算可以沿着指定的轴 (axis) 进行。
axis=0
表示沿着“第0个轴”(即行的方向)进行计算,实际上是把每一列的元素加起来。axis=1
表示沿着“第1个轴”(即列的方向)进行计算,实际上是把每一行的元素加起来。 因此,要得到每一列的和,我们使用axis=0
。
附加题 (Bonus Question)
问题: 有没有办法确保我们每次都能得到相同的随机数?
答案: 有,通过设置随机种子 (random seed)。
代码示例:
# 设置一个种子
np.random.seed(101)
# 生成一些随机数
print(np.random.rand(4))
# 再生成一些
print(np.random.rand(4))
# 重新将种子设为相同的值
np.random.seed(101)
# 你会发现,第一组随机数被重新生成了一遍
print(np.random.rand(4))
解释:
计算机中的随机数生成器实际上是伪随机的;它们是根据一个初始值(即种子)通过特定算法计算出的数字序列。这个序列看起来是随机的,但只要种子相同,生成的序列就完全相同。通过在生成随机数之前调用 np.random.seed()
设置一个固定的种子,你可以保证每次运行代码时都会得到完全一样的“随机”数序列。这对于需要复现实验结果的科学研究,以及调试含有随机性的代码至关重要。