为什么学Numpy数组?¶
在Python数据分析和科学计算中,Numpy是基础中的基础。它提供了高效的多维数组对象,能让我们像处理简单数据一样操作复杂的数值集合,而且运算速度比纯Python列表快得多。要深入理解Numpy,必须掌握数组的结构(shape)、如何访问元素(索引)和如何截取子数组(切片),这也是本文的核心内容。
一、数组的创建:从基础开始¶
要操作数组,首先得创建它。Numpy提供了多种创建数组的方法,初学者可以从这几个最常用的开始:
1. np.array():从Python列表创建¶
import numpy as np
# 1维数组(向量)
arr1 = np.array([1, 2, 3, 4, 5])
print("1维数组:", arr1)
# 2维数组(矩阵)
arr2 = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print("2维数组:\n", arr2)
2. 快速创建全0/全1数组¶
# 3行4列的全0数组
zeros = np.zeros((3, 4)) # shape=(3,4)
print("全0数组:\n", zeros)
# 2行5列的全1数组
ones = np.ones((2, 5))
print("全1数组:\n", ones)
3. np.arange():类似Python的range¶
# 从0到9,步长为2(生成数组[0,2,4,6,8])
arange_arr = np.arange(0, 10, 2)
print("arange数组:", arange_arr)
二、shape:数组的“维度身份证”¶
shape是Numpy数组的核心属性,它告诉我们数组的维度信息(比如“几行几列”)。理解shape是处理数组的第一步。
1. 查看shape¶
用 .shape 属性查看数组的形状:
print("arr1的shape:", arr1.shape) # 输出 (5,) → 1维数组,长度5
print("arr2的shape:", arr2.shape) # 输出 (3, 3) → 3行3列的矩阵
2. 修改shape:reshape()¶
reshape() 可以调整数组的维度,但总元素数必须不变。例如:
# 将1维数组转为2行3列(原长度5?不行!必须保证总元素数不变)
# 修正:arange_arr是5个元素,reshape(2,3)会报错。换个例子:
arr3 = np.arange(6) # [0,1,2,3,4,5],shape=(6,)
arr3_reshaped = arr3.reshape(2, 3) # 转为2行3列
print("reshape后的数组:\n", arr3_reshaped)
print("新shape:", arr3_reshaped.shape) # (2, 3)
关键点:¶
reshape()只是调整维度,不会改变数据顺序(C-style行优先)。- 如果想转成1行多列,可以用
reshape(1, -1)(-1表示自动计算列数)。
三、索引:访问数组元素¶
索引就像“钥匙”,让我们能精准找到数组中的某个元素。Numpy数组的索引规则和Python列表类似,但支持更简洁的多维度索引。
1. 1维数组索引¶
和Python列表一样,1维数组的索引从0开始,支持正负索引(负索引表示“倒数第几个”):
print("arr1[0] =", arr1[0]) # 第一个元素:1
print("arr1[-1] =", arr1[-1]) # 最后一个元素:5
print("arr1[2] =", arr1[2]) # 第三个元素:3
2. 2维数组索引¶
2维数组需要两个索引(行索引,列索引),用逗号分隔:
# arr2 = [[1,2,3], [4,5,6], [7,8,9]]
print("arr2[1, 2] =", arr2[1, 2]) # 第2行(索引1)第3列(索引2)→ 6
print("arr2[0, 0] =", arr2[0, 0]) # 第1行第1列 → 1
print("arr2[-1, -1] =", arr2[-1, -1]) # 最后一行最后一列 → 9
注意:¶
- 不要写成
arr2[1][2](虽然Python列表嵌套也支持,但Numpy数组更推荐arr[i,j],效率更高)。
四、切片:截取子数组¶
切片允许我们批量提取元素,形成一个“子数组”。语法是 [start:end:step],其中 start 是起始位置,end 是结束位置(不包含),step 是步长。
1. 1维数组切片¶
# arr1 = [1,2,3,4,5]
print("arr1[1:4] =", arr1[1:4]) # 从索引1到4(不含4)→ [2,3,4]
print("arr1[::2] =", arr1[::2]) # 步长2 → [1,3,5]
print("arr1[:3] =", arr1[:3]) # 省略start → 前3个元素 → [1,2,3]
print("arr1[::] =", arr1[::]) # 省略step和start/end → 整个数组
2. 2维数组切片¶
2维数组切片需要分别指定行切片和列切片,用逗号分隔:
# arr2 = [[1,2,3], [4,5,6], [7,8,9]]
print("arr2[1:3, 0:2] = \n", arr2[1:3, 0:2])
# 解释:取第1-3行(不含3),第0-2列(不含2) → [[4,5], [7,8]]
print("arr2[:, 1] =", arr2[:, 1]) # 所有行,第1列 → [2,5,8]
print("arr2[0:2, :] = \n", arr2[0:2, :]) # 前2行,所有列 → [[1,2,3], [4,5,6]]
3. 切片的“视图”特性¶
Numpy切片默认返回的是原数组的“视图”(共享数据内存),修改子数组会影响原数组:
sub_arr = arr2[1:3, 0:2] # 子数组
sub_arr[0, 0] = 100 # 修改子数组
print("修改后原数组:\n", arr2) # 原数组的[1,0]位置也被修改为100
如何避免修改原数组?¶
用 .copy() 方法创建独立的拷贝:
sub_arr = arr2[1:3, 0:2].copy() # 拷贝子数组
sub_arr[0, 0] = 200 # 修改拷贝,原数组不变
print("原数组未被修改:\n", arr2)
五、总结与练习建议¶
- shape:理解数组的维度,用
reshape()调整维度。 - 索引:1维数组类似列表,2维数组需行+列双索引,支持正负索引。
- 切片:通过
[start:end:step]截取子数组,注意视图与拷贝的区别。
练习:尝试用Numpy创建一个5x5的随机数组,然后:
1. 查看它的shape;
2. 用索引访问第3行第4列的元素;
3. 用切片截取前3行前3列的子数组;
4. 对切片后的子数组修改,观察原数组是否变化。
通过动手实践,你会更快掌握Numpy数组的核心操作!