Python3快速入门(十二)——NumPy
一、NumPy简介
1、NumPy简介
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,同时对数组运算提供了大量的数学函数库。
Numpy 是一个运行速度非常快的数学库,内部解除了CPython的GIL,运行效率极好,主要用于数组计算,是大量机器学习框架的基础库,NumPy主要包括如下:
(1)强大的N维数组对象 ndarray
(2)广播功能函数
(3)整合 C/C++/Fortran 代码的工具
(4)线性代数、傅里叶变换、随机数生成等功能。
NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)组合使用,用于替代 MatLab。
2、NumPy的优缺点
NumPy优点如下:
(1)对于同样的数值计算任务,使用NumPy要比直接编写Python代码便捷得多。
(2)NumPy中的数组的存储效率和输入输出性能均远远优于Python中等价的基本数据结构,且其能够提升的性能是与数组中的元素成比例的。
(3)NumPy的大部分代码都用C语言写,其底层算法在设计时有优异的性能,使得NumPy比纯Python代码高效。
NumPy缺点如下:
由于NumPy使用内存映射文件以达到最优的数据读写性能,而内存的大小限制了其对TB级大文件的处理;NumPy数组的通用性不及Python提供的list容器。
3、NumPy安装
pip install --user numpy
--user 选项可以设置只安装在当前的用户下,而不是写入到系统目录。
4、NumPy数据类型
numpy支持的数据类型比 Python 内置的类型要多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 Python 内置的类型。bool_
布尔型数据类型(True 或者 False)int_
默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssizet,通常是int32或 int64)
int8 字节(-128 to 127)
int16 整数(-32768 to 32767)
int32 整数(-2147483648 to 2147483647)
int64 整数(64bit)
uint8 无符号整数(0 to 255)
uint16 无符号整数(0 to 65535)
uint32 无符号整数(0 to 4294967295)
uint64 无符号整数(0 to 18446744073709551615)
`floatfloat64类型的简写
complex_` complex128类型的简写,即 128 位复数
float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float64 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)
每个内建类型都有一个唯一字符代码:
b 布尔类型
i 有符号整型
u 无符号整型
f 浮点型
c 复数浮点型
m 时间间隔
M 日期间隔
O Python对象
S,a byte字符串
U Unicode
V 原始数据(void)
5、dtype数据类型对象
数据类型对象dtype用于描述与数组对应的内存区域如何使用,依赖如下几个方面:
(1)数据的类型(整数,浮点数或者 Python 对象)
(2)数据的大小(例如, 整数使用多少个字节存储)
(3)数据的字节顺序(小端法或大端法)
(4)在结构化类型的情况下,字段的名称、每个字段的数据类型和每个字段所取的内存块的部分。
(5)如果数据类型是子数组,其形状和数据类型。
(6)字节顺序是通过对数据类型预先设定"<"或">"来决定的。"<"意味着小端法(最小值存储在最小的地址,即低位组放在最前面)。">"意味着大端法(最重要的字节存储在最小的地址,即高位组放在最前面)。
dtype 对象使用以下语法构造的:numpy.dtype(object, align, copy)
object - 要转换为的数据类型对象
align - 如果为 true,填充字段使其类似 C 的结构体。
copy - 复制 dtype 对象 ,如果为 false,则是对内置数据类型对象的引用
一个结构化数据类型 student,包含字符串字段 name,整数字段 age,及浮点字段 score,并将 dtype 应用到 ndarray 对象。
import numpy
if __name__ == "__main__":
student = numpy.dtype([("name", "S20"), ("age", numpy.int8), ("marks", "
二、ndarray
1、ndarray简介
ndarray是NumPy的核心,ndarray封装了python原生的同数据类型的n维数组,通过正整数元组索引。
ndarray内部结构如下:
(1)一个指向数据(内存或内存映射文件中的一块数据)的指针。
(2)数据类型(dtype),描述在数组中的固定大小值的格子。
(3)一个表示数组形状(shape)的元组,表示各维度大小的元组。
(4)一个跨度元组(stride),其中整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。
ndarray 和 标准Python 数组的区别如下:
(1)ndarray 在创建时具有固定的大小, 更改ndarray的大小将创建一个新数组并删除原来的数组,与Python的原生数组对象(可以动态增长)不同。
(2)ndarray 中的元素必须具有相同的数据类型,因此在内存中的大小相同。
(3)ndarray 有助于对大量数据进行高级数学和其它类型的操作。 通常,ndarray 的执行效率更高,比使用Python原生数组的代码更少。
(4)大部分基于Python的科学和数学软件包都使用NumPy数组,尽管通常也支持Python原生数组作为参数,但在处理前仍然会将输入数组转换为NumPy数组,而且通常输出为NumPy数组。为了高效地使用当今基于Python的科学计算工具,需要知道如何使用NumPy数组。
2、ndarray 对象的属性
ndarray 对象提供的关键属性如下:
ndarray.ndim:数组的轴(维度)的个数,维度的数量被称为rank。
ndarray.shape:数组的维度,是一个整数的元组,表示每个维度中数组的大小。对于n行和m列的矩阵,shape是(n,m)。因此,shape元组的长度就是rank或维度的个数 ndim。
ndarray.size:数组元素的总数,等于shape的元素的乘积。
ndarray.dtype:描述数组中元素类型的对象。可以使用标准的Python类型创建或指定dtype。NumPy提供自己的类型,如numpy.int32、numpy.int16和numpy.float64。
ndarray.itemsize:数组中每个元素的字节大小,等于 ndarray.dtype.itemsize。元素为 float64 类型的数组的 itemsize 为8(=64/8),而 complex32 类型的数组的 itemsize 为4(=32/8)。
ndarray.flags:ndarray对象的内存信息。
ndarray.real:ndarray元素的实部
ndarray.imag:ndarray 元素的虚部
ndarray.data:缓冲区包含数组的实际元素。
Ndarray.flags的内存信息属性如下:
C_CONTIGUOUS (C):数据是在一个单一的C风格的连续段中
F_CONTIGUOUS (F):数据是在一个单一的Fortran风格的连续段中
OWNDATA (O):数组拥有自己所使用的内存或从另一个对象中借用
WRITEABLE (W:)数据区域可以被写入,将值设置为 False,则数据为只读。
ALIGNED (A):数据和所有元素都适当地对齐到硬件上。
UPDATEIFCOPY (U):数组是其它数组的一个副本,当数组被释放时,原数组的内容将被更新。
import numpy
if __name__ == "__main__":
a = numpy.arange(15).reshape(5, 3)
print(a)
print("shape: ", a.shape)
print("ndim:", a.ndim)
print("dtype:", a.dtype.name)
print("itemsize: ", a.itemsize)
print("itemsize: ", a.dtype.itemsize)
print("size: ", a.size)
print("flags: ", a.flags)
print("data: ", a.data)
print("type:", type(a))
# output:
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]
# [12 13 14]]
# shape: (5, 3)
# ndim: 2
# dtype: int64
# itemsize: 8
# itemsize: 8
# size: 15
# flags: C_CONTIGUOUS : True
# F_CONTIGUOUS : False
# OWNDATA : False
# WRITEABLE : True
# ALIGNED : True
# WRITEBACKIFCOPY : False
# UPDATEIFCOPY : False
# data:
# type:
3、创建数组
numpy.empty(shape, dtype = float, order = 'C')
numpy.empty 方法用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组。
import numpy
if __name__ == "__main__":
array_empty = numpy.empty([2, 3])
print(array_empty)
# output:
# [[6.92184835e-310 1.23016891e-316 6.92184893e-310]
# [6.92184893e-310 1.45897537e-303 2.72466824e-311]]
numpy.array(p_object, dtype=None, copy=True, order='K', subok=False, ndmin=0)
创建数组,p_object为数组或序列,dtype为数组元素类型
import numpy
if __name__ == "__main__":
a = numpy.array([[1, 2, 3], [4, 5, 6]], numpy.int)
print(a)
# output:
# [[1 2 3]
# [4 5 6]]
numpy.asarray(a, dtype = None, order = None)
创建数组,a为数组或序列,dtype为数组元素类型
import numpy
if __name__ == "__main__":
array_as = numpy.asarray([[1, 2, 3, 4], [5, 6, 7, 8]])
print(array_as)
# output:
# [[1 2 3 4]
# [5 6 7 8]]
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
numpy.frombuffer 用于实现动态数组。
buffer 参数为人以对象,以流的形式读入转化成 ndarray 对象。buffer 是字符串的时候,Python3 默认 str 是 Unicode 类型,所以要转成 bytestring 在原 str 前加上 b。
dtype参数,数组的数据类型,可选。
count参数,读取的数据量,默认为-1,读取所有的数据。
offset参数,读取的起始位置,默认为0。
import numpy
if __name__ == "__main__":
s = b"Hello, Python"
a = numpy.frombuffer(s, dtype="S1")
print(a)
# output:
# [b'H' b'e' b'l' b'l' b'o' b',' b' ' b'P' b'y' b't' b'h' b'o' b'n']
numpy.fromiter(iterable, dtype, count=-1)
numpy.fromiter 方法从可迭代对象中建立 ndarray 对象,返回一维数组。
Iterable参数,可迭代对象。
dtype参数,数组的数据类型,可选。
count参数,读取的数据数量,默认为-1,读取所有数据。
import numpy
if __name__ == "__main__":
# 使用 range 函数创建列表对象
l = range(10)
it = iter(l)
# 使用迭代器创建 ndarray
x = numpy.fromiter(it, dtype=float)
print(x)
# output:
# [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
numpy.ones(shape, dtype=None, order='C')
创建数值为1的数组,shape是数组的形状,dtype是数值类型。
import numpy
if __name__ == "__main__":
array_ones = numpy.ones((2, 3), numpy.int)
print(array_ones)
# output:
# [[1 1 1]
# [1 1 1]]
numpy.zeros(shape, dtype=None, order='C')
创建数值为0的数组,shape是数组的形状,dtype是数值类型。
import numpy
if __name__ == "__main__":
array_zeros = numpy.zeros((2, 3), numpy.int)
print(array_zeros)
# output:
# [[0 0 0]
# [0 0 0]]
numpy.full(shape, fill_value, dtype=None, order='C')
创建指定数值的数组,shape是数组的形状,fill_value是数值,dtype是数值类型。
import numpy
if __name__ == "__main__":
array_full = numpy.full((2, 3), 3.14, numpy.float)
print(array_full)
# output:
# [[3.14 3.14 3.14]
# [3.14 3.14 3.14]]
numpy.eye(N, M=None, k=0, dtype=float, order='C')
创建单位矩阵,N为行数,M为列数
import numpy
if __name__ == "__main__":
array_eye = numpy.eye(2, 3)
print(array_eye)
# output:
# [[1. 0. 0.]
# [0. 1. 0.]]
numpy.diag(v, k=0)
创建对角矩阵,v是主对角线数值,k是对角线元素,k = 0表示主对角线,k>0的值选择在主对角线之上的对角线中的元素,k<0
的值选择在主对角线之下的对角线中的元素。
import numpy
if __name__ == "__main__":
array_diag = numpy.diag([1, 2, 3], k=1)
print(array_diag)
# output:
# [[0 1 0 0]
# [0 0 2 0]
# [0 0 0 3]
# [0 0 0 0]]
numpy.random.rand(*dn)
创建指定shape的数组,数值范围在0~1之间。dn是可变参数,接收多个参数用于指定数组的shape。
import numpy
if __name__ == "__main__":
array_rand = numpy.random.rand(2, 3)
print(array_rand)
# output:
# [[0.73299266 0.10939252 0.61875294]
# [0.11556114 0.62150992 0.56455656]]
numpy.random.uniform(low=0.0, high=1.0, size=None)
创建指定范围内的数值的数或数组,low为下限,high为上限,size为个数,可以为序列,用于指定数组的shape。
import numpy
if __name__ == "__main__":
array_uniform = numpy.random.uniform(3, 3.14, (2, 3))
print(array_uniform)
print(numpy.random.uniform(0, 100, 3))
# output:
# [[3.00724161 3.10009725 3.04795313]
# [3.06319773 3.12678593 3.09834495]]
# [73.03084565 34.16123519 95.58874675]
numpy.randint(low, high=None, size=None, dtype='l')
创建指定范围内的数值的数或数组,low为下限,high为上限,size为个数,可以为序列,用于指定数组的shape。
import numpy
if __name__ == "__main__":
array_randint = numpy.random.randint(0, 10, (2, 3), dtype=numpy.int)
print(array_randint)
print(numpy.random.randint(0, 100, 3, dtype=numpy.int))
# output:
# [[6 2 8]
# [1 4 8]]
# [60 16 25]
numpy.arange(start=None, *args, **kwargs)
创建一维数组,其中包含位于半开区间[start, stop)内并均匀分布的值,step表示步长。
import numpy
if __name__ == "__main__":
array_arange = numpy.arange(0, 10, 3)
print(array_arange)
# output:
# [0 3 6 9]
numpy.linspace(start, stop, N)
创建N个在闭区间[start, stop]内均匀分布的值。
import numpy
if __name__ == "__main__":
array_linspace = numpy.linspace(0, 10, 5)
print(array_linspace)
# output:
# [ 0. 2.5 5. 7.5 10. ]
numpy.random.normal(loc=0.0, scale=1.0, size=None)
创建给定均值loc、标准差scale、维度size的正态分布
import numpy
if __name__ == "__main__":
array_normal = numpy.random.normal(loc=1.75, scale=0.1, size=[2, 3])
print(array_normal)
# output:
# [[1.6629973 1.78608724 1.83688018]
# [1.77781707 1.62255632 1.73506316]]
4、ndarray索引
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。
ndarray 数组可以基于 0 - n 的下标进行索引,切片对象可以通过内置的 slice 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。
array[start : end:step]:截取start到end的切片,间隔为step
array[start:]:截取从start到结尾的切片
array[:end]:截取从开始到end的切片
import numpy
if __name__ == "__main__":
array_rand = numpy.arange(1, 10)
print(array_rand)
print(array_rand[1:7:2])
# output:
# [1 2 3 4 5 6 7 8 9]
# [2 4 6]
ndarray数组可以通过整数数组进行索引,通常需要分别构造行索引和列索引的数组,通过行索引数组和列索引数组组合使用最终定位数组的索引。
import numpy
if __name__ == "__main__":
array_rand = numpy.random.randint(0, 10, [5, 8])
print(array_rand)
rows = numpy.array([[0, 0], [3, 3]])
cols = numpy.array([[0, 2], [0, 2]])
result = array_rand[rows, cols]
print(result)
# output:
# [[6 1 7 7 6 1 0 5]
# [9 5 4 6 1 0 8 0]
# [0 2 1 5 3 3 5 6]
# [4 4 5 0 2 5 2 2]
# [1 9 8 5 7 1 3 2]]
# [[6 7]
# [4 5]]
ndarray可以通过一个布尔数组来进行索,布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
import numpy
if __name__ == "__main__":
array_rand = numpy.random.randint(0, 10, [5, 8])
print(array_rand)
result = array_rand[array_rand > 5]
print(result)
# output:
# [[2 3 2 2 0 5 4 7]
# [8 8 2 8 6 5 9 7]
# [9 6 3 9 5 9 9 5]
# [3 9 1 1 8 7 9 7]
# [8 2 0 6 5 0 2 7]]
# [7 8 8 8 6 9 7 9 6 9 9 9 9 8 7 9 7 8 6 7]
5、数组修改
numpy.ndarray.reshape(a, newshape, order='C')
把指定的数组改变形状,但元素个数不变;有返回值,即不对原始多维数组进行修改。a是数组,newshape为新的shape。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, 10)
b = numpy.reshape(a, [2, 5])
print(a)
print(b)
c = b.reshape([1, 10])
print(b)
print(c)
# output:
# [2 7 0 7 3 0 3 2 5 2]
# [[2 7 0 7 3]
# [0 3 2 5 2]]
# [[2 7 0 7 3]
# [0 3 2 5 2]]
# [[2 7 0 7 3 0 3 2 5 2]]
numpy.ndarray.resize(a, new_shape)
把指定的数组改变形状,但元素个数可变,不足补0。numpy.resize作为含磺素使用时,不会对原始数组进行修改,返回新的结果数组;array.resize作为方法使用时,无返回值,会对原始多维数组进行修改。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, 10)
print(a)
# 不修改原始数组
b = numpy.resize(a, [3, 4])
print(a)
print(b)
# 修改原始数组
a.resize([3, 4])
print(a)
# output:
# [0 0 7 5 7 1 3 8 1 9]
# [0 0 7 5 7 1 3 8 1 9]
# [[0 0 7 5]
# [7 1 3 8]
# [1 9 0 0]]
# [[0 0 7 5]
# [7 1 3 8]
# [1 9 0 0]]
三、NumPy 数组迭代
1、迭代数组简介
NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
import numpy
if __name__ == "__main__":
a = numpy.arange(0, 12).reshape([2, 6])
print(a)
it = numpy.nditer(a)
for x in it:
print(x, end=", ")
print("\n")
for x in numpy.nditer(a.T.copy(order='C')):
print(x, end=", ")
# output:
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]]
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
#
# 0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11,
2、遍历顺序控制
for x in numpy.nditer(arr, order='F'):
pass
for x in numpy.nditer(arr.T, order='C'):
pass
order='F',表示Fortran order,即列序优先;order='C',表示C order,即行序优先。
3、遍历修改数组元素值
nditer 对象有一个可选参数 op_flags。 默认情况下,nditer将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 read-write 或者 write-only 的模式。
import numpy
if __name__ == "__main__":
a = numpy.arange(0, 12).reshape([2, 6])
print(a)
it = numpy.nditer(a, op_flags=["readwrite"])
for x in it:
x[...] = x**2
print(a)
# output:
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]]
# [[ 0 1 4 9 16 25]
# [ 36 49 64 81 100 121]]
4、外部循环
nditer的构造器拥有flags参数,可以接受下列值:
c_index:可以跟踪 C 顺序的索引
f_index:可以跟踪 Fortran 顺序的索引
multi-index:每次迭代可以跟踪一种索引类型
external_loop:给出的值是具有多个值的一维数组,而不是零维数组
5、广播迭代
如果两个数组是可广播的,nditer 组合对象能够同时迭代。 假设数组 a 的维度为 3X4,数组 b 的维度为 1X4 ,则使用迭代器(数组 b 被广播到 a 的大小)如下:
import numpy
if __name__ == "__main__":
a = numpy.arange(0, 12).reshape([3, 4])
print(a)
b = [11, 12, 13, 14]
it = numpy.nditer([a, b])
for x, y in it:
print("%d:%d" % (x, y), end=", ")
# output:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 0:11, 1:12, 2:13, 3:14, 4:11, 5:12, 6:13, 7:14, 8:11, 9:12, 10:13, 11:14,
四、NumPy运算
1、条件运算
numpy.where(condition, x=None, y=None)
三目运算,满足condition,为x;不满足condition,则为y。返回新的结果数组。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, 10)
print(a)
b = numpy.where(a < 5, 5, 0)
print(b)
# output:
# [8 9 6 5 3 2 9 7 3 4]
# [0 0 0 0 5 5 0 0 5 5]
2、统计函数
numpy.amax(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue)
根据指定轴统计矩阵的最大值,axis=0统计矩阵中每一列的最大值,axis=1统计矩阵中每一行的最大值,默认统计矩阵中的最大值。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 100, [3, 5])
print(a)
# 统计整个矩阵的最大值
result = numpy.amax(a)
print(result)
# 统计矩阵中每一列的最大值
result = numpy.amax(a, axis=0)
print(result)
# 统计矩阵中每一行的最大值
result = numpy.amax(a, axis=1)
print(result)
# output:
# [[85 54 46 38 98]
# [27 65 23 13 63]
# [43 68 31 42 82]]
# 98
# [85 68 46 42 98]
# [98 65 82]
numpy.amin(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue)
根据指定轴统计矩阵的最小值,axis=0统计矩阵中每一列的最小值,axis=1统计矩阵中每一行的最小值,默认统计矩阵中的最小值。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 100, [3, 5])
print(a)
# 统计整个矩阵的最小值
result = numpy.amin(a)
print(result)
# 统计矩阵中每一列的最小值
result = numpy.amin(a, axis=0)
print(result)
# 统计矩阵中每一行的最小值
result = numpy.amin(a, axis=1)
print(result)
# output:
# [[74 95 64 18 99]
# [24 61 36 2 65]
# [66 68 9 19 19]]
# 2
# [24 61 9 2 19]
# [18 2 9]
numpy.mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue)
根据指定轴统计矩阵的平均值,axis=0统计矩阵中每一列的平均值,axis=1统计矩阵中每一行的平均值,默认统计矩阵中的平均值。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 100, [3, 5])
print(a)
# 统计整个矩阵的平均值
result = numpy.mean(a)
print(result)
# 统计矩阵中每一列的平均值
result = numpy.mean(a, axis=0)
print(result)
# 统计矩阵中每一行的平均值
result = numpy.mean(a, axis=1)
print(result)
# output:
# [[38 36 68 78 58]
# [41 38 84 92 95]
# [52 86 62 94 33]]
# 63.666666666666664
# [43.66666667 53.33333333 71.33333333 88. 62. ]
# [55.6 70. 65.4]
numpy.std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue)
根据指定轴统计矩阵的方差,axis=0统计矩阵中每一列的方差,axis=1统计矩阵中每一行的方差,默认统计矩阵中的方差。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 100, [3, 5])
print(a)
# 统计整个矩阵的方差
result = numpy.std(a)
print(result)
# 统计矩阵中每一列的方差
result = numpy.std(a, axis=0)
print(result)
# 统计矩阵中每一行的方差
result = numpy.std(a, axis=1)
print(result)
# output:
# [[80 68 47 51 2]
# [75 38 97 70 98]
# [57 66 64 17 70]]
# 25.442746183015178
# [ 9.87702159 13.69509239 20.7578633 21.92411154 40.30991055]
# [26.59774427 21.9326241 19.36388391]
numpy.sum(a, axis=None, dtype=None, out=None, keepdims=np._NoValue, initial=np._NoValue)
根据指定轴统计矩阵的求和,axis=0统计矩阵中每一列的求和,axis=1统计矩阵中每一行的求和,默认统计矩阵中的求和。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 100, [3, 5])
print(a)
# 统计整个矩阵的求和
result = numpy.sum(a)
print(result)
# 统计矩阵中每一列的求和
result = numpy.sum(a, axis=0)
print(result)
# 统计矩阵中每一行的求和
result = numpy.sum(a, axis=1)
print(result)
# output:
# [[87 16 90 96 83]
# [23 96 52 76 39]
# [46 5 55 91 66]]
# 921
# [156 117 197 263 188]
# [372 286 263]
numpy.ptp()()ptp(a, axis=None, out=None, keepdims=np._NoValue)
计算数组中元素最大值与最小值的差(最大值 - 最小值)
numpy.percentile(a, q, axis=None, out=None,
overwrite_input=False, interpolation='linear', keepdims=False)
百分位数是统计中使用的度量,表示小于这个值的观察值的百分比
参数a,输入数组
参数q,要计算的百分位数,在 0 ~ 100 之间
参数axis: 沿着计算百分位数的轴numpy.median(a, axis=None, out=None, overwrite_input=False, keepdims=False)
用于计算数组 a 中元素的中位数(中值)numpy.average(a, axis=None, weights=None, returned=False)
根据各自的权重计算数组中元素的加权平均值。
参数a,输入数组
参数axis,指定轴
weights:权重
import numpy
if __name__ == "__main__":
a = numpy.array([10, 20, 30, 40])
print(numpy.average(a))
weight = [1, 2, 3, 4]
result = numpy.average(a, weights=weight)
print(result)
result = numpy.average(a, weights=weight, returned=True)
print(result)
# output:
# 25.0
# 30.0
# (30.0, 10.0)
3、算术运算
数组与数的运算包括加、减、乘、除、取整、取模,可以使用函数也可以使用操作符。numpy.add(x1, x2, *args, **kwargs)
将x1和x2相加,并将结果返回。numpy.subtract(x1, x2, *args, **kwargs)
将x1和x2相减,并将结果返回。numpy.multiply(x1, x2, *args, **kwargs)
将x1和x2相乘,并将结果返回。numpy.divide(x1, x2, *args, **kwargs)
将x1和x2相除,并将结果返回。numpy.mod(*args, **kwargs)
计算输入数组中相应元素的相除后的余数numpy.power(x1, x2, *args, **kwargs)
将x1作为底数,计算x1的x2次幂。numpy.reciprocal(x, *args, **kwargs)
返回x的倒数。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, [2, 5])
print(a)
result = a + 5
print(result)
result = a - 5
print(result)
result = a * 5
print(result)
result = a / 5
print(result)
result = a // 5
print(result)
result = a % 5
print(result)
# output:
# [[9 6 6 7 9]
# [0 3 2 4 8]]
# [[14 11 11 12 14]
# [ 5 8 7 9 13]]
# [[ 4 1 1 2 4]
# [-5 -2 -3 -1 3]]
# [[45 30 30 35 45]
# [ 0 15 10 20 40]]
# [[1.8 1.2 1.2 1.4 1.8]
# [0. 0.6 0.4 0.8 1.6]]
# [[1 1 1 1 1]
# [0 0 0 0 1]]
# [[4 1 1 2 4]
# [0 3 2 4 3]]
数组间运算包括加、减、乘、除,但两个数组的shape必须一样。numpy.intersect1d(ar1, ar2, assume_unique=False, return_indices=False)
查找两个数组中的相同元素。numpy.setdiff1d(ar1, ar2, assume_unique=False)
查找在数组a中不在数组b中的元素。numpy.union1d(ar1, ar2)
查找两个数组的并集元素
import numpy
if __name__ == "__main__":
a = numpy.random.randint(1, 10, [2, 5])
b = numpy.random.randint(1, 10, [2, 5])
print(a)
print(b)
result = a + b
print(result)
result = a - b
print(result)
result = a * b
print(result)
result = a / b
print(result)
# 求交
result = numpy.intersect1d(a, b)
print(result)
# 求差
result = numpy.setdiff1d(a, b)
print(result)
# 求并
result = numpy.union1d(a, b)
print(result)
# output:
# [[2 8 4 1 5]
# [1 9 4 4 7]]
# [[9 2 4 7 3]
# [7 7 3 2 1]]
# [[11 10 8 8 8]
# [ 8 16 7 6 8]]
# [[-7 6 0 -6 2]
# [-6 2 1 2 6]]
# [[18 16 16 7 15]
# [ 7 63 12 8 7]]
# [[0.22222222 4. 1. 0.14285714 1.66666667]
# [0.14285714 1.28571429 1.33333333 2. 7. ]]
# [1 2 4 7 9]
# [5 8]
# [1 2 3 4 5 7 8 9]
4、广播
广播(Broadcast)是 numpy 对不同shape的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。
如果两个数组进行运算时必须要求shape相同,当运算中的 2 个数组的shape不同时,numpy 将自动触发广播机制。
广播机制的规则如下:
(1)让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
(2)输出数组的形状是输入数组形状的各个维度上的最大值。
(3)如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
(4)当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。
如果条件不满足,抛出 "ValueError: frames are not aligned" 异常。
4x3 的二维数组与1x 3 的一维数组相加,等效于把一维数组 在二维上重复 4 次再运算。
import numpy
if __name__ == "__main__":
a = numpy.array([[0, 0, 0],
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]])
b = numpy.array([1, 2, 3])
result = a + b
print(result)
# output:
# [[ 1 2 3]
# [11 12 13]
# [21 22 23]
# [31 32 33]]
5、矩阵运算
numpy.dot(a, b, out=None)
矩阵点乘,(M行,N列)*(N行,Z列)=(M行,Z列)
import numpy
if __name__ == "__main__":
# 成绩,期末考试成绩和平常作业成绩组成
score = numpy.array([[100, 87], [88, 87], [78, 80], [65, 89]])
# 权重因子,期末成绩占70%,平时作业成绩占30%
q = numpy.array([[0.7], [0.3]])
result = numpy.dot(score, q)
print(result)
# output:
# [[96.1]
# [87.7]
# [78.6]
# [72.2]]
numpy.vstack(tup)
矩阵垂直拼接(两个矩阵列数必须相同,行数随意),参数tup为数组的元组。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, [3, 6])
b = numpy.random.randint(0, 10, [2, 6])
print(a)
print(b)
result = numpy.vstack((a, b))
print(result)
# output:
# [[2 5 7 6 2 8]
# [1 7 2 2 0 0]
# [1 1 5 8 3 4]]
# [[6 5 3 4 9 9]
# [4 3 2 4 2 9]]
# [[2 5 7 6 2 8]
# [1 7 2 2 0 0]
# [1 1 5 8 3 4]
# [6 5 3 4 9 9]
# [4 3 2 4 2 9]]
numpy.hstack(tup)
矩阵水平拼接(两个矩阵行数必须相同,列数随意),参数tup为数组的元组。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, [2, 3])
b = numpy.random.randint(0, 10, [2, 4])
c = numpy.random.randint(0, 10, [2, 5])
print(a)
print(b)
print(c)
result = numpy.hstack((a, b, c))
print(result)
# output:
# [[5 4 2]
# [3 3 3]]
# [[7 0 7 7]
# [3 5 0 2]]
# [[8 6 3 0 2]
# [3 9 7 4 1]]
# [[5 4 2 7 0 7 7 8 6 3 0 2]
# [3 3 3 3 5 0 2 3 9 7 4 1]]
numpy.delete(arr, obj, axis=None)
矩阵删除,参数arr为数组;参数obj为要删除的对象;参数axis为轴,axis=0表示删除行,axis=1表示删除列,默认删除行和列。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, [10, 10])
print(a)
result = numpy.delete(a, [0, 2])
print(result)
result = numpy.delete(a, [0, 2], axis=0)
print(result)
result = numpy.delete(a, [0, 2], axis=1)
print(result)
# output:
# [[8 0 7 2 1 6 8 9 5 5]
# [6 3 1 6 5 5 5 6 1 8]
# [2 0 8 5 0 2 4 7 6 3]
# [8 8 3 9 3 1 9 6 4 2]
# [2 1 5 1 2 9 9 5 9 9]
# [2 2 8 1 5 8 6 7 2 9]
# [9 6 2 7 6 0 1 5 1 8]
# [7 9 8 7 8 6 8 5 1 6]
# [1 9 6 9 4 1 7 7 0 9]
# [7 1 8 8 7 1 0 2 7 2]]
# [0 2 1 6 8 9 5 5 6 3 1 6 5 5 5 6 1 8 2 0 8 5 0 2 4 7 6 3 8 8 3 9 3 1 9 6 4
# 2 2 1 5 1 2 9 9 5 9 9 2 2 8 1 5 8 6 7 2 9 9 6 2 7 6 0 1 5 1 8 7 9 8 7 8 6
# 8 5 1 6 1 9 6 9 4 1 7 7 0 9 7 1 8 8 7 1 0 2 7 2]
# [[6 3 1 6 5 5 5 6 1 8]
# [8 8 3 9 3 1 9 6 4 2]
# [2 1 5 1 2 9 9 5 9 9]
# [2 2 8 1 5 8 6 7 2 9]
# [9 6 2 7 6 0 1 5 1 8]
# [7 9 8 7 8 6 8 5 1 6]
# [1 9 6 9 4 1 7 7 0 9]
# [7 1 8 8 7 1 0 2 7 2]]
# [[0 2 1 6 8 9 5 5]
# [3 6 5 5 5 6 1 8]
# [0 5 0 2 4 7 6 3]
# [8 9 3 1 9 6 4 2]
# [1 1 2 9 9 5 9 9]
# [2 1 5 8 6 7 2 9]
# [6 7 6 0 1 5 1 8]
# [9 7 8 6 8 5 1 6]
# [9 9 4 1 7 7 0 9]
# [1 8 7 1 0 2 7 2]]
numpy.append(arr, values, axis=None)
矩阵添加,参数arr为数组;参数values为要追加的对象;参数axis为轴,axis=0表示追加到行,axis=1表示追加到列,默认添加到所有数组元素的尾部。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, [3, 8])
print(a)
result = numpy.append(a, [0, 2, 3])
print(result)
# 追加一行
result = numpy.append(a, [[9, 9, 9, 9, 9, 9, 9, 9]], axis=0)
print(result)
# 追加一列
result = numpy.append(a, [[9], [9], [9]], axis=1)
print(result)
# output:
# [[3 0 2 8 1 2 2 6]
# [4 2 5 7 3 4 6 9]
# [3 3 2 6 2 7 9 9]]
# [3 0 2 8 1 2 2 6 4 2 5 7 3 4 6 9 3 3 2 6 2 7 9 9 0 2 3]
# [[3 0 2 8 1 2 2 6]
# [4 2 5 7 3 4 6 9]
# [3 3 2 6 2 7 9 9]
# [9 9 9 9 9 9 9 9]]
# [[3 0 2 8 1 2 2 6 9]
# [4 2 5 7 3 4 6 9 9]
# [3 3 2 6 2 7 9 9 9]]
numpy.insert(arr, obj, values, axis=None)
矩阵插入,参数arr为数组,obj为插入位置索引,values为插入的值,参数axis为轴,axis=0表示插入到行,axis=1表示插入到列,默认插入到所有数组元素的序列的指定位置。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, [3, 8])
print(a)
result = numpy.insert(a, 0, [11, 12, 13])
print(result)
result = numpy.insert(a, 0, [11, 12, 13, 14, 15, 16, 17, 18], axis=0)
print(result)
result = numpy.insert(a, 0, [11, 12, 13], axis=1)
print(result)
# output:
# [[5 0 0 8 9 8 5 8]
# [3 0 2 3 5 1 4 2]
# [4 2 4 0 6 5 6 1]]
# [11 12 13 5 0 0 8 9 8 5 8 3 0 2 3 5 1 4 2 4 2 4 0 6
# 5 6 1]
# [[11 12 13 14 15 16 17 18]
# [ 5 0 0 8 9 8 5 8]
# [ 3 0 2 3 5 1 4 2]
# [ 4 2 4 0 6 5 6 1]]
# [[11 5 0 0 8 9 8 5 8]
# [12 3 0 2 3 5 1 4 2]
# [13 4 2 4 0 6 5 6 1]]
6、位运算
bitwise_and对数组中整数的二进制形式执行位与运算。
bitwise_or对数组中整数的二进制形式执行位与运算。
invert对数组中整数进行位取反运算,即 0 变成 1,1 变成 0。
left_shift将数组元素的二进制形式向左移动到指定位置,右侧附加相等数量的 0。
right_shift将数组元素的二进制形式向右移动到指定位置,左侧附加相等数量的 0。
import numpy
if __name__ == "__main__":
a = numpy.arange(0, 12).reshape([3, 4])
print(a)
b = [11, 12, 13, 14]
print(b)
result = numpy.bitwise_and(a, b)
print(result)
result = numpy.bitwise_or(a, b)
print(a)
result = numpy.invert(a)
print(result)
result = numpy.left_shift(a, 2)
print(result)
result = numpy.right_shift(result, 2)
print(result)
# output:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# [11, 12, 13, 14]
# [[ 0 0 0 2]
# [ 0 4 4 6]
# [ 8 8 8 10]]
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# [[ -1 -2 -3 -4]
# [ -5 -6 -7 -8]
# [ -9 -10 -11 -12]]
# [[ 0 4 8 12]
# [16 20 24 28]
# [32 36 40 44]]
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
7、字符串处理
NumPy中对字符串的处理基于 Python 内置库中的标准字符串函数,对dtype为 numpy.string_
或numpy.unicode_
的数组执行向量化字符串操作,相应函数在字符数组类(numpy.char)中定义。numpy.char.add()
依次对两个数组的元素进行字符串连接。numpy.char.multiply()
对数组的数值执行多次重度连接。numpy.char.center()
将数组的数值字符串居中,并使用指定字符在左侧和右侧进行填充。numpy.char.capitalize()
将数组数值字符串的第一个字母转换为大写:numpy.char.title()
将数组数值字符串的每个单词的第一个字母转换为大写:numpy.char.lower()
对数组的每个元素转换为小写,对每个元素调用 str.lower。numpy.char.upper()
对数组的每个元素转换为大写,对每个元素调用 str.upper。numpy.char.split()
通过指定分隔符对字符串进行分割,并返回数组。默认情况下,分隔符为空格。numpy.char.splitlines()
以换行符作为分隔符来分割字符串,并返回数组。numpy.char.strip()
用于移除开头或结尾处的特定字符。numpy.char.join()
通过指定分隔符来连接数组中的元素或字符串numpy.char.replace()
使用新字符串替换字符串中的所有子字符串。numpy.char.encode()
对数组中的每个元素调用 str.encode 函数。 默认编码是 utf-8,可以使用标准 Python 库中的编×××。numpy.char.decode()
对编码的元素进行 str.decode() 解码。
8、数学函数
NumPy 包含大量的各种数学运算的函数,包括三角函数,算术运算的函数,复数处理函数等。numpy.sin(x, *args, **kwargs)
计算x的正弦并返回,x为弧度值numpy.arcsin(x, *args, **kwargs)
计算x的反正弦并返回,返回为弧度值numpy.cos(x, *args, **kwargs)
计算x的余弦并返回,x为弧度值numpy.arccos(x, *args, **kwargs)
计算x的反余弦并返回,返回为弧度值numpy.tan(x, *args, **kwargs)
计算x的正切并返回,x为弧度值numpy.arctan(x, *args, **kwargs)
计算x的反正切并返回,返回为弧度值numpy.degrees(x, *args, **kwargs)
计算x的角度值并返回,x为弧度值
import numpy
if __name__ == "__main__":
angles = numpy.array([0, 45, 60, 90, 120, 150, 180])
result = numpy.sin(angles * numpy.pi / 180)
print(result)
result = numpy.arcsin(result)
print(numpy.degrees(result))
result = numpy.cos(angles * numpy.pi / 180)
print(result)
result = numpy.arccos(result)
print(result)
result = numpy.tan(angles * numpy.pi / 180)
print(result)
result = numpy.arctan(result)
print(result)
numpy.around(a, decimals=0, out=None)
返回指定数字的四舍五入值。
参数a表示数值,可以为数组
参数decimals表示舍入的小数位数。 默认值为0。 如果为负,整数将四舍五入到小数点左侧的位置numpy.floor(x, *args, **kwargs)
返回数值x的下舍整数numpy.ceil(x, *args, **kwargs)
返回数值x的上入整数。
import numpy
if __name__ == "__main__":
a = numpy.array([1.2, 3.14, -2.5, 9.8])
print(a)
result = numpy.around(a,decimals=1)
print(result)
result = numpy.floor(a)
print(result)
result = numpy.ceil(a)
print(result)
# output:
# [ 1.2 3.14 -2.5 9.8 ]
# [ 1.2 3.1 -2.5 9.8]
# [ 1. 3. -3. 9.]
# [ 2. 4. -2. 10.]
9、排序过滤
numpy.sort(a, axis=-1, kind='quicksort', order=None)
参数a为要排序的数组
参数axis,沿着axis排序数组的轴,如果没有数组会被展开,沿着最后的轴排序, axis=0 按列排序,axis=1 按行排序。
参数kind,用于指定排序算法,'quicksort'(快速排序),'mergesort'(归并排序),'heapsort'(堆排序)。
order: 如果数组包含字段,则是要排序的字段。
numpy.sort()作为函数使用时,不修改被排序的原始array;array.sort()作为方法使用时,会对原始array修改为排序后数组array。
NumPy 提供了多种排序的方法,不同的排序算法的特征在于执行速度,最坏情况性能,所需的工作空间和算法的稳定性。快速排序最坏效率O(n^2),是不稳定排序算法,最快的排序算法;归并排序最坏效率为O(n*log(n))
,是稳定的排序算法;堆排序最坏效率为O(n*log(n))
,是不稳定排序算法。
import numpy
if __name__ == "__main__":
a = numpy.random.randint(0, 10, 10)
print(a)
# 排序不会改变原始数组
b = numpy.sort(a)
print(a)
print(b)
# 排序改变数组对象
a.sort()
print(a)
# output:
# [3 9 4 7 3 7 9 0 6 3]
# [3 9 4 7 3 7 9 0 6 3]
# [0 3 3 3 4 6 7 7 9 9]
# [0 3 3 3 4 6 7 7 9 9]
numpy.argsort(a, axis=-1, kind='quicksort', order=None)
返回数组值从小到大的索引值。
参数a为输入数组
参数axis,沿着axis排序数组的轴,如果没有数组会被展开,沿着最后的轴排序, axis=0 按列排序,axis=1 按行排序。
参数kind,用于指定排序算法,'quicksort'(快速排序),'mergesort'(归并排序),'heapsort'(堆排序)。
order: 如果数组包含字段,则是要排序的字段。numpy.lexsort(keys, axis=None)
对多个序列进行排序,每一列代表一个序列,排序时优先照顾靠后的列。
import numpy
if __name__ == "__main__":
fruits = ["banana", "apple", "copper"]
dv = ["c", "a", "b"]
index = numpy.lexsort((fruits, dv))
print(index)
result = [fruits[i] + ", " + dv[i] for i in index]
print(result)
# output:
# [1 2 0]
# ['apple, a', 'copper, b', 'banana, c']
numpy.msort(a)
按第一个轴对数组a进行排序,返回排序后的数组副本,相当于
numpy.sort(a, axis=0)
numpy.sort_complex(a)
对复数按照先实部后虚部的顺序进行排序。numpy.partition(a, kth, axis=-1, kind='introselect', order=None)
指定一个数kth,对数组进行分区。小于kth的排在kth前面,大于kth的排在kth后面。numpy.argpartition(a, kth, axis=-1, kind='introselect', order=None)
可以通过关键字 kind 指定算法沿着指定轴对数组进行分区,并返回分区后的索引。
import numpy
if __name__ == "__main__":
x = [1, 4, 6, 5, 8, 4, 9]
print(x)
result = numpy.partition(x, 5)
print(result)
index = numpy.argpartition(x, 3)
print(index)
for i in index:
print(x[i], end=" ")
# output:
# [1, 4, 6, 5, 8, 4, 9]
# [4 1 4 5 6 8 9]
# [1 0 5 3 4 2 6]
# 4 1 4 5 8 6 9
numpy.extract(condition, arr)
根据某个条件从数组中抽取元素,返回满条件的元素
参数condition用于指示数组元素是否被提取。
参数arr表示输入数组。
import numpy
if __name__ == "__main__":
x = numpy.arange(9).reshape(3, 3)
print(x)
condition = numpy.mod(x, 2) == 0
print(condition)
result = numpy.extract(condition, x)
print(result)
# output:
# [[0 1 2]
# [3 4 5]
# [6 7 8]]
# [[ True False True]
# [False True False]
# [ True False True]]
# [0 2 4 6 8]
numpy.where(condition, x=None, y=None)
返回输入数组中满足给定条件的元素的索引
import numpy
if __name__ == "__main__":
x = numpy.random.randint(0, 10, 10)
print(x)
condition = numpy.where(x > 5)
print(condition)
result = x[condition]
print(result)
# output:
# [1 7 5 5 9 9 7 0 2 8]
# (array([1, 4, 5, 6, 9]),)
# [7 9 9 7 8]
numpy.nonzero(a)
返回输入数组中非零元素的索引。
import numpy
if __name__ == "__main__":
x = numpy.random.randint(0, 10, 10)
print(x)
y = numpy.nonzero(x)
print(y)
result = x[y]
print(result)
# output:
# [4 9 0 5 0 3 5 9 8 2]
# (array([0, 1, 3, 5, 6, 7, 8, 9]),)
# [4 9 5 3 5 9 8 2]
numpy.argmax(a, axis=None, out=None)
沿给定轴返回数组中最大元素的索引numpy.argmin(a, axis=None, out=None)
沿给定轴返回数组中最小元素的索引
import numpy
if __name__ == "__main__":
x = numpy.random.randint(0, 10, 10)
print(x)
y = numpy.argmax(x)
print(y)
result = x[y]
print(result)
print(numpy.max(x))
y = numpy.argmin(x)
print(y)
result = x[y]
print(result)
print(numpy.min(x))
# output:
# [3 4 7 3 6 9 4 3 4 4]
# 5
# 9
# 9
# 0
# 3
# 3
10、字节交换
计算机中,多字节对象通常被存储为连续的字节序列。字节顺序是跨越多字节的程序对象的存储规则。
大端模式:数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,大端模式的地址由小向大增加,而数据从高位往低位放。
小端模式:数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,小端模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。numpy.ndarray.byteswap(self, inplace=False)
将 ndarray 中每个元素中的字节进行大小端转换。
import numpy
if __name__ == "__main__":
x = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=numpy.int16)
print(x)
for i in x:
print(hex(i), end=" ")
print("\n")
result = x.byteswap(True)
for i in result:
print(hex(i), end=" ")
# output:
# [1 2 3 4 5 6 7 8 9]
# 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9
#
# 0x100 0x200 0x300 0x400 0x500 0x600 0x700 0x800 0x900
11、副本和视图
副本是一个数据的完整的拷贝,如果对副本进行修改,不会影响到原始数据,物理内存不在同一位置。
视图是数据的引用,通过视图可访问、操作原有数据,但原有数据不会产生拷贝。如果对视图进行修改,会影响到原始数据,物理内存在同一位置。
在 Python 中,对象赋值本质是对象的引用。当创建一个对象,然后将其赋给另一个变量时,Python并没有拷贝对象,而只是拷贝对象的引用,称为浅拷贝。
在 Python中,当进行赋值操作时,为使两个变量互不影响,可以使用 copy 模块中的 deepcopy 方法,称为深拷贝。
通常,切片操作会返回原数据的视图,调用 ndarray 的 view() 函数会产生视图;切片操作中调用deepCopy()函数会产生副本,调用 ndarray 的 copy() 函数会产生副本。
简单的赋值不会创建数组对象的副本。
import numpy
if __name__ == "__main__":
x = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=numpy.int16)
y = x
print(id(x))
print(id(y))
y.shape = [3, 3]
print(x)
print(y)
# output:
# 140621988193024
# 140621988193024
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
ndarray.view() 方会创建一个新的数组对象,view方法创建的新数组的维数更改不会更改原始数据的维数。
import numpy
if __name__ == "__main__":
x = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=numpy.int16)
y = x.view()
print(id(x))
print(id(y))
y.shape = [3, 3]
print(x)
print(y)
# output:
# 140025825882960
# 140025825245024
# [1 2 3 4 5 6 7 8 9]
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
使用切片创建视图修改数据会影响到原始数组,视图虽然指向原数据,但会创建新的对象。
import numpy
if __name__ == "__main__":
x = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=numpy.int16)
a = x[2:]
b = x[5:]
print(id(x))
print(id(a))
print(id(b))
print(a)
print(b)
a[0] = 11
b[0] = 12
print(a)
print(b)
print(x)
# output:
# 139764960379728
# 139764959741792
# 139764836999776
# [3 4 5 6 7 8 9]
# [6 7 8 9]
# [11 4 5 12 7 8 9]
# [12 7 8 9]
# [ 1 2 11 4 5 12 7 8 9]
ndarray.copy() 函数创建一个副本, 对副本数据进行修改,不会影响到原始数据。
import numpy
if __name__ == "__main__":
x = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=numpy.int16)
y = x.copy()
print(id(x))
print(id(y))
y[0] = 10
print(x)
print(y)
# output:
# 139690155443024
# 139690154805088
# [1 2 3 4 5 6 7 8 9]
# [10 2 3 4 5 6 7 8 9]
numpy.copy(a, order='K')
创建给定数组a的一个副本,可以作为数组的方法使用。
import numpy
if __name__ == "__main__":
array_normal = numpy.random.normal(loc=1.75, scale=0.1, size=[5, 5])
print(array_normal)
b = array_normal[1, 2].copy()
print(b)
# 截取第1行至第3行(不包括第3行),第2列至第4列(不包括第4列)的数据
c = numpy.copy(array_normal[1:3, 2:4])
print(c)
# output:
# [[1.71679806 1.85533715 1.74308905 1.75119872 1.79173827]
# [1.65084866 1.8366689 1.72241261 1.71965308 1.58003833]
# [1.86165973 1.84692966 1.73746162 1.81721825 1.75710235]
# [1.95509949 1.90046488 1.71245928 2.00848233 1.73175004]
# [1.64957638 1.80259583 1.84005861 1.85791674 1.825334 ]]
# 1.7224126132538562
# [[1.72241261 1.71965308]
# [1.73746162 1.81721825]]
五、NumPy.matlib矩阵模块
1、matlib模块简介
NumPy 中包含了一个矩阵库 numpy.matlib,numpy.matlib模块中的函数返回的是一个矩阵,而不是 ndarray 对象。
一个 mxn的矩阵是一个由m行(row)和n列(column)元素排列成的矩形阵列,矩阵里的元素可以是数字、符号或数学式。
2、矩阵创建
numpy.matlib.empty(shape, dtype, order)
创建矩阵,填充随机数据。
shape参数,定义新矩阵形状的整数或整数元组。
dtype参数,可选,数据类型。
order参数,可选项为C(行序优先) 或者 F(列序优先)。
矩阵是二维的,而 ndarray 是一个 n 维数组。 矩阵与ndarray是可互换的。numpy.matlib.zeros(shape, dtype=None, order='C'):
创建一个以 0 填充的矩阵。numpy.matlib.ones(shape, dtype=None, order='C'):
创建一个以 1 填充的矩阵。numpy.matlib.eye(n, M,k, dtype)
numpy.matlib.eye() 函数返回一个矩阵,对角线元素为 1,其他位置为零。
n: 返回矩阵的行数
M: 返回矩阵的列数,默认为 n
k: 对角线的索引
dtype: 数据类型numpy.matlib.identity(n,dtype=None)
返回给定大小的单位矩阵。
单位矩阵是个方阵,从左上角到右下角的对角线(称为主对角线)上的元素均为 1,除此以外全都为 0。numpy.matlib.rand(*args):
创建一个给定大小的矩阵,数据是随机填充的。
六、NumPy.linalg线性代数模块
1、linalg线性代数模块
NumPy 提供了线性代数函数库 linalg,linalg库包含了线性代数所需的所有功能。
2、线性代数运算
numpy.dot(a, b, out=None)
两个数组的点积,对应数组元素相乘。
a : ndarray 数组
b : ndarray 数组
out : ndarray, 可选,用来保存dot()的计算结果
对于两个一维的数组,计算两个数组对应下标元素的乘积和(数学上称为内积);对于二维数组,计算两个数组的矩阵乘积;对于多维数组,通用计算公式如下,即结果数组中的每个元素都是:数组a的最后一维上的所有元素与数组b的倒数第二位上的所有元素的乘积和。numpy.vdot(a, b)
两个向量的点积。
如果第一个参数是复数,那么其共轭复数会用于计算。 如果参数是多维数组,会被展开。numpy.inner(a, b)
返回一维数组的向量内积。对于更高的维度,返回最后一个轴上的和的乘积。numpy.matmul(x1, x2, *args, **kwargs)
返回两个数组的矩阵乘积,但如果任一参数的维数大于2,则将其视为存在于最后两个索引的矩阵的栈,并进行相应广播。
另一方面,如果任一参数是一维数组,则通过在其维度上附加 1 来将其提升为矩阵,并在乘法后被去除。
对于二维数组,它就是矩阵乘法:numpy.linalg.det(a)
计算输入矩阵的行列式。
行列式在线性代数中是非常有用的值,从方阵的对角元素计算。 对于 2×2 矩阵,是左上和右下元素的乘积与其他两个的乘积的差。
对于矩阵[[a,b],[c,d]],行列式计算为 ad-bc。 较大的方阵被认为是 2×2 矩阵的组合。numpy.linalg.solve(a, b)
求解线性矩阵方程。numpy.linalg.inv(a)
计算矩阵的乘法逆矩阵。
逆矩阵(inverse matrix):设A是数域上的一个n阶矩阵,若在相同数域上存在另一个n阶矩阵B,使得: AB=BA=E ,则称B是A的逆矩阵,而A则被称为可逆矩阵,E为单位矩阵。
七、NumPy IO操作
Numpy 可以读写磁盘上的文本数据或二进制数据。
NumPy 为 ndarray 对象引入了一个简单的文件格式:npy。
npy 文件用于存储重建 ndarray 所需的数据、图形、dtype 和其他信息。numpy.save(file, arr, allow_pickle=True, fix_imports=True)
将数组以未压缩的原始二进制格式保存在扩展名为 .npy 的文件中。
参数file,要保存的文件,扩展名为 .npy,如果文件路径末尾没有扩展名 .npy,扩展名会被自动加上。
参数arr,要保存的数组。
参数allow_pickle, 可选,布尔值,允许使用 Python pickles 保存对象数组,Python 中的 pickle 用于在保存到磁盘文件或从磁盘文件读取前,对对象进行序列化和反序列化。
参数fix_imports:,可选,为了方便 Pyhton2 中读取 Python3 保存的数据。load(file, mmap_mode=None, allow_pickle=False, fix_imports=True,encoding='ASCII')
加载npy文件
file参数,文件名。
import numpy
if __name__ == "__main__":
a = numpy.arange(0, 12).reshape([3, 4])
numpy.save("outfile.npy", a)
b = numpy.load("outfile.npy")
print(b)
# output:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
numpy.savez(file, *args, **kwds)
将多个数组以未压缩的原始二进制格式保存在扩展名为 .npz 的文件中。
参数file,要保存的文件,扩展名为 .npz,如果文件路径末尾没有扩展名 .npz,扩展名会被自动加上。
参数args,要保存的数组,可以使用关键字参数为数组起一个名字,非关键字参数传递的数组会自动起名为 arr_0, arr_1。
参数kwds:,要保存的数组使用关键字名称。
import numpy
if __name__ == "__main__":
a = numpy.array([[1, 2, 3], [4, 5, 6]])
b = numpy.arange(0, 1.0, 0.1)
c = numpy.sin(b)
# c 使用了关键字参数 sin_array
numpy.savez("outfile.npz", a, b, sin_array=c)
r = numpy.load("outfile.npz")
print(r.files) # 查看各个数组名称
print(r["arr_0"])
print(r["arr_1"])
print(r["sin_array"])
# output:
# ['sin_array', 'arr_0', 'arr_1']
# [[1 2 3]
# [4 5 6]]
# [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
# [0. 0.09983342 0.19866933 0.29552021 0.38941834 0.47942554
# 0.56464247 0.64421769 0.71735609 0.78332691]
numpy.loadtxt(file, dtype=int, delimiter=' ')
以简单的文本文件格式读取数据。
参数file为要加载的文件名
参数dtype为数据类型
参数 delimiter 可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等。numpy.savetxt(file, a, fmt="%d", delimiter=",")
以简单的文本文件格式存储数据。
参数file为要加载的文件名
参数a为要保存的数组
参数fmt为格式化字符串
参数 delimiter 可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等。
import numpy
if __name__ == "__main__":
b = numpy.arange(0, 1.0, 0.1)
c = numpy.sin(b)
numpy.savetxt("outfile.txt", (b, c))
r = numpy.loadtxt("outfile.txt")
print(r)
# output:
# [[0. 0.1 0.2 0.3 0.4 0.5
# 0.6 0.7 0.8 0.9 ]
# [0. 0.09983342 0.19866933 0.29552021 0.38941834 0.47942554
# 0.56464247 0.64421769 0.71735609 0.78332691]]