目录
- 一、numpy简介
- 二、创建数组
- (一)从现有的数据创建
- (二)从形状或值创建
- 1、np.empty(shape, dtype=np.float64)
- 2、np.empty_like(prototype, dtype=None)
- 3、np.zeros(shape, dtype=np.float64)
- 4、np.zeros_like(a, dtype=None)
- 5、np.ones(shape, dtype=np.float64)
- 6、np.ones(shape, dtype=np.float64)
- 7、np.full(shape, fill_value, dtype=None)
- 8、np.full_like(a, fill_value, dtype=None)
- 9、np.eye(N, M=None, k=0, dtype=np.float64)
- 10、np.eye(N, M=None, k=0, dtype=np.float64)
- (三)从数值范围创建数组
- 三、广播机制
- 四、索引和切片
一、numpy简介
NumPy(Numerical Python)是 Python 进行科学计算的一个扩展库,提供了
大量的函数和操作,主要用于对多维数组执行计算,它比 Python 自身的嵌套
列表结构要高效的多
二、创建数组
(一)从现有的数据创建
1、np.array(object, dtype=None)
- object:array_like,类似于数组的对象。如果object是标量,则返回包含object的0维数组
- data-type,数组所需的数据类型。如果没有给出,会从输入数据推断数据类型
- 创建一个数组对象并返回(ndarray实例对象)
DTYPE常用值
DTYPE常用值 | 描述 |
---|---|
np.int8 | 字节(-128 to 127) |
np.int16 | 整数(-32768 to 32767) |
np.int32 | 整数(-2147483648 to 2147483647) |
np.int64 | 整数(-9223372036854775808 to 9223372036854775807) |
np.uint8 | 无符号整数(0 to 255) |
np.uint16 | 无符号整数(0 to 65535) |
np.uint32 | 无符号整数(0 to 4294967295) |
np.uint64 | 无符号整数(0 to 18446744073709551615) |
np.float16 | 半精度浮点数 |
np.float32 | 单精度浮点数 |
np.float64 | 双精度浮点数 |
NDARRAY常用属性
NDARRAY常用属性 | 描述 |
---|---|
ndarray.ndim | 即轴的数量或维度的数量 |
ndarray.shape | 数组的形状 |
ndarray.size | 数组元素的总个数 (shape相应元组相乘) |
ndarray.dtype | ndarray 对象的元素类型 |
ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |
ndarray.shape 数组的形状 (一维数组的shape (m,n) 如 (3,) 表示这是一维数组,3表示一维数组有3个元素; (2,3)表示是二维数组,2表示二维数组有2行(第一个维度有2个元素),3表示每行有3个元素(表示一行有3个元素) )
# 创建数组
arr = np.array([[1, 2, 3], [4, 5, 9]])
print(arr)
#[[1 2 3]
# [4 5 9]]
#打印数组维度
print(arr.ndim)
# 2
#数组形状
print(arr.shape)
#(2, 3)
#数组元素总个数
print(arr.size)
# 6
#对象的元素类型
print(arr.dtype)
#int32
#ndarray 对象中每个元素的大小
print(arr.itemsize)
# 4
np.array()函数接受一个可迭代对象作为输入,并将其转换成一个numpy数组。
arr1 = np.array((1, 2, 3))
print(arr1)
# [1 2 3]
arr2 = np.array(range(1, 5))
print(arr2)
# [1 2 3 4]
2、np.asarray(a, dtype=None)
类似于 np.array,主要区别是当 a是 ndarray 且 dtype 也匹配时,
np.asarray不执行复制操作,而 np.array 仍然会复制出一个副本,占
用新的内存
obj = [1, 2, 3] # a是array_like
# obj = np.array([1, 2, 3]) # a是ndarray
arr1 = np.array(obj)
arr2 = np.asarray(obj)
obj[1] = 4
print(obj)
# [1, 4, 3]
print(arr1)
# [1 2 3]
print(arr2)
# [1 2 3]
3、np.copy(a)
- a: array_like,类似于数组的对象。
- 返回给定对象的数组副本
a1 = [1, 2, 3]
arr1 = np.copy(a1)
a1[1] = 5
print(arr1)
# [1 2 3]
4、ndarray.copy()
对象方法,返回数组的副本
arr = np.array([1, 2, 3])
print(arr.copy())
# [1 2 3]
5、np.fromiter(iterable, dtype, count=-1)
- iterable:可迭代对象
- dtype:返回数组的数据类型
- count:读取的数据数量,默认为-1,表示读取所有数据
- 从可迭代对象创建一个新的一维数组并返回
iterable = (x * x for x in range(5))
print(np.fromiter(iterable, dtype=int, count=-1))
# [ 0 1 4 9 16]
(二)从形状或值创建
1、np.empty(shape, dtype=np.float64)
- 返回给定形状和类型且未初始化的新数组
print(np.empty((2, 3), dtype=np.int16))
# [[77 75 76]
# [95 86 69]]
2、np.empty_like(prototype, dtype=None)
- prototype:array_like,类似于数组的对象
- dtype:如果指定该参数,将会覆盖结果的数据类型
- 返回形状和类型与给定 prototype 相同的新数组
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)
print(np.empty_like(a))
# [[-1 -1 2]
# [ 0 0 0]]
3、np.zeros(shape, dtype=np.float64)
- 返回给定形状和类型的新数组,并用零填充
print(np.zeros((2, 3), dtype=np.int16))
#[[0 0 0]
# [0 0 0]]
4、np.zeros_like(a, dtype=None)
- a:array_like
- dtype:如果指定该参数,将会覆盖结果的数据类型
- 返回一个与给定 a 具有相同形状和类型的零数组。
arr = ([1, 2, 3], [4, 5, 6])
print(np.zeros_like(arr))
# [[0 0 0]
# [0 0 0]]
5、np.ones(shape, dtype=np.float64)
- 返回给定形状和类型的新数组,并用1填充
print(np.ones((2, 3), dtype=np.int16))
# [[1 1 1]
# [1 1 1]]
6、np.ones(shape, dtype=np.float64)
- a:array_like
- dtype:如果指定该参数,将会覆盖结果的数据类型
- 返回一个与给定 a 具有相同形状和类型的1构成的数组。
a = ([1, 2, 3], [4, 5, 6])
print(np.ones_like(a))
# [[1 1 1]
# [1 1 1]]
7、np.full(shape, fill_value, dtype=None)
- 返回给定形状和类型的新数组,并用 fill_value 填充
print(np.full((2, 3), 9, dtype=np.int8))
#[[9 9 9]
# [9 9 9]]
8、np.full_like(a, fill_value, dtype=None)
- a:array_like
- dtype:如果指定该参数,将会覆盖结果的数据类型
- 返回一个与给定 a 具有相同形状和类型的 fill_value 填充的数组
a = ([1, 2, 3], [4, 5, 6])
print(np.full_like(a, 6))
#[[6 6 6]
# [6 6 6]]
9、np.eye(N, M=None, k=0, dtype=np.float64)
- N:输出数组的行数
- M:输出数组的列数。如果为None,则默认为N
- k:对角线的索引,默认为0,表示主对角线,正值表示上对角线,负值表示下对角线
- dtype:数组的数据类型
print(np.eye(3, 4, 0, dtype=np.int8))
# [[1 0 0 0]
# [0 1 0 0]
# [0 0 1 0]]
10、np.eye(N, M=None, k=0, dtype=np.float64)
- 返回 n*n 的单位数组(主对角线为1,其他元素为0的方形数组)
- 对角线为1,其他地方为0(单位矩阵)
print(np.identity(3, dtype=np.int8))
# [[1 0 0]
# [0 1 0]
# [0 0 1]]
(三)从数值范围创建数组
1、np.arange([start,] stop[, step,], dtype=None)
- 返回一个包含从 start 到 stop(不包括)的等差数列的数组
- start:开始值,默认为0
- stop:结束值
- step:步长,默认为1
- dtype:数组的数据类型
print(np.arange(1, 10, 2, dtype=np.int8))
# [1 3 5 7 9]
2、np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
- num:生成的样本数量
- endpoint:如果为 True, stop 为最后一个样本。否则,不包括在内
- retstep:如果为 True,返回 (samples, step), step 是样本之间的间隔
- dtype:如果没有给出dtype,则从 start 和 stop 推断数据类型。推断出的 dtype 永远不会是整数;即使参数会产生一个整数数组,也会选择 np.float64
- 把给定区间分成 num 个均匀间隔的样本,构成数组并返回(等差数列)
print(np.linspace(1, 10, num=4, endpoint=False, retstep=True, dtype=np.float32))
# (array([1. , 3.25, 5.5 , 7.75], dtype=float32), 2.25)
3、np.logspace(start, stop, num=50, endpoint=True, base=10.0,dtype=None)
- start:序列的起始值为:base ** start
- stop:序列的终止值为:base ** stop
- num:生成的样本数量
- endpoint:如果为 True, stop 为最后一个样本。否则,不包括在内
- 对数 log 的底数
- dtype:如果没有给出dtype,则从 start 和 stop 推断数据类型。推断出的 dtype 永远不会是整数;即使参数会产生一个整数数组,也会选择 np.float64
- 把给定区间分成 num 个按对数尺度均匀间隔的样本,构成数组并返回(等比数列)
print(np.logspace(2, 3, num=4, endpoint=False, base=10, dtype=np.int32))
# [100 177 316 562]
三、广播机制
NumPy的广播(broadcasting)机制是NumPy库中的一种强大的功能,它允许NumPy在执行数组运算时自动扩展数组的维度,从而可以在不同形状的数组之间进行数学运算。这种机制极大地简化了数组之间的运算,并提高了运算的效率。
广播的基本规则如下:
- 如果两个数组的维度数不同,那么在维度较小的数组形状左侧补1,直到两个数组的形状长度相同。例如,形状为(3,)的数组和形状为(2,3)的数组进行广播时,前者会被视为(1,3)的形状。
- 从最后一个维度(即最右边的维度)开始比较两个数组的形状,对应维度上的值必须相等,或者其中一个值为1。如果满足这个条件,那么就可以进行广播。否则,无法进行广播。
- 广播会在所有长度为1的维度上进行,生成的新数组形状是原数组形状在非1维度上的最大值。
广播的前提:
- 后缘维度相同或者不同的维度有1,可以广播
a = np.arange(24).reshape((2, 3, 4))
b = np.arange(12).reshape((3, 4))
c = np.arange(4).reshape((1, 4))
d = np.arange(4).reshape(4)
e = np.arange(12).reshape((1, 3, 4))
f = np.arange(6).reshape((2, 3, 1))
g = np.arange(2).reshape((2, 1, 1))
h = np.arange(2).reshape((1, 2, 1, 1))
i = np.arange(10).reshape((5, 2, 1, 1))
a与b、c、d、e的后缘维度相同
print((a + b).shape)
print((a + c).shape)
print((a + d).shape)
print((a + e).shape)
# (2, 3, 4)
# (2, 3, 4)
# (2, 3, 4)
# (2, 3, 4)
a与f、g、h、i的后缘维度不同,但其维度是1
print((a + f).shape)
print((a + g).shape)
print((a + h).shape)
print((a + i).shape)
# (2, 3, 4)
# (2, 3, 4)
# (1, 2, 3, 4)
# (5, 2, 3, 4)
四、索引和切片
数组的索引和切片与 Python 中序列的索引和切片区别:
数组的索引和切片与 Python 中序列的索引和切片操作基本类似,不同点在于:
①数组切片不会复制内部数组数据,只会生成原始数据的新视图
②数组支持多维数组的多维索引和切片
需要注意的是,切片返回的是原始数组的一个视图(view),这意味着返回的数组与原始数组共享相同的数据内存块。对切片所做的任何修改都会反映到原始数组中(除非进行了数据复制,比如通过修改数组形状或数据类型。
切片语法:
基本语法是使用冒号(:)来指定开始索引、结束索引和步长
array[start:stop:step]
- start:开始索引(包含),默认为0。
- stop:结束索引(不包含),默认为数组长度。
- step:步长,即选择元素时的间隔,默认为1。
注意:索引是前闭后开的区间 ‘[ )’
1. 一维数组索引和切片
索引:
array = np.arange(2, 10)
print(array) # [2 3 4 5 6 7 8 9]
item = array[1]
print(item) # 3
切片:
part = array[-2:1:-1]
print(part) # [8 7 6 5 4]
array[1] = 33
array[3:] = [55, 66, 77, 88, 99]
print(item) # 3
print(part) # [88 77 66 55 4]
2. 多维数组切片
索引:
lis = [[1, 2], [3, 4], [5, 6]]
arr = np.array(lis)
print(arr)
# [[1 2]
# [3 4]
# [5 6]]
print(arr[1, 0])
# 3
使用基本索引,arr[1, 0]表示选择第2行(索引为1,因为索引是从0开始的)和第1列(索引为0)的元素。输出是3。
print(arr[1][0])
# 3
这行代码与上一行在功能上是等效的,但使用了不同的索引方式。arr[1]首先选择了第2行,得到一个一维数组[3, 4],然后[0]从这个一维数组中选择了第1个元素,即3
切片:
print(arr[:2, 1:2])
# [[2]
# [4]]
这里使用了切片。arr[:2]选择了前两行,形成一个形状为(2, 2)的子数组:
[[1 2]
[3 4]]
然后,1:2选择了这些行的第2列(Python中的切片是左闭右开的),但是因为你使用的是1:2(起始索引是1,结束索引是2,不包括2),所以实际上只会选择索引为1的列,即第2列。
但是,由于你选择的范围只包含一个元素(从索引1到索引2,但不包括2),所以结果是一个形状为(2, 1)的数组:
print(arr[:2][1:2])
# [[3 4]]
这行代码首先使用arr[:2]选择了前两行,得到一个形状为(2, 2)的子数组。然后,[1:2]对这个子数组进行切片,选择了第2行(在子数组中,不是原始数组中的第2行,而是第1行,因为子数组已经只有两行)。
所以结果是一个形状为(1, 2)的数组,只包含原数组的第二行:[[3 4]]
总结:
- arr[1, 0]和arr[1][0]都选择了原数组的第二行第一列的元素。
- arr[:2, 1:2]选择了原数组前两行的第二列的元素,但由于切片范围只包含一个元素,所以结果是一个列向量。
- arr[:2][1:2]首先选择了原数组的前两行,然后从这些行中选择了第二行(在子数组中的位置),所以结果是一个单行矩阵。
3.高级索引
在NumPy中,当你使用列表或数组作为索引时,你实际上是在执行高级索引。这种索引方式允许你通过指定一个索引数组来选择多个元素,这些元素可以来自数组的任何位置,并且不必是连续的。
① 使用单个数组作为索引
x = np.array([[1, 2], [3, 4], [5, 6]])
print(x[[1, 2]]) # 等价于x[1]和x[2]组成的数组
# [[3 4]
# [5 6]]
x[[1, 2]] 表示你想从数组 x 中提取索引为 1 和 2 的行。由于 Python 中的索引是从 0 开始的,所以索引 1 对应的是第 2 行,索引 2 对应的是第 3 行。因此,这段代码会输出一个包含原始数组 x 中第 2 行和第 3 行的新数组。
② 使用两个数组作为索引
print(x[[0, 1, 2], [0, 1, 0]]) # 等价于x[0, 0]、x[1, 1]和x[2, 0]组成的数组
# [1 4 5]
当你使用两个索引数组进行高级索引时,第一个数组指定了行索引,第二个数组指定了列索引。
这两个数组的长度必须相同,因为它们是成对使用的:第一个元素来自第一个数组的行索引和第二个数组的列索引,
第二个元素来自第二个数组的行索引和第二个数组的列索引,依此类推。
- 从第 0 行(索引为 0)提取第 0 列的元素,即 x[0, 0],得到 1。
- 从第 1 行(索引为 1)提取第 1 列的元素,即 x[1, 1],得到 4。
- 从第 2 行(索引为 2)提取第 0 列的元素,即 x[2, 0],得到 5。
③ 使用布尔数组作为索引
print(x[[True, False, True]])
# [[1 2]
# [5 6]]
使用布尔数组作为索引是一种高级索引的形式,允许你根据布尔条件选择数组中的元素。布尔数组中的每个元素(True 或 False)对应于原始数组中相应位置的元素是否应该被选中。
④ 使用比较运算符索引
print(x < 4)
# [[ True True]
# [ True False]
# [False False]]
在NumPy中,当你对数组使用比较运算符(如 <、>、<=、>=、==、!=)时,你会得到一个与原始数组形状相同的布尔数组,其中的每个元素都是原始数组中对应元素与给定值比较的结果(True 或 False)。
print(x[x < 4])
# [1 2 3]
print(x[np.array([[True, True], [True, False], [False,False]])])
# [1 2 3]
NumPy 会提取所有布尔值为 True 的位置对应的元素,并将它们展平为一个一维数组。所以输出将会是[1 2 3]