1、为什么使用Numpy数组结构代替Python本身的列表?
- 列表list的元素在内存是分散存储,而NumPy数组存储在一个连续的内存中。numpy数组遍历比列表list更高效。
- 因为连续存储,可以连续加载多个浮点数到寄存器,从而利用CPU的多核,并行计算。
2、python列表和numpy数组的差异
差异方面 | python列表 | numpy数组(ndarray) |
---|
数据类型 | 可以包含不同的数据类型(例如:str类型和int类型可在同一个列表中) | 数组中所有的元素必须是相同的数据类型(例如:一个数据中必须全是整数,或者全是浮点数) |
内存效率 | 列表中存储的是对象的引用(也就是只想原始数据的指针),原始数据存储在内存的其他位置,因此内存开销大; | 直接在一片连续的空间内存储原始数据,内存占用比列表小很多 |
性能表现 | 通常需要使用python解释器循环,运算速度较慢 | 底层采用C语言实现,支持向量化操作,运算速度快(通常快10-100倍) |
维度 | 一维,但可以用嵌套李彪模拟多维 | 支持多维数组 |
功能实现 | 采用append、insert、remove等函数,不支持直接的数学运算 | 丰富的数据运算(矩阵的加减乘除等、线性代数运算)、广播机制、高级索引 |
可变性 | 动态大小,可通过内置函数增减元素 | 底层是C语言实现的,因此ndarray数组创建后大小固定不变 |
3、创建ndarray数组
-
array([])
:创建指定的数组
-
zeros((行数,列数))
:创建满足行数和列数的 全是0的数组
-
ones((行数,列数))
:创建满足行数和列数的 全是1的数组
-
full((行数,列数),指定数字)
: 创建满足行数和列数的 全是指定数字的数组
-
empty((行数,列数))
: 创建满足行数和列数的数组,其内容取决于内存当前的状态
- 可能的值是:之前程序使用的残留值、随机垃圾值、极大或者极小的值
-
zeros_like(已有的数组)
:根据已有数组的形状创建全是0的数组
-
ones_like(已有数组)
:根据已有数组的形状创建全是1的数组
-
empty_like(已有数组)
:根据已有数组的形状创建未初始化的数组
-
arange()
:类似python中的range(start,end,step)
,生成有规律的序列
-
linspace(start,end,总数)
:生成一个开始到结束之间共总数个数字(平均分配区间)
-
random.rand()
:生成0-1之间的随机浮点数,可以给定形状生成数组,不给形状的话生成单个数值
-
random.randn()
:生成标准正态分布的随机数,可以给定形状生成数组,不给形状的话生成单个数值
-
random.standard_normal()
:生成标准正态分布的随机数,可以给定形状生成数组,不给形状的话生成单个数值
-
random.normal(loc=0,scale=1,size)
:根据均值为0,标准差为1的正态分布生成指定大小的随机数组
-
random.randint(开始,结束,大小)
:生成指定大小(元素大小在指定范围内)的随机整数数组
-
random.choice(数组,size)
:从指定数组中选取指定个数的元素
-
NumPy 1.17开始,推荐使用新的随机数生成器API
-
rng = np.random.default_rng(seed=42)
:创建随机数生成器,seed是指定的种子(指定随机数)
rng.random()
:代替random.rand()
,生成0-1之间的随机浮点数rng.integers()
:代替random.randint()
,生成指定大小(元素大小在指定范围内)的随机整数数组rng.normal()
:代替random.normal()
,生成指定正态分布大小的随机数组
import numpy as np
arr1 = np.array([1, 2, 3, 4])
arr2 = np.array([[1, 2], [3, 4]])
zeros = np.zeros((3, 4))
ones = np.ones((2, 3))
empty = np.empty((2, 2))
full = np.full((3, 3), 7)
ones_like = np.ones_like(arr1)
zeros_like = np.zeros_like(arr2)
empty_like = np.empty_like(arr2)
range_arr = np.arange(10)
lin_arr = np.linspace(0, 1, 5)
print(np.random.rand())
print(np.random.rand(3, 2) )
print(np.random.randn())
print(np.random.randn(2, 3))
print(np.random.standard_normal((1,3)))
print(np.random.normal(loc=0,scale=1,size=(3,3)))
print(np.random.randint(0, 10))
print(np.random.randint(5, size=(2, 3)))
print(np.random.choice(np.array([1, 2, 3, 4, 5]),size=3))
4、 数组的数据类型
- 有符号的数据类型:有一位代表符号位。例如:
int8
,中11111111
表示 -127 - 无符号的数据类型:所有的位置都表示数字。例如:
uint8
中11111111
表示255 - astype(数组类型):将数组的类型转化成指定的数组类型
类型 | 类型代码 | 说明 |
---|
int8, uint8 | i1, u1 | 有符号和无符号的8位(1个字节)整型 |
int16,uint16 | i2, u2 | 有符号和无符号的16位(2个字节)整型 |
int32,uint32 | i4, u4 | 有符号和无符号的32位(4个字节)整型 |
int64,uint64 | i8, u8 | 有符号和无符号的64位(8个字节)整型 |
float16 | f2 | 半精度浮点数 |
float32 | f4或f | 标准的单精度浮点数。与C的float兼容 |
float64 | f8或d | 标准的双精度浮点数。与C的double和Python的float对象兼容 |
bool | ? | 存储True和False值的布尔类型 |
object | 0 | 任意python对象, |
bytes_ | S | 固定长度的ASCII(无中文)字符串类型(每个字符1个字节)。例如,要创建一个长度为10的字符串,应使用’S10’ |
unicode_ | U | 固定长度的Unicode类型(字节数由平台决定);与字符串的指定语法一样(如‘U10’) |
arr = np.array([1,2,3,4,5])
float_arr = arr.astype(np.float64)
5、数组属性
- 数组变量.ndim :显示数组变量的维度
- 数组变量.shape :显示数组的形状
- 数组变量.size :显示数组的元素个数
- 数组变量.dtype :显示数组的数据类型
- 数组变量.itemsize :显示每个元素的字节大小
- 数组变量.ndytes :显示数组的总字节
- 数组变量.T:将数组进行转置
- 数组变量.flags:查看数组在内存中的相关信息
C_CONTIGUOUS
:True的时候,数组按行存储。即:a11 → a12 → a13 → a21 → a22 → a23F_CONTIGUOUS
:True的时候,数组按列存储。即:a11 → a21 → a12 → a22 → a13 → a23F_CONTIGUOUS
和 C_CONTIGUOUS
是相对的,一个为True另一个一定是False
- 数组变量.strides:在内存中移动到相邻数组元素所需的字节步长。
arr = np.array([[1, 2, 3], [4, 5, 6]],oeder = 'C')
print(arr.ndim)
print(arr.shape)
print(arr.size)
print(arr.dtype)
print(arr.itemsize)
print(arr.nbytes)
print(arr.T)
print(arr.flags)
print(arr.strides)
6、ndarray的简单运算和形状变换
- 广播机制:NumPy的广播功能允许不同形状的数组进行算术运算
- 规则一:如果两个数组的维度数不同,形状会在较小的数组前面补1
A形状:(3,4,2)、B形状: (4,1)——>B形状广播成(1,4,1) - 规则二:对于每个维度,大小要么相等,要么其中一个为1,要么其中一个不存在
A形状:(3,4,2)、B形状广播后的形状(1,4,1)
第一维度:3,1:存在1,可兼容
第二维度:4,4:大小相等,可兼容
第三维度:2,1:存在1,可兼容 - 规则三:在维度大小为1的情况下,数组会沿着该维度"拉伸"以匹配另一个数组的形状
A形状:(3,4,2)、B形状广播后的形状(1,4,1)
第一维度:3,1:B的第一维度复制三次(3,4,1)
第二维度:4,4:大小相等,可兼容(3,4,1)
第三维度:2,1:B的第三维度复制两次(3,4,2)
- 数组与标量(单纯的一个数字)的算术运算标量值传播到数组的各个元素
- 基础的
+ - * /
运算 - reshape((行,列)):将数组的形状转化成指定的形状
- flatten():将数组转化成一维数组
- T:将数组转置(行形状变成列形状;列形状变成行形状)
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a + 3)
print(a * b)
print(1 / arr) 相当于1除以每个数字
print(arr ** 2) 相当于arr中每个元素做平方操作
print(arr * 6) 相当于每个元素都×6
arr = np.arange(6)
print(arr.reshape(2, 3))
print(arr.flatten())
print(arr.T)