NumPy数组属性
首先让我们讨论一些有用的数组属性。我们将从定义三个随机数组开始,分别是一维,二维和三维数组。我们将使用NumPy的随机数生成器,我们将使seed设置初始值,以确保每次运行此代码时都生成相同的随机数组:
In [8]: import numpy as np
...: np.random.seed(0) # seed for reproducibility
...:
...: x1 = np.random.randint(10, size=6) #一维数组
...: x2 = np.random.randint(10, size=(3, 4)) # 3*4的二维数组
...: x3 = np.random.randint(10, size=(3, 4, 5)) # 3*4*5的三维数组
每个数组都有属性ndim(维数),形状(每个维的大小)和大小(数组的总大小):
查看x3的相关信息
In [2]: print("x3 ndim: ", x3.ndim)
...: print("x3 shape:", x3.shape)
...: print("x3 size: ", x3.size)
x3 ndim: 3
x3 shape: (3, 4, 5)
x3 size: 60
In [3]: x3
Out[3]:
array([[[8, 1, 5, 9, 8],
[9, 4, 3, 0, 3],
[5, 0, 2, 3, 8],
[1, 3, 3, 3, 7]],
[[0, 1, 9, 9, 0],
[4, 7, 3, 2, 7],
[2, 0, 0, 4, 5],
[5, 6, 8, 4, 1]],
[[4, 9, 8, 1, 1],
[7, 9, 9, 3, 6],
[7, 2, 0, 3, 5],
[9, 4, 4, 6, 4]]])
# 取出第一维的下标1种二维下标1三维下表为0的数
In [4]: print(x3[1][1][0])
4
# 类型
In [5]: print("dtype:",x3[1][1][0].dtype)
dtype: int32
可以查看数组单个元素的字节和总字节数
In [7]: print("itemsize:", x3.itemsize, "bytes")
...: print("nbytes:", x3.nbytes, "bytes")
# int32的为4字节
itemsize: 4 bytes
#总共3*4*5=60个元素 60*4 个字节
nbytes: 240 bytes
2. 数组索引:访问单个元素
In [8]: x1
Out[8]: array([5, 0, 3, 3, 7, 9])
In [9]: x1[0]
Out[9]: 5
In [10]: x2
Out[10]:
array([[3, 5, 2, 4],
[7, 6, 8, 8],
[1, 6, 7, 7]])
In [11]: x2[0][1]
Out[11]: 5
从数组末端访问用负号,-1从最后开始依次往前,可自己尝试
In [13]: x1
Out[13]: array([5, 0, 3, 3, 7, 9])
In [14]: x1[-1]
Out[14]: 9
In [15]: x3
Out[15]:
array([[[8, 1, 5, 9, 8],
[9, 4, 3, 0, 3],
[5, 0, 2, 3, 8],
[1, 3, 3, 3, 7]],
[[0, 1, 9, 9, 0],
[4, 7, 3, 2, 7],
[2, 0, 0, 4, 5],
[5, 6, 8, 4, 1]],
[[4, 9, 8, 1, 1],
[7, 9, 9, 3, 6],
[7, 2, 0, 3, 5],
[9, 4, 4, 6, 4]]])
In [16]: x3[-2][-1][0]
Out[16]: 5
数组切片,访问子数组
正如我们可以使用方括号来访问单个数组元素一样,我们也可以使用方括号来访问带有切片符号(由冒号(:)字符标记)的子数组。 NumPy切片语法遵循标准Python列表的语法;要访问数组x的切片,请使用以下命令:
x[start:stop:step]
In [20]: x = np.arange(10)
...: x
Out[20]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
#前三个
In [21]: x[:3]
Out[21]: array([0, 1, 2])
#从下标2截取
In [22]: x[2:]
Out[22]: array([2, 3, 4, 5, 6, 7, 8, 9])
In [23]: x[1:3]
Out[23]: array([1, 2])
# 从索引1开始步长为2截取
In [24]: x[1::2]
Out[24]: array([1, 3, 5, 7, 9])
# 如果步长为负,则反向截取
In [27]: x[::-2]
Out[27]: array([9, 7, 5, 3, 1])
多维子数组
In [33]: x2[1,1]
Out[33]: 6
# 截取一维前两个元素后,对应的二维截取前三个元素
In [34]: x2[:2,:3]
Out[34]:
array([[3, 5, 2],
[7, 6, 8]])
# 截取一维前两个元素后,对应的二维截取步长为2截取
In [35]: x2[:2,::2]
Out[35]:
array([[3, 2],
[7, 8]])
#利用负的步长可以将二维数组完全反转
In [37]: x2[::-1, ::-1]
Out[37]:
array([[7, 7, 6, 1],
[8, 8, 6, 7],
[4, 2, 5, 3]])
访问数组的行和列
数组的冒号:可以访问当前维度的所有
Out[40]:
array([[3, 5, 2, 4],
[7, 6, 8, 8],
[1, 6, 7, 7]])
# 访问索引0的列
In [41]: x2[:,0]
Out[41]: array([3, 7, 1])
# 访问列
In [45]: x2[1]
Out[45]: array([7, 6, 8, 8])
数组视图
numpy数组切片的一个重要且极其有用的事情是,它们返回视图而不是数组数据的副本。这是NumPy数组切片与Python列表切片不同的一个领域:在Python 列表中,切片将是副本。之前的二维数组:
In [46]: x2
Out[46]:
array([[3, 5, 2, 4],
[7, 6, 8, 8],
[1, 6, 7, 7]])
In [47]: x2_sub=x2[:2,:2]
In [48]: x2_sub
Out[48]:
array([[3, 5],
[7, 6]])
In [49]: x2_sub[0,0]=233
In [50]: x2
Out[50]:
array([[233, 5, 2, 4],
[ 7, 6, 8, 8],
[ 1, 6, 7, 7]])
上面我们看到修改子数组x2_sub后,x2的元素也被修改了
这种默认行为实际上非常有用:这意味着当我们使用大型数据集时,我们可以访问和处理这些数据集的片段,而无需复制基础数据缓冲区。
创建数组副本
尽管数组视图具有出色的功能,但有时在数组或子数组中显式复制数据有时还是很有用的。使用copy()方法可以很容易地做到这一点:
In [51]: x2
Out[51]:
array([[233, 5, 2, 4],
[ 7, 6, 8, 8],
[ 1, 6, 7, 7]])
In [52]: x2_copy=x2[:2,:2].copy()
In [53]: x2_copy
Out[53]:
array([[233, 5],
[ 7, 6]])
In [54]: x2_copy[0,0]=888
In [55]: x2_copy
Out[55]:
array([[888, 5],
[ 7, 6]])
In [56]: x2
Out[56]:
array([[233, 5, 2, 4],
[ 7, 6, 8, 8],
[ 1, 6, 7, 7]])
可以看到修改copy后的数组,x2不会改变
重塑数组
另一种有用的操作类型是数组的重塑。最灵活的方法是使用整形方法。例如,如果要将数字1到9放在3×3的网格中,则可以执行以下操作:
In [57]: grid = np.arange(1, 10).reshape((3, 3))
...: print(grid)
[[1 2 3]
[4 5 6]
[7 8 9]]
请注意,要使此方法起作用,初始数组的大小必须与调整后的数组的大小匹配。在可能的情况下,reshape将使用初始数组的无副本视图,但是对于非连续的内存缓冲区,情况并非总是如此。
另一种常见的重塑模式是将一维数组转换为二维行或列矩阵。可以使用reshape方法完成此操作,也可以通过在slice操作中使用newaxis关键字更轻松地完成此操作:
In [64]: x
Out[64]: array([1, 2, 3])
# 形成 1*3的二维数组
In [65]: x.reshape(1,3)
Out[65]: array([[1, 2, 3]])
# 使用newaxis方式,后面:截取所有
In [66]: x[np.newaxis,:]
Out[66]: array([[1, 2, 3]])
# 形成 3*1的二维数组
In [67]: x.reshape(3,1)
Out[67]:
array([[1],
[2],
[3]])
In [68]: x[:,np.newaxis]
Out[68]:
array([[1],
[2],
[3]])
In [69]: x
Out[69]: array([1, 2, 3])
# 也可以这样处理三维
In [73]: x.reshape(3,1,1)
Out[73]:
array([[[1]],
[[2]],
[[3]]])
#或者
In [74]: x[:,np.newaxis,np.newaxis]
Out[74]:
array([[[1]],
[[2]],
[[3]]])
数组串联与分割
前面所有例子均在单个数组上运行。也可以将多个数组合并为一个,然后将单个数组拆分为多个数组。我们将在这里查看这些操作。
- 数组的串联
In [81]: x = np.array([1, 2, 3])
...: y = np.array([3, 2, 1])
...: np.concatenate([x, y])
Out[81]: array([1, 2, 3, 3, 2, 1])
# 也可以使用二维数组上
In [83]: grid=np.array([[1,2,3],[4,6,0]])
In [84]: np.concatenate([grid,grid])
Out[84]:
array([[1, 2, 3],
[4, 6, 0],
[1, 2, 3],
[4, 6, 0]])
In [101]: # concatenate along the second axis (zero-indexed)
...: np.concatenate([grid, grid], axis=1)
Out[101]:
array([[1, 2, 3, 1, 2, 3],
[4, 6, 0, 4, 6, 0]])
对于使用混合维度的数组,使用np.vstack(垂直堆栈)和np.hstack(水平堆栈)函数会更加清楚:
In [102]: x = np.array([1, 2, 3])
...: grid = np.array([[9, 8, 7],
...: [6, 5, 4]])
...: # 垂直锥线
...: np.vstack([x, grid])
Out[102]:
array([[1, 2, 3],
[9, 8, 7],
[6, 5, 4]])
In [103]: #水平锥线
...: y = np.array([[66],
...: [88]])
...: np.hstack([grid, y])
Out[103]:
array([[ 9, 8, 7, 66],
[ 6, 5, 4, 88]])
数组分割
与 串联的相反是分割,它是通过np.split,np.hsplit和np.vsplit实现。对于每一个数组,我们都可以传递给出分割点的索引表:
In [111]: x = [1, 2, 3, 99, 99, 3, 2, 1]
...: x1,x2,x3=np.split(x,[1,2])
...: print(x1,x2,x3)
[1] [2] [ 3 99 99 3 2 1]
- 注意,N个分裂点会产生N + 1个子数组。相关功能np.hsplit和np.vsplit相似:
In [114]: grid = np.arange(16).reshape((4, 4))
...: grid
Out[114]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
# 上下分割,从第二行
In [115]: upper, lower = np.vsplit(grid, [2])
...: print(upper)
...: print(lower)
[[0 1 2 3]
[4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]
# 从第二列分割
In [122]: left, right = np.hsplit(grid, [2])
...: print(left)
...: print(right)
[[ 0 1]
[ 4 5]
[ 8 9]
[12 13]]
[[ 2 3]
[ 6 7]
[10 11]
[14 15]]
np.dsplit和前面类似处理三维数组
In [127]: x = np.arange(16.0).reshape(2, 2, 4)
...: print(x)
...: np.dsplit(x, 2)
[[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]]
[[ 8. 9. 10. 11.]
[12. 13. 14. 15.]]]
Out[127]:
[array([[[ 0., 1.],
[ 4., 5.]],
[[ 8., 9.],
[12., 13.]]]),
array([[[ 2., 3.],
[ 6., 7.]],
[[10., 11.],
[14., 15.]]])]
网友评论