第三章:NumPy (1)
NumPy(1) 简介
ndarray 对象
概述
- 用于存放同类型元素的多维数组
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
名称 | 描述 |
---|---|
object | 数组或嵌套的数列 |
dtype | 数组元素的数据类型,可选 |
copy | 对象是否需要复制,可选 |
order | 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) |
subok | 默认返回一个与基类类型一致的数组 |
ndmin | 指定生成数组的最小维度 |
示例
import numpy as np
# 一维数组
a = np.array([1, 2, 3])
print(a)
运行结果
[1 2 3]
import numpy as np
# 多维数组
a = np.array([[1, 2], [3, 4]])
print(a)
运行结果
[[1 2] [3 4]]
import numpy as np
# 最小维度
a = np.array([1, 2, 3, 4, 5], ndmin=2)
print(a)
运行结果
[[1 2 3 4 5]]
import numpy as np
# dtype 参数
a = np.array([1, 2, 3], dtype=complex)
print(a)
运行结果
[1.+0.j 2.+0.j 3.+0.j]
import numpy as np
# 最小维度
a = np.array([1, 2, 3, 8, 9, 10], ndmin=3)
print(a)
运行结果
[[[1 2 3 8 9 10]]]
数据类型
常用 NumPy 基本类型
名称 | 描述 |
---|---|
bool_ | 布尔型数据类型(True 或者 False) |
int_ | 默认的整数类型(类似于 C 语言中的 long,int32 或 int64) |
intc | 与 C 的 int 类型一样,一般是 int32 或 int 64 |
intp | 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64) |
int8 | 字节(-128 to 127) |
int16 | 整数(-32768 to 32767) |
int32 | 整数(-2147483648 to 2147483647) |
int64 | 整数(-9223372036854775808 to 9223372036854775807) |
uint8 | 无符号整数(0 to 255) |
uint16 | 无符号整数(0 to 65535) |
uint32 | 无符号整数(0 to 4294967295) |
uint64 | 无符号整数(0 to 18446744073709551615) |
float_ | float64 类型的简写 |
float16 | 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位 |
float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位 |
float64 | 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位 |
complex_ | complex128 类型的简写,即 128 位复数 |
complex64 | 复数,表示双 32 位浮点数(实数部分和虚数部分) |
complex128 | 复数,表示双 64 位浮点数(实数部分和虚数部分) |
练习
Int8
占一个字节,取值范围为:
- 0 ~ 128
- -128 ~ 127
- -32768 ~ 32767
- -128 ~ 128
答案
-128 ~ 127
Uint16
的取值范围为:
- 0 ~ 127
- 0 ~ 255
- 0 ~ 65535
- 0 ~ 4294967295
答案
0 ~ 65535
数据类型对象 dtype
用来描述与数组对应的内存区域是如何使用,它描述了数据的以下几个方面:
- 数据的类型(整数,浮点数或者
Python
对象) - 数据的大小(例如, 整数使用多少个字节存储)
- 数据的字节顺序(小端法或大端法)
numpy.dtype(object, align, copy)
名称 | 描述 |
---|---|
object | 要转换为的数据类型对象 |
align | 如果为 true ,填充字段使其类似 C 的结构体。 |
copy | 复制 dtype 对象 ,如果为 false ,则是对内置数据类型对象的引用 |
示例
import numpy as np
dt = np.dtype([("age", np.int8)])
print(dt)
运行结果
[('age', 'i1')]
注意
int8,int16,int32,可替换为等价的字符串 'i1','<i2','<i4',以此类推。
import numpy as np
dt = np.dtype([("age", np.int32)])
print(dt)
运行结果
[('age', '<i4')]
import numpy as np
dt = np.dtype("i8")
print(dt)
运行结果
int64
数组属性
概览
属性 | 说明 |
---|---|
ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 |
ndarray.ndim | 秩,即轴的数量或维度的数量 |
ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |
ndarray.flags | ndarray 对象的内存信息 |
ndarray.size | 数组元素的总个数,相当于 .shape 中 n*m 的值 |
ndarray.dtype | ndarray 对象的元素类型 |
ndarray.real | ndarray元素的实部 |
ndarray.imag | ndarray 元素的虚部 |
ndarray.data | 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。 |
ndarray.shape
- 返回一个包含数组维度的元组,可以用于调整数组大小
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape)
运行结果
(2, 3)
import numpy as np
# a.shape 会调整数组大小
a = np.array([[1, 2, 3], [4, 5, 6]])
a.shape = (3, 2)
print(a)
运行结果
[[1 2] [3 4] [5 6]]
import numpy as np
# 使用 reshape 调整数组大小
a = np.array([[1, 2, 3], [4, 5, 6]])
b = a.reshape(3, 2)
print(b)
运行结果
[[1 2] [3 4] [5 6]]
ndarray.ndim
- 返回数组的维数
import numpy as np
# 等间隔数字的数组
a = np.arange(0, 9, 2)
print(a)
print(a.ndim)
运行结果
[0 2 4 6 8]
1
ndarray.itemsize
- 返回数组元素的字节单位长度
import numpy as np
# 数组的 dtype 为 int8 (一字节)
x = np.array([1, 2, 3, 4, 5], dtype=np.int8)
y = np.array([1, 2, 3, 4, 5], dtype=np.int16)
z = np.array([1, 2, 3, 4, 5], dtype=np.int32)
print(x.itemsize, y.itemsize, z.itemsize)
运行结果
1 2 4
ndarray.flags
- 返回
ndarray
对象的内存信息,包含以下属性:
属性 | 描述 |
---|---|
C_CONTIGUOUS (C) | 数据是在一个单一的C风格的连续段中 |
F_CONTIGUOUS (F) | 数据是在一个单一的Fortran风格的连续段中 |
OWNDATA (O) | 数组拥有它所使用的内存或从另一个对象中借用它 |
WRITEABLE (W) | 数据区域可以被写入,将该值设置为 False,则数据为只读 |
ALIGNED (A) | 数据和所有元素都适当地对齐到硬件上 |
UPDATEIFCOPY (U) | 这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新 |
import numpy as np
x = np.array([1,2,3,4,5])
print (x.flags)
运行结果
C_CONTIGUOUS : True F_CONTIGUOUS : True OWNDATA : True WRITEABLE : True ALIGNED : True WRITEBACKIFCOPY : False
数组创建例程
NumPy 数组创建例程
ndarray
数组除了可以使用底层ndarray
构造器来创建外,也可以通过以下几种方式来创建
概览
方式 | 说明 |
---|---|
numpy.empty | 创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组 |
numpy.zeros | 创建指定大小的数组,数组元素以 0 来填充 |
numpy.ones | 创建指定形状的数组,数组元素以 1 来填充 |
numpy.empty
- 来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组
numpy.empty(shape, dtype = float, order = 'C')
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。 |
import numpy as np
x = np.empty([3, 2], dtype=int)
print(x)
运行结果
[[744107117 760884589] [777662061 794439533] [811217005 23330817]]
注意
数组元素为随机值,因为它们未初始化
numpy.zeros
- 创建指定大小的数组,数组元素以 0 来填充
numpy.zeros(shape, dtype = float, order = 'C')
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | 'C' 用于 C 的行数组,或者 'F' 用于 FORTRAN 的列数组 |
import numpy as np
# 含有5个0的数组,默认数据类型为float
x = np.zeros(5)
y = np.zeros(5, dtype=int)
print(x)
print(y)
运行结果
[0. 0. 0. 0. 0.]
[0 0 0 0 0]
numpy.ones
- 创建指定形状的数组,数组元素以 1 来填充
numpy.ones(shape, dtype = None, order = 'C')
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | 'C' 用于 C 的行数组,或者 'F' 用于 FORTRAN 的列数组 |
import numpy as np
# 默认为浮点数
x = np.ones(5)
print(x)
# 自定义类型
x = np.ones([2, 2], dtype=int)
print(x)
运行结果
[1. 1. 1. 1. 1.] [[1 1] [1 1]]
NumPy 从已有的数组创建数组
- 从已有的数组创建数组
概览
方式 | 说明 |
---|---|
numpy.asarray | 类似于 numpy.array ,常用于将 Python 序列转为 ndarray |
numpy.frombuffer | 接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象 |
numpy.fromiter | 从可迭代对象中建立 ndarray 对象,返回一维数组 |
numpy.asarray
- 类似于
numpy.array
,常用于将Python
序列转为ndarray
numpy.asarray(a, dtype = None, order = None)
参数 | 描述 |
---|---|
a | 任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组 |
dtype | 数据类型,可选 |
order | 可选,有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
import numpy as np
# 将列表转换为 ndarray
x = [1, 2, 3]
a = np.asarray(x)
print(x, type(x))
print(a, type(a))
运行结果
[1, 2, 3] <class 'list'> [1 2 3] <class 'numpy.ndarray'>
numpy.frombuffer
- 接受
buffer
输入参数,以流的形式读入转化成ndarray
对象
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
参数 | 描述 |
---|---|
buffer | 可以是任意对象,会以流的形式读入。 |
dtype | 返回数组的数据类型,可选 |
count | 读取的数据数量,默认为-1,读取所有数据。 |
offset | 读取的起始位置,默认为0。 |
import numpy as np
s = b"Hello World!"
a = np.frombuffer(s, dtype="S1")
b = np.frombuffer(s, dtype="S2")
c = np.frombuffer(s, dtype="S3")
print(a)
print(b)
print(c)
运行结果
[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd' b'!'] [b'He' b'll' b'o ' b'Wo' b'rl' b'd!'] [b'Hel' b'lo ' b'Wor' b'ld!']
注意
- 前缀
u
表示该字符串是unicode
编码 - 前缀
b
表示该字符串是bytes
类型 - 前缀
f
用来格式化字符串 - 使用
r
来表示原始字符串,这种字符串被称为“Raw String”
numpy.fromiter
- 从可迭代对象中建立
ndarray
对象,返回一维数组
参数 | 描述 |
---|---|
iterable | 可迭代对象 |
dtype | 返回数组的数据类型 |
count | 读取的数据数量,默认为-1,读取所有数据 |
import numpy as np
# 使用 range 函数创建列表对象
list = range(5)
it = iter(list)
# 使用迭代器创建 ndarray
x = np.fromiter(it, dtype=float)
print(x)
运行结果
[0. 1. 2. 3. 4.]
NumPy 数值范围数组
- 如何从数值范围创建数组
概览
方式 | 说明 |
---|---|
numpy.arange | 使用 arange 函数创建数值范围并返回 ndarray 对象 |
numpy.linspace | 创建一个一维数组,数组是一个等差数列构成的 |
numpy.logspace | 创建一个等比数列 |
numpy.arange
- 使用
arange
函数创建数值范围并返回ndarray
对象
numpy.arange(start, stop, step, dtype)
参数 | 描述 |
---|---|
start | 起始值,默认为 0 |
stop | 终止值(不包含) |
step | 步长,默认为 1 |
dtype | 返回 ndarray 的数据类型,如果没有提供,则会使用输入数据的类型。 |
import numpy as np
x = np.arange(5)
print(x)
运行结果
[0 1 2 3 4]
import numpy as np
x = np.arange(1, 100, 10, dtype=int)
print(x)
运行结果
[ 1 11 21 31 41 51 61 71 81 91]
numpy.linspace
- 创建一个一维数组,数组是一个等差数列构成的
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
参数 | 描述 |
---|---|
start | 序列的起始值 |
stop | 序列的终止值,如果 endpoint 为 true ,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为 50 |
endpoint | 该值为 true 时,数列中包含stop 值,反之不包含,默认是 true |
retstep | 如果为 true 时,生成的数组中会显示间距,反之不显示。 |
dtype | ndarray 的数据类型 |
import numpy as np
x = np.linspace(10, 20, 5)
print(x)
运行结果
[10. 12.5 15. 17.5 20. ]
import numpy as np
x = np.linspace(10, 30, 4)
print(x)
运行结果
[10. 16.66666667 23.33333333 30. ]
numpy.logspace
- 创建一个等比数列
numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
参数 | 描述 |
---|---|
start | 序列的起始值为:base ** start |
stop | 序列的终止值为:base ** stop。如果endpoint 为true ,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 |
endpoint | 该值为 true 时,数列中中包含stop 值,反之不包含,默认是True。 |
base | 对数 log 的底数。 |
dtype | ndarray 的数据类型 |
import numpy as np
# 默认底数为 10
# 该语句的意思是:在10的1次幂到10的2次幂的闭区间中找到10个公比相同的数字
x = np.logspace(1.0, 2.0, num=10)
print(x)
运行结果
[ 10. 12.91549665 16.68100537 21.5443469 27.82559402 35.93813664 46.41588834 59.94842503 77.42636827 100. ]
import numpy as np
# 默认底数为 10
# 语句的意思是:在10的1.0次幂到10的2.0次幂的闭区间中找到10个公比相同的数字
x = np.logspace(1.0, 2.0, num=10)
print(x)
运行结果
[ 10. 12.91549665 16.68100537 21.5443469 27.82559402 35.93813664 46.41588834 59.94842503 77.42636827 100. ]
import numpy as np
# 语句的意思是:在5的1.0次幂到10的2.0次幂的闭区间中找到3个公比相同的数字
x = np.logspace(1.0, 2.0, 3, base=5)
print(x)
运行结果
[ 5. 11.18033989 25. ]
切片和索引
切片
ndarray
对象的内容可以通过索引或切片来访问和修改,与Python
中list
的切片操作一样ndarray
数组可以基于0 - n
的下标进行索引,切片对象可以通过内置的slice
函数,并设置start
,stop
及step
参数进行,从原数组中切割出一个新数组
import numpy as np
# 从索引 2 开始到索引 7 停止,间隔为2
a = np.arange(10)
s = slice(2, 7, 2)
print(a[s])
运行结果
[2 4 6]
import numpy as np
a = np.arange(10)
s = slice(1, 9, 2)
print(a[s])
运行结果
[1 3 5 7]
我们也可以通过冒号分隔切片参数 start:stop:step
来进行切片操作:
import numpy as np
# 从索引 2 开始到索引 7 停止,间隔为2
a = np.arange(10)
b = a[2:7:2]
print(b)
运行结果
[2 4 6]
import numpy as np
a = np.array([[5, 8, 9], [100, 300, 20], [7, 6, 3], [5, 5, 5]])
print("现在我们从索引a[2:]的地方开发切片")
print(a[2:])
print("现在我们从索引a[:3]的地方开发切片")
print(a[:3])
运行结果
现在我们从索引a[2:]的地方开发切片 [[7 6 3] [5 5 5]] 现在我们从索引a[:3]的地方开发切片 [[ 5 8 9] [100 300 20] [ 7 6 3]]
NumPy 高级索引
NumPy
中的高级索引指的是使用整数数组、布尔数组或者其他序列来访问数组的元素。相比于基本索引,高级索引可以访问到数组中的任意元素,并且可以用来对数组进行复杂的操作和修改。
整数数组索引
- 使用一个数组来访问另一个数组的元素。这个数组中的每个元素都是目标数组中某个维度上的索引值。
import numpy as np
# 以下实例获取数组中 (0,0),(1,1) 和 (2,0) 位置处的元素
x = np.array([[1, 2], [3, 4], [5, 6]])
y = x[[0, 1, 2], [0, 1, 0]]
print(y)
运行结果
[1 4 5]
import numpy as np
# 以下实例获取数组中 (0,0),(1,1) 和 (2,0) 位置处的元素
x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
rows = np.array([0, 0, 3, 3])
cols = np.array([0, 2, 0, 2])
y = x[rows, cols]
print(y)
运行结果
[ 0 2 9 11]
布尔值索引
- 通过一个布尔数组来索引目标数组。布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
import numpy as np
# 获取大于 5 的元素
x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print("我们的数组是:")
print(x)
print("\n")
# 现在我们会打印出大于 5 的元素
print("大于 5 的元素是:")
print(x[x > 5])
运行结果
我们的数组是: [[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]]
大于 5 的元素是: [ 6 7 8 9 10 11]
import numpy as np
x = np.array([[0, 10, 12], [3, 4, 5], [6, 17, 8], [9, 0, 1]])
print(x[x >= 8])
运行结果
[10 12 17 8 9]
广播
- 广播是指
NumPy
在算术运算期间处理不同形状的数组的能力。对数组的算术运算通常在相应的元素上进行。如果两个阵列具有完全相同的形状,这些操作就会被无缝执行。
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
c = a * b
print(c)
运行结果
[ 10 40 90 160]
import numpy as np
a = np.array(
[[0.0, 0.0, 0.0], [10.0, 10.0, 10.0], [20.0, 20.0, 20.0], [30.0, 30.0, 30.0]]
)
b = np.array([1.0, 2.0, 3.0])
print("第一个数组:")
print(a)
print()
print("第二个数组:")
print(b)
print()
print("第一个数组加第二个数组:")
print(a + b)
运行结果
第一个数组: [[ 0. 0. 0.] [10. 10. 10.] [20. 20. 20.] [30. 30. 30.]]
第二个数组: [1. 2. 3.]
第一个数组加第二个数组: [[ 1. 2. 3.] [11. 12. 13.] [21. 22. 23.] [31. 32. 33.]]
import numpy as np
a = np.array([[5, 8, 9], [100, 30, 20], [7, 6, 3], [5, 5, 5]])
b = np.array([0, 1, 2])
print("第一个数组加第二个数组:")
print(a + b)
运行结果
第一个数组加第二个数组: [[ 5 9 11] [100 31 22] [ 7 7 5] [ 5 6 7]]