Python之NumPy详解

NumPy(Numerical Python) 是Python语言的一个数值计算扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

NumPy的前身Numeric最早是由Jim Hugunin与其它协作者共同开发,2005年,Travis Oliphant在Numeric中结合了另一个同性质的程序库Numarray的特色,并加入了其它扩展而开发了NumPyNumPy为开放源代码并且由许多协作者共同维护开发。

NumPy是一个运行速度非常快的数学库,主要用于数组计算,包含:

  • 一个强大的N维数组对象ndarray,对数组进行函数运算;
  • 数值积分;
  • 广播功能函数;
  • 整合C/C++/Fortran代码的工具;
  • 线性代数、傅里叶变换、随机数生成等功能。

NumPy通常与SciPy(Scientific Python)和Matplotlib(绘图库)一起使用, 这种组合广泛用于替代MatLab,是一个强大的科学计算环境,有助于我们通过Python学习数据科学或者机器学习。

SciPy是一个开源的Python算法库和数学工具包。SciPy包含的模块有最优化线性代数积分插值特殊函数快速傅里叶变换信号处理和图像处理常微分方程求解和其他科学与工程中常用的计算。

MatplotlibPython编程语言及其数值数学扩展包NumPy的可视化操作界面。它为利用通用的图形用户界面工具包,如Tkinter, wxPython, QtGTK+向应用程序嵌入式绘图提供了应用程序接(API)。

标准的Python中用list(列表)保存值,可以当做数组使用,但因为列表中的元素可以是任何对象,所以浪费了CPU运算时间和内存。NumPy诞生为了弥补这些缺陷,它提供了两种基本的对象。

  • ndarray:全称(n-dimensional array object)是储存单一数据类型的多维数组;
  • ufunc:全称(universal function object)它是一种能够对数组进行处理的函数。

NumPy官网(https://numpy.org/)

SciPy官网(https://scipy.org/)

Matplotlib官网(https://matplotlib.org/)

⛄ndarray对象

NumPy最重要的一个特点是其N维数组对象ndarray,它是一系列同类型数据的集合,以0下标为开始进行集合中元素的索引。NumPy里面所有的函数都是围绕ndarray展开的。

ndarray对象是用于存放同类型元素的多维数组。

ndarray中的每个元素在内存中都有相同存储大小的区域。

ndarray内部由以下内容组成:

  • 一个指向数据(内存或内存映射文件中的一块数据)的指针;
  • 数据类型或dtype,描述在数组中的固定大小值的格子;
  • 一个表示数组形状(shape)的元组,表示各维度大小的元组;
  • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。跨度可以是负数,这样会使数组在内存中后向移动,切片中 obj[::-1]obj[:,::-1] 就是如此

ndarray的创建

numpy.array()函数创建

创建一个ndarray只需调用NumPyarray函数即可:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
# 参数说明
object	数组或嵌套的数列
dtype	数组元素的数据类型,可选
copy	对象是否需要复制,可选
order	创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok	默认返回一个与基类类型一致的数组
ndmin	指定生成数组的最小维度

# 例子
# dtype参数  
import numpy as np 
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,4,5], ndmin = 2)  
print(a)
# 输出结果
[[1 2 3 4 5]]

ndarray对象由计算机内存的连续一维部分组成,并结合索引模式,将每个元素映射到内存块中的一个位置。内存块以行顺序(C样式)或列顺序(FORTRANMatLab风格,即前述的F样式)来保存元素。

特殊函数创建
  • numpy.empty()
  • numpy.zeros()
  • numpy.ones()
  • numpy.full()
  • numpy.random.*
  • numpy.eye()

(1)numpy.empty()方法用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组:

numpy.empty(shape, dtype = float, order = 'C')

# 参数说明
shape	数组形状,可以是int或是元组,也可以是列表,如:(34or 3 or [3,4]
dtype	数据类型,可选
order	有"C""F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。

# 例子
import numpy as np 
x = np.empty([3,2], dtype = int) 
print(x)
# 输出结果
[[ 6917529027641081856  5764616291768666155]
 [ 6917529027641081859 -5764598754299804209]
 [          4497473538      844429428932120]]

注意:数组元素为随机值,因为它们未初始化。

(2)numpy.zeros()创建指定大小的数组,数组元素以0来填充:

numpy.zeros(shape, dtype = float, order = 'C')

# 参数说明
shape	数组形状
dtype	数据类型,可选
order	'C'用于C的行数组,或者'F'用于FORTRAN的列数组

# 例子
import numpy as np
# 默认为浮点数
x = np.zeros(5) 
print(x)
# 设置类型为整数
y = np.zeros((5,), dtype = int) 
print(y)
# 自定义类型
z = np.zeros((2,2), dtype = [('x','i4'), ('y','i4')])  
print(z)
# 输出结果
[0. 0. 0. 0. 0.]
[0 0 0 0 0]
[[(0, 0) (0, 0)]
 [(0, 0) (0, 0)]]

(3)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]]

(4)numpy.full()创建指定形状的数组,数组元素以fill_value来填充:

numpy.full(shape, fill_value, dtype=None, order='C')
# 参数说明
shape	数组形状
fill_value	填充值(标量或类似数组)
dtype	数据类型,可选
order	'C' 用于C的行数组,或者'F'用于 FORTRAN 的列数组

# 例子
import numpy as np
a = np.full((2,2),np.pi)
b = np.full((2,2),1)
c = np.full((2,2),[1,2])
print(a)
print(b)
print(c)
# 输出结果
[[3.14159265 3.14159265]
 [3.14159265 3.14159265]]
[[1 1]
 [1 1]]
[[1 2]
 [1 2]]

(5)numpy.random.*

Python中,有两个模块可以产生随机数:

  • python自带random包: 提供一些基本的随机数产生函数,可满足基本需要;
  • numpy.random:提供一些产生随机数的高级函数,满足高级需求。
from numpy import random
# 例子1 Numpy创建标准正态分布数组
# 创建randn(size)服从X~N(0,1)的正态分布随机数组
a = random.randn(2,3)
print(a)
# 输出结果
[[-0.75827863 -0.0696867  -2.23015832]
 [-0.57744225 -0.20939873 -1.2368758 ]]

# 例子2 Numpy创建随机分布整数型数组
# 利用randint([low,high],size)创建一个整数型指定范围在[low.high]之间的数组
b=random.randint(100,300,(4,4))
print(b)
# 输出结果
[[130 136 156 208]
 [221 241 124 244]
 [203 266 160 222]
 [142 183 203 215]]

(6)numpy.eye()

import numpy as np
# 创建对角矩阵数组
a = np.eye(5)
print(a)
# 输出结果
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]
NumPy从已有的数组创建数组
  • numpy.asarray()
  • numpy.frombuffer()
  • numpy.fromiter()

(1)numpy.asarray()

numpy.asarray()类似numpy.array(),但numpy.asarray()参数只有三个。

numpy.asarray(a, dtype = None, order = None)
# 参数说明
a	任意形式的输入参数,可以是:列表、列表的元组、元组、元组的元组、元组的列表、多维数组
dtype	数据类型,可选
order	可选,有"C""F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。

import numpy as np
# 将列表转换为ndarray
x = [1,2,3]
a1 = np.asarray(x)  
a2 = np.asarray(x, dtype = float)  
print(a1)
print(a2)
# 将元组转换为ndarray
y = (1,2,3) 
b = np.asarray(y)  
print(b)
# 将元组列表转换为ndarray
z = [(1,2,3),(4,5)] 
c = np.asarray(z)  
print(c)

# 输出结果
[1 2 3]
[1. 2. 3.]
[1 2 3]
[(1, 2, 3) (4, 5)]

(2)numpy.frombuffer()

numpy.frombuffer()用于实现动态数组。

numpy.frombuffer()接受buffer输入参数,以流的形式读入转化成ndarray对象。

numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
# 注意:buffer是字符串的时候,Python3默认str是Unicode类型,所以要转成bytestring在原str前加上b。
buffer	可以是任意对象,会以流的形式读入。
dtype	返回数组的数据类型,可选
count	读取的数据数量,默认为-1,读取所有数据。
offset	读取的起始位置,默认为0# Python3例子
import numpy as np 
str = b'Hello World9527' 
a = np.frombuffer(str, dtype = 'S1')  
print(a)
# 输出结果
[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd' b'9' b'5' b'2' b'7']

(3)numpy.fromiter()

numpy.fromiter()方法从可迭代对象中建立ndarray对象,返回一维数组。

numpy.fromiter(iterable, dtype, count=-1)
# 参数说明
iterable	可迭代对象
dtype	返回数组的数据类型
count	读取的数据数量,默认为-1,读取所有数据

import numpy as np 
# 使用range函数创建列表对象  
list=range(5)
it=iter(list)
print(it)
# 使用迭代器创建 ndarray 
x=np.fromiter(it, dtype = float)
print(x)

# 输出结果
<range_iterator object at 0x0000023512CA7E70>
[0. 1. 2. 3. 4.]
NumPy从数值范围创建数组
  • numpy.arange()
  • numpy.linspace()
  • numpy.logspace()

(1)numpy.arange()

numpy包中的使用arange函数创建数值范围并返回ndarray对象,函数格式如下:

numpy.arange(start, stop, step, dtype)
# 根据start与stop指定的范围以及step设定的步长,生成一个ndarray
# 参数说明
start	起始值,默认为0
stop	终止值(不包含)
step	步长,默认为1
dtype	返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。

import numpy as np
a1 = np.arange(10)
a2 = np.arange(10, dtype = float)
b = np.arange(10, 20)
c = np.arange(10, 20, 2)
print(a1)
print(a2)
print(b)
print(c)
# 输出结果
[0 1 2 3 4 5 6 7 8 9]
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
[10 11 12 13 14 15 16 17 18 19]
[10 12 14 16 18]

(2)numpy.linspace()

numpy.linspace函数用于创建一个一维数组,数组是一个等差数列构成的,格式如下:

np.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的数据类型

# 例子1
import numpy as np
a = np.linspace(1,10,10)
b = np.linspace(1,1,10)
c = np.linspace(10, 20, 5, endpoint = False) 
d = np.linspace(10, 20, 5)  
print(a)
print(b)
print(c)
print(d)
# 输出结果
[1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[10. 12. 14. 16. 18.]
[10. 12.5 15. 17.5 20. ]

# 例子2
import numpy as np
e1 = np.linspace(1,10,10,retstep= True)
e2 = np.linspace(1,10,5,retstep= True) 
print(e1)
print(e2)
# 拓展例子
f = np.linspace(1,10,10).reshape([10,1])
print(f)
#输出结果
(array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.]), 1.0)
(array([ 1.,  3.25,  5.5,  7.75, 10.]), 2.25)
[[ 1.]
 [ 2.]
 [ 3.]
 [ 4.]
 [ 5.]
 [ 6.]
 [ 7.]
 [ 8.]
 [ 9.]
 [10.]]

(3)numpy.logspace()

numpy.logspace函数用于创建一个于等比数列。格式如下:

np.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
a = np.logspace(1.0, 2.0, num = 10)
# 将对数的底数设置为 2 
b = np.logspace(0, 9, 10,base = 2)
print(a)
print(b)

# 输出结果
[ 10.          12.91549665  16.68100537  21.5443469   27.82559402
  35.93813664  46.41588834  59.94842503  77.42636827 100.        ]
[  1.   2.   4.   8.  16.  32.  64. 128. 256. 512.]
结构数组

C语言中可以通过struct关键字定义结构类型。NumPy中也有类似的结构数组。

import numpy as np
# 例子1
student = np.dtype([('name','S20'), ('age', 'i1'), ('marks', 'f4')]) 
a = np.array([('abc', 21, 50),('xyz', 18, 75)], dtype = student) 
print(a)
print(a[0])
# 输出结果
[(b'abc', 21, 50.) (b'xyz', 18, 75.)]
(b'abc', 21, 50.)

# 例子2
persontype = np.dtype({
    'names':['name','age','weight'],
    'formats':['S30','i','f']})
b = np.array([('Zhang',32,75.5),('Wang',24,65.2)],dtype = persontype)
print(b)
print(b[0])
# 输出结果
[(b'Zhang', 32, 75.5) (b'Wang', 24, 65.2)]
(b'Zhang', 32, 75.5)

Python打印字符串,前面出现b:

  • b: bytes
  • python3.x里默认的str是(py2.x里的)unicode, bytes是(py2.x)的str, b”“前缀代表的就是bytes ;
  • python2.x里, b前缀没什么具体意义, 只是为了兼容python3.x的这种写法.

NumPy数据类型对象(dtype)

NumPy支持的数据类型比Python内置的类型要多很多,基本上可以和C语言的数据类型对应上,其中部分类型对应为Python内置的类型。

名称 描述
bool_ 布尔型数据类型(True 或者 False)
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 个尾数位

数据类型对象(numpy.dtype类的实例)用来描述与数组对应的内存区域是如何使用,它描述了数据的以下几个方面:

  • 数据的类型(整数,浮点数或者Python对象)
  • 数据的大小(例如, 整数使用多少个字节存储)
  • 数据的字节顺序(小端法或大端法)
  • 在结构化类型的情况下,字段的名称、每个字段的数据类型和每个字段所取的内存块的部分
  • 如果数据类型是子数组,那么它的形状和数据类型是什么。

字节顺序是通过对数据类型预先设定 <> 来决定的。 <意味着小端法(最小值存储在最小的地址,即低位组放在最前面)。>意味着大端法(最重要的字节存储在最小的地址,即高位组放在最前面)。

dtype对象是使用以下语法构造的:

numpy.dtype(object, align, copy)
# 参数说明
object - 要转换为的数据类型对象
align - 如果为true,填充字段使其类似C的结构体。
copy - 复制dtype对象,如果为false,则是对内置数据类型对象的引用

# 例子1
import numpy as np
# 使用标量类型
dt1 = np.dtype(np.int32)
# int8, int16, int32, int64四种数据类型可以使用字符串'i1', 'i2','i4','i8'代替
dt2 = np.dtype('i4')
# 字节顺序标注
dt3 = np.dtype(')
print(dt1)
print(dt2)
print(dt4)
# 输出结果
int32
int32
int32

下面实例展示结构化数据类型的使用,类型字段和对应的实际类型将被创建。

import numpy as np
# 例子1
# 首先创建结构化数据类型
dt = np.dtype([('age',np.int8)]) 
print(dt)
# 输出结果
[('age', 'i1')]

# 例子2
# 将数据类型应用于ndarray对象
dt = np.dtype([('age',np.int8)]) 
a = np.array([(10,),(20,),(30,)], dtype = dt) 
print(a)
# 输出结果
[(10,) (20,) (30,)]

# 例子3
# 类型字段名可以用于存取实际的age列
dt = np.dtype([('age',np.int8)]) 
a = np.array([(10,),(20,),(30,)], dtype = dt) 
print(a['age'])
# 输出结果
[10 20 30]

下面的示例定义一个结构化数据类型student,包含字符串字段name,整数字段age,及浮点字段marks,并将这个dtype应用到ndarray对象。

import numpy as np
# 例子1
student = np.dtype([('name','S20'), ('age', 'i1'), ('marks', 'f4')]) 
print(student)
# 输出结果
[('name', 'S20'), ('age', 'i1'), ('marks', 'f4')]

# 例子2
a = np.array([('abc', 21, 50),('xyz', 18, 75)], dtype = student) 
print(a)
print(a[0])
# 输出结果
[(b'abc', 21, 50.) (b'xyz', 18, 75.)]
(b'abc', 21, 50.)

每个内建类型都有一个唯一定义它的字符代码,如下:

字符 对应类型
b 布尔型
i (有符号) 整型
u 无符号整型 integer
f 浮点型
c 复数浮点型
m timedelta(时间间隔)
M datetime(日期时间)
O (Python) 对象
S,a (byte-)字符串
U Unicode
V 原始数据 (void)

NumPy数组属性

NumPy数组的维数称为秩(rank),秩就是轴的数量,即数组的维度,一维数组的秩为 1,二维数组的秩为 2,以此类推。在NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是NumPy中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。

很多时候可以声明axis。axis=0,表示沿着第0轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。NumPy的数组中比较重要ndarray对象属性有:

属性 说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n行m列
ndarray.size 数组元素的总个数,相当于 .shape中n*m的值
ndarray.dtype ndarray对象的元素类型
ndarray.itemsize ndarray对象中每个元素的大小,以字节为单位
ndarray.flags ndarray对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性

ndarray.ndim用于返回数组的维数,等于秩。

import numpy as np 
# ndarray.ndim用于返回数组的维数,等于秩。
a = np.arange(24)  
print(a.ndim)             # a 现只有一个维度
# 现在调整其大小
b = a.reshape(2,4,3)       # b 现在拥有三个维度
print(b.ndim)

# 输出结果
1
3

ndarray.shape表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即ndim属性(秩)。比如,一个二维数组,其维度表示"行数"和"列数"。

ndarray.shape也可以用于调整数组大小。NumPy也提供了reshape()函数来调整数组大小。

ndarray.size数组元素的总个数,相当于 .shape中n*m的值。

import numpy as np  

# 例子1
a = np.array([[1,2,3],[4,5,6]])  
print(a.shape)
b = np.array([[1,2,3],[4,5,6]]) 
b.shape = (3,2)  
print(b)
# 输出结果
(2, 3)
[[1 2]
 [3 4]
 [5 6]]

# 例子2
c = np.array([[1,2,3],[4,5,6]]) 
d = c.reshape(3,2)  
e = np.size(c)
print(d)
# 输出结果
[[1 2]
 [3 4]
 [5 6]]
6

ndarray.itemsize以字节的形式返回数组中每一个元素的大小。

例如,一个元素类型为float64的数组itemsize属性值为 8(float64占用64个bits(位),每个字节(Byte)长度为8,所以64/8,占用8个字节),又如,一个元素类型为complex32的数组item属性为4(32/8)。

import numpy as np 
 
# 数组的dtype为int8(一个字节)  
x = np.array([1,2,3,4,5], dtype = np.int8)  
print(x.itemsize)
 
# 数组的dtype现在为float64(八个字节) 
y = np.array([1,2,3,4,5], dtype = np.float64)  
print(y.itemsize)

# 输出结果
1
8

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
UPDATEIFCOPY : False

ndarray.reshape()通常返回的是非拷贝副本,即改变返回后数组的元素,原数组对应元素的值也会改变。

import numpy as np

a = np.array([[1,2,3],[4,5,6]])
b = a.reshape((6,))
print(a)
print(b)
print("*"*20)
b[0] = 168
print(b)
print(a)

# 输出结果
[[1 2 3]
 [4 5 6]]
[1 2 3 4 5 6]
********************
[168   2   3   4   5   6]
[[168   2   3]
 [  4   5   6]]

NumPy切片和索引

(1)整数和切片索引

ndarray对象的内容可以通过索引或切片来访问和修改,与Pythonlist的切片操作一样。

ndarray数组可以基于0-n的下标进行索引,切片对象可以通过内置的slice函数,并设置start, stop及step参数进行,从原数组中切割出一个新数组。

import numpy as np
a = np.arange(10)
# 内置的slice函数
# 从索引2开始到索引7停止,间隔为2
s = slice(2,7,2)
print(a[s])
# 从索引2开始到索引7停止,间隔为2
b = a[2:7:2]
print(b)

# 输出结果
[2 4 6]
[2 4 6]

冒号:的解释:如果只放置一个参数,如[2],将返回与该索引相对应的单个元素。如果为[2:],表示从该索引开始以后的所有项都将被提取。如果使用了两个参数,如[2:7],那么则提取两个索引(不包括停止索引)之间的项。

import numpy as np
a = np.arange(10)  # [0 1 2 3 4 5 6 7 8 9]
b = a[5]
c = a[2:]
d = a[2:5]
print(a)
print(b)
print(c)
print(d)

# 输出结果
[0 1 2 3 4 5 6 7 8 9]
5
[2 3 4 5 6 7 8 9]
[2 3 4]

多维数组同样适用上述索引提取方法。

切片还可以包括省略号,来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray。

import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(a)
# 从某个索引处开始切割
print(a[1:])
print(a[...,1])   # 第2列元素
print(a[1,...])   # 第2行元素
print(a[...,1:])  # 第2列及剩下的所有元素

# 输出结果
[[1 2 3]
 [3 4 5]
 [4 5 6]]
[[3 4 5]
 [4 5 6]]
[2 4 5]
[3 4 5]
[[2 3]
 [4 5]
 [5 6]]

np.s_[:]的用法,可以参考Python中内置的 slice 函数,并设置start, stop及step参数。

Out[23]:np.s_[:]
Out[23]:slice(None, None, None)

(2)高级索引

  • 整数数组索引
  • 布尔索引
  • 花式索引
# 整数数组索引
import numpy as np 
# 获取数组中(0,0),(1,1)和(2,0)位置处的元素。
a = np.array([[1,2], [3,4], [5,6]]) 
b = a[[0,1,2],[0,1,0]]  
print(b)
# 输出结果
[1 4 5]

#**********************************
c = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])  
print(c)
rows = np.array([[0,0],[3,3]])
cols = np.array([[0,2],[0,2]])
d = c[rows,cols]
print(d)
# 输出结果
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
[[ 0  2]
 [ 9 11]]

#**********************************
# 借助切片:或…与索引数组组合。如下面例子:
e = np.array([[1,2,3],[4,5,6],[7,8,9]])
f = e[1:3,1:3]
g = e[1:3,[1,2]]
h = e[...,1:]
print(e)
print(f)
print(g)
print(h)
# 输出结果
[[1 2 3]
 [4 5 6]
 [7 8 9]]
[[5 6]
 [8 9]]
[[5 6]
 [8 9]]
[[2 3]
 [5 6]
 [8 9]]

布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。

import numpy as np 

x = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])  
print(x)
# 现在我们会打印出大于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]

#**********************************
# 使用了~(取补运算符)来过滤NaN
a = np.array([np.nan,1,2,np.nan,3,4,5])  
print(a[np.isnan(a)])
print(a[~np.isnan(a)])
# 输出结果
[1. 2. 3. 4. 5.]

#**********************************
# 从数组中过滤掉非复数元素
a = np.array([1,2+6j,5,3.5+5j])  
print(a[np.iscomplex(a)])
# 输出结果
[2.+6.j 3.5+5.j]

花式索引指的是利用整数数组进行索引。花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。

  • 对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。

  • 花式索引跟切片不一样,它总是将数据复制到新数组中;

  • 传入多个索引数组(要使用np.ix_)。np.ix_ 函数就是输入两个数组,产生笛卡尔积的映射关系。

    笛卡尔乘积是指在数学中,两个集合 X 和 Y 的笛卡尔积(Cartesian product),又称直积,表示为 X×Y,第一个对象是X的成员而第二个对象是 Y 的所有可能有序对的其中一个成员。

import numpy as np

# 一维数组只有一个轴 axis = 0,所以一维数组就在 axis = 0 这个轴上取值:
a = np.arange(1,10)
print(a)
# 一维数组读取指定下标对应的元素
print("-------读取下标对应的元素-------")
b = a[[0,6]] # 使用花式索引
print(b)
print(b[0])
print(b[1])
# 输出结果
[1 2 3 4 5 6 7 8 9]
-------读取下标对应的元素-------
[1 7]
1
7

#**********************************
# 二维数组
c = np.arange(32).reshape((8,4))
print(c)
# 二维数组读取指定下标对应的行,输出下表为4,2,1,7对应的行
print(c[[4,2,1,7]])
# 传入倒序索引数组
print(c[[-4,-2,-1,-7]])
# 输出结果
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]
 [24 25 26 27]
 [28 29 30 31]]
[[16 17 18 19]
 [ 8  9 10 11]
 [ 4  5  6  7]
 [28 29 30 31]]
[[16 17 18 19]
 [24 25 26 27]
 [28 29 30 31]
 [ 4  5  6  7]]

#**********************************
# 传入多个索引数组(要使用np.ix_),笛卡尔积
# 例如 A={a,b}, B={0,1,2},则:
# A×B={(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}
# B×A={(0,a),(0,b),(1,a),(1,b),(2,a),(2,b)}
d = np.arange(32).reshape((8,4))
print(d)
print(d[np.ix_([1,5,7,2],[0,3,1,2])])
# 输出结果
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]
 [24 25 26 27]
 [28 29 30 31]]
[[ 4  7  5  6]
 [20 23 21 22]
 [28 31 29 30]
 [ 8 11  9 10]]

⛄ufunc函数

NumPy广播(Broadcast)

广播(Broadcast)是numpy对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。如果两个数组a和b形状相同,即满足a.shape == b.shape,那么a*b的结果就是a与b数组对应位相乘。这要求维数相同,且各维度的长度相同。

import numpy as np
a = np.array([1,2,3,4]) 
b = np.array([10,20,30,40]) 
c = a * b 
print(c)
# 当运算中的2个数组的形状不同时,numpy将自动触发广播机制
d = np.array([[0,0,0],
           [10,10,10],
           [20,20,20],
           [30,30,30]])
e = np.array([0,1,2])
print(d + e)
# 4x3的二维数组与长为3的一维数组相加,等效于把数组b在二维上重复4次再运算:
f = np.array([[0,0,0],
           [10,10,10],
           [20,20,20],
           [30,30,30]])
g = np.array([1,2,3])
gg = np.tile(g,(4,1))  #重复b的各个维度
print(gg)
print(f+gg)

# 输出结果
[10 40 90 160]
[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]
[[1 2 3]
 [1 2 3]
 [1 2 3]
 [1 2 3]]
[[ 1  2  3]
 [11 12 13]
 [21 22 23]
 [31 32 33]]

广播的规则:

  • 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加1补齐。
  • 输出数组的形状是输入数组形状的各个维度上的最大值。
  • 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为1时,这个数组能够用来计算,否则出错。
  • 当输入数组的某个维度的长度为1时,沿着此维度运算时都用此维度上的第一组值。

**简单理解:**对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

  • 数组拥有相同形状。
  • 当前维度的值相等。
  • 当前维度的值有一个是1。

若条件不满足,抛出 “ValueError: frames are not aligned” 异常。

NumPy迭代数组

NumPy迭代器对象numpy.nditer提供了一种灵活访问一个或者多个数组元素的方式。

迭代器最基本的任务的可以完成对数组元素的访问。

import numpy as np
a = np.arange(6).reshape(2,3)
print('原始数组是:')
print(a)
print('\n')
print('迭代输出元素:')
for x in np.nditer(a):
    print(x, end=", ")
print('\n')

# 输出结果
原始数组是:
[[0 1 2]
 [3 4 5]]

迭代输出元素:
0, 1, 2, 3, 4, 5, 

以上实例不是使用标准C或者Fortran顺序,选择的顺序是和数组内存布局一致的,这样做是为了提升访问的效率,默认是行序优先(row-major order,或者说是 C-order)。这反映了默认情况下只需访问每个元素,而无需考虑其特定顺序。aa.T的遍历顺序是一样的,也就是他们在内存中的存储顺序也是一样的,但是a.T.copy(order = 'C')的遍历结果是不同的,那是因为它和前两种的存储方式是不一样的,默认是按行访问。

import numpy as np
 
a = np.arange(6).reshape(2,3)
for x in np.nditer(a.T):
    print(x, end=", ")
print('\n')
 
for x in np.nditer(a.T.copy(order='C')):
    print(x, end=", ")
print('\n')

# 输出结果
0, 1, 2, 3, 4, 5, 

0, 3, 1, 4, 2, 5,

(1)控制遍历顺序

  • for x in np.nditer(a, order='F'):Fortran order,即是列序优先;
  • for x in np.nditer(a.T, order='C'):C order,即是行序优先;
import numpy as np
 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print('原始数组是:') 
print(a) 
print('\n') 
print('原始数组的转置是:') 
b = a.T 
print(b) 
print('\n') 
print('以 C 风格顺序排序:') 
c = b.copy(order='C')  
print(c)
for x in np.nditer(c):  
    print (x, end=", ")
print('\n') 
print('以 F 风格顺序排序:')
c = b.copy(order='F')  
print (c)
for x in np.nditer(c):  
    print(x, end=", ")

# 输出结果
原始数组是:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]


原始数组的转置是:
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]

以 C 风格顺序排序:
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]
0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55, 

以 F 风格顺序排序:
[[ 0 20 40]
 [ 5 25 45]
 [10 30 50]
 [15 35 55]]
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 

可以通过显式设置,来强制nditer对象使用某种顺序:

import numpy as np 
 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print('原始数组是:')
print(a)
print('\n')
print('以 C 风格顺序排序:')
for x in np.nditer(a, order = 'C'):  
    print(x, end=", ")
print('\n')
print('以 F 风格顺序排序:')
for x in np.nditer(a, order = 'F'):  
    print(x, end=", ")

# 输出结果
原始数组是:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]

以 C 风格顺序排序:
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 

以 F 风格顺序排序:
0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55, 

(2)修改数组中元素的值

nditer对象有另一个可选参数op_flags。 默认情况下,nditer将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定readwrite或者writeonly的模式。

import numpy as np
 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print('原始数组是:')
print(a)
print('\n')
for x in np.nditer(a, op_flags=['readwrite']): 
    # x[...]是修改原numpy元素,x只是个拷贝。
    x[...]=2*x 
print('修改后的数组是:')
print(a)

# 输出结果
原始数组是:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]

修改后的数组是:
[[  0  10  20  30]
 [ 40  50  60  70]
 [ 80  90 100 110]]

(3)使用外部循环

nditer类的构造器拥有flags参数,它可以接受下列值:

参数 描述
c_index 可以跟踪C顺序的索引
f_index 可以跟踪Fortran顺序的索引
multi_index 每次迭代可以跟踪一种索引类型
external_loop 给出的值是具有多个值的一维数组,而不是零维数组
# 迭代器遍历对应于每列,并组合为一维数组
# 当数组的order与在循环中指定的order顺序不同时,打印为多个一维数组,当相同时,是整个一个一维数组。
import numpy as np 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print('原始数组是:')
print(a)
print('\n')
print('修改后的数组(F风格)是:')
for x in np.nditer(a, flags = ['external_loop'], order = 'F'):  
   print(x, end=", ")
print('\n')
print('修改后的数组(C风格)是:')
for y in np.nditer(a, flags = ['external_loop'], order = 'C'):  
   print(y, end=", ")
# 输出结果
原始数组是:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]

修改后的数组(F风格)是:
[ 0 20 40], [ 5 25 45], [10 30 50], [15 35 55], 

修改后的数组(C风格)是:
[ 0  5 10 15 20 25 30 35 40 45 50 55], 

(4)广播迭代

如果两个数组是可广播的,nditer组合对象能够同时迭代它们。 假设数组a的维度为3X4,数组b的维度为1X4 ,则使用以下迭代器(数组b被广播到a的大小)。

import numpy as np 
 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print('第一个数组为:')
print(a)
print('\n')
print('第二个数组为:')
b = np.array([1,  2,  3,  4], dtype = int)  
print(b)
print('\n')
print('修改后的数组为:')
for x,y in np.nditer([a,b]):  
    print("%d:%d"%(x,y), end=", ")
# 输出结果
第一个数组为:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]

第二个数组为:
[1 2 3 4]

修改后的数组为:
0:1, 5:2, 10:3, 15:4, 20:1, 25:2, 30:3, 35:4, 40:1, 45:2, 50:3, 55:4, 

NumPy数组操作

Numpy中包含了一些函数用于处理数组,大概可分为以下几类:

修改数组形状
函数 描述
reshape 不改变数据的条件下修改形状
flat 数组元素迭代器
flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组
ravel 返回展开数组
翻转数组
函数 描述
transpose 对换数组的维度
ndarray.T self.transpose() 相同
rollaxis 向后滚动指定的轴
swapaxes 对换数组的两个轴
修改数组维度
函数 描述
broadcast 产生模仿广播的对象
broadcast_to 将数组广播到新形状
expand_dims 扩展数组的形状
squeeze 从数组的形状中删除一维条目
连接数组
函数 描述
concatenate 连接沿现有轴的数组序列
stack 沿着新的轴加入一系列数组。
hstack 水平堆叠序列中的数组(列方向)
vstack 竖直堆叠序列中的数组(行方向)
分割数组
函数 描述
split 将一个数组分割为多个子数组
hsplit 将一个数组水平分割为多个子数组(按列)
vsplit 将一个数组垂直分割为多个子数组(按行)
数组元素的添加与删除
函数 描述
resize 返回指定形状的新数组
append 将值添加到数组末尾
insert 沿指定轴将值插入到指定下标之前
delete 删掉某个轴的子数组,并返回删除后的新数组
unique 查找数组内的唯一元素

NumPy位运算

NumPy"bitwise_" 开头的函数是位运算函数。NumPy位运算包括以下几个函数:

函数 描述
bitwise_and 对数组元素执行位与操作
bitwise_or 对数组元素执行位或操作
invert 按位取反
left_shift 向左移动二进制表示的位,相当于右侧附加相等数量的0
right_shift 向右移动二进制表示的位,相当于左侧附加相等数量的0

bitwise_and()函数对数组中整数的二进制形式执行位与运算。

import numpy as np 
 
print('13和17的二进制形式:')
a,b = 13,17
print(bin(a), bin(b))
print('\n')
print('13和17的位与:')
print(np.bitwise_and(13, 17))

# 输出结果
1317的二进制形式:
0b1101 0b10001

1317的位与:
1

bitwise_or()函数对数组中整数的二进制形式执行位或运算。

import numpy as np 
 
a,b = 13,17 
print('13和17的二进制形式:')
print(bin(a), bin(b))
 
print('13和17的位或:')
print(np.bitwise_or(13, 17))

# 输出结果
1317的二进制形式:
0b1101 0b10001
1317的位或:
29

invert()函数对数组中整数进行位取反运算,即0变成1,1变成0。对于有符号整数,取该二进制数的补码,然后 +1。二进制数,最高位为0表示正数,最高位为1表示负数。

import numpy as np 
 
print('13的位反转,其中ndarray的dtype是uint8:')
print(np.invert(np.array([13], dtype = np.uint8)))
print('\n')
# 比较13和242的二进制表示,我们发现了位的反转
 
print('13的二进制表示:')
print(np.binary_repr(13, width = 8))
print('\n')
 
print('242的二进制表示:')
print(np.binary_repr(242, width = 8))

# 输出结果
13的位反转,其中ndarray的dtype是uint8:
[242]

13的二进制表示:
00001101

242的二进制表示:
11110010

left_shift()函数将数组元素的二进制形式向左移动到指定位置,右侧附加相等数量的0。

import numpy as np 
 
print('将10左移两位:')
print(np.left_shift(10,2))
print('\n')
 
print('10的二进制表示:')
print(np.binary_repr(10, width = 8))
print('\n')
 
print('40的二进制表示:')
print(np.binary_repr(40, width = 8))
# '00001010' 中的两位移动到了左边,并在右边添加了两个0。

# 输出结果10左移两位:
40

10的二进制表示:
00001010

40的二进制表示:
00101000

right_shift()函数将数组元素的二进制形式向右移动到指定位置,左侧附加相等数量的0。

import numpy as np 
 
print('将40右移两位:')
print(np.right_shift(40,2))
print('\n')
 
print('40的二进制表示:')
print(np.binary_repr(40, width = 8))
print('\n')
 
print('10的二进制表示:')
print(np.binary_repr(10, width = 8))
# '00001010'中的两位移动到了右边,并在左边添加了两个0。

# 输出结果40右移两位:
10

40的二进制表示:
00101000

10的二进制表示:
00001010

NumPy字符串函数

以下函数用于对dtypenumpy.string_numpy.unicode_的数组执行向量化字符串操作。 它们基于Python 内置库中的标准字符串函数。这些函数在字符数组类(numpy.char)中定义。

函数 描述
add() 对两个数组的逐个字符串元素进行连接
multiply() 返回按元素多重连接后的字符串
center() 居中字符串
capitalize() 将字符串第一个字母转换为大写
title() 将字符串的每个单词的第一个字母转换为大写
lower() 数组元素转换为小写
upper() 数组元素转换为大写
split() 指定分隔符对字符串进行分割,并返回数组列表
splitlines() 返回元素中的行列表,以换行符分割
strip() 移除元素开头或者结尾处的特定字符
join() 通过指定分隔符来连接数组中的元素
replace() 使用新字符串替换字符串中的所有子字符串
decode() 数组元素依次调用str.decode
encode() 数组元素依次调用str.encode

numpy.char.add()函数依次对两个数组的元素进行字符串连接。

import numpy as np 
 
print('连接两个字符串:')
print(np.char.add(['hello'],[' xyz']))
print('\n')
 
print('连接示例:')
print(np.char.add(['hello', 'hi'],[' abc', ' xyz']))

# 输出结果
连接两个字符串:
['hello xyz']

连接示例:
['hello abc' 'hi xyz']

numpy.char.multiply()函数执行多重连接。

import numpy as np 
 
print(np.char.multiply('Runoob ',3))

# 输出结果
Runoob Runoob Runoob 

numpy.char.center()函数用于将字符串居中,并使用指定字符在左侧和右侧进行填充。

import numpy as np 
 
# np.char.center(str , width,fillchar) :
# str: 字符串,width: 长度,fillchar: 填充字符
print(np.char.center('Runoob', 20,fillchar = '*'))

# 输出结果
*******Runoob*******

numpy.char.capitalize()函数将字符串的第一个字母转换为大写。

import numpy as np 
 
print(np.char.capitalize('runoob'))

# 输出结果
Runoob

numpy.char.title()函数将字符串的每个单词的第一个字母转换为大写。

import numpy as np
 
print(np.char.title('i like runoob'))

# 输出结果
I Like Runoob

numpy.char.lower()函数对数组的每个元素转换为小写。它对每个元素调用str.lower。

import numpy as np 
 
#操作数组
print(np.char.lower(['RUNOOB','GOOGLE']))
# 操作字符串
print(np.char.lower('RUNOOB'))

# 输出结果
['runoob' 'google']
runoob

numpy.char.upper()函数对数组的每个元素转换为大写。它对每个元素调用 str.upper。

import numpy as np 
 
#操作数组
print(np.char.upper(['runoob','google']))
# 操作字符串
print(np.char.upper('runoob'))

# 输出结果
['RUNOOB' 'GOOGLE']
RUNOOB

numpy.char.split()通过指定分隔符对字符串进行分割,并返回数组。默认情况下,分隔符为空格。

import numpy as np 
 
# 分隔符默认为空格
print(np.char.split('i like runoob?'))
# 分隔符为.
print(np.char.split('www.runoob.com', sep = '.'))

# 输出结果
['i', 'like', 'runoob?']
['www', 'runoob', 'com']

numpy.char.splitlines()函数以换行符作为分隔符来分割字符串,并返回数组。

import numpy as np 
# \n,\r,\r\n 都可用作换行符。
# 换行符\n
print(np.char.splitlines('i\nlike runoob?')) 
print(np.char.splitlines('i\rlike runoob?'))

# 输出结果
['i', 'like runoob?']
['i', 'like runoob?']

numpy.char.strip()函数用于移除开头或结尾处的特定字符。

import numpy as np 
 
# 移除字符串头尾的a字符
print(np.char.strip('ashok arunooba','a'))
# 移除数组元素头尾的a字符
print(np.char.strip(['arunooba','admin','java'],'a'))

# 输出结果
shok arunoob
['runoob' 'dmin' 'jav']

numpy.char.join()函数通过指定分隔符来连接数组中的元素或字符串

import numpy as np 
 
# 操作字符串
print(np.char.join(':','runoob'))
# 指定多个分隔符操作数组元素
print(np.char.join([':','-'],['runoob','google']))

# 输出结果
r:u:n:o:o:b
['r:u:n:o:o:b' 'g-o-o-g-l-e']

numpy.char.replace()函数使用新字符串替换字符串中的所有子字符串。

import numpy as np 
 
print(np.char.replace('i like runoob', 'oo', 'cc'))

# 输出结果
i like runccb

numpy.char.encode()函数对数组中的每个元素调用str.encode函数。 默认编码是utf-8,可以使用标准Python库中的编解码器。

import numpy as np 
 
a = np.char.encode('runoob', 'cp500') 
print(a)

# 输出结果
b'\x99\xa4\x95\x96\x96\x82'

numpy.char.decode()函数对编码的元素进行str.decode()解码。

import numpy as np 
 
a = np.char.encode('runoob', 'cp500') 
print(a)
print(np.char.decode(a,'cp500'))

# 输出结果
b'\x99\xa4\x95\x96\x96\x82'
runoob

NumPy数学函数

NumPy包含大量的各种数学运算的函数,包括三角函数,算术运算的函数,复数处理函数等。

(1)三角函数

NumPy提供了标准的三角函数:sin()、cos()、tan()。arcsin,arccos,和arctan函数返回给定角度的sin,cos和tan的反三角函数。这些函数的结果可以通过numpy.degrees()函数将弧度转换为角度。

import numpy as np
 
a = np.array([0,30,45,60,90])  
print('含有正弦值的数组:')
sin = np.sin(a*np.pi/180)  
print(sin)
print('\n')
print('计算角度的反正弦,返回值以弧度为单位:')
inv = np.arcsin(sin)  
print(inv)
print('\n')
print('通过转化为角度制来检查结果:')
print(np.degrees(inv))

# 输出结果
含有正弦值的数组:
[0.         0.5        0.70710678 0.8660254  1.        ]

计算角度的反正弦,返回值以弧度为单位:
[0.         0.52359878 0.78539816 1.04719755 1.57079633]

通过转化为角度制来检查结果:
[ 0. 30. 45. 60. 90.]

(2)舍入函数

numpy.around()函数返回指定数字的四舍五入值。

numpy.around(a,decimals)
参数说明:
    a: 数组
    decimals: 舍入的小数位数。默认值为0。如果为负,整数将四舍五入到小数点左侧的位置。例如decimals为-1,代表舍入到十位,13舍入为10,16舍入为20

import numpy as np
 
a = np.array([1.0,5.55,123,0.567,25.532])  
print('原数组:')
print(a)
print('\n')
print('舍入后:')
print(np.around(a))
print(np.around(a, decimals = 1))
print(np.around(a, decimals = -1))

# 输出结果
原数组:
[1.	5.55  123.	0.567  25.532]

舍入后:
[1.  6. 123.   1.  26.]
[1.  5.6 123.    0.6  25.5]
[0.  10. 120.   0.  30.]

numpy.floor()返回小于或者等于指定表达式的最大整数,即向下取整。

numpy.ceil()返回大于或者等于指定表达式的最小整数,即向上取整。

NumPy算术函数

NumPy算术函数包含简单的加减乘除: add()subtract()multiply()divide()。需要注意的是数组必须具有相同的形状或符合数组广播规则。

import numpy as np 
 
a = np.arange(9, dtype = np.float_).reshape(3,3)  
print('第一个数组:')
print(a)
print('\n')
print('第二个数组:')
b = np.array([10,10,10])  
print(b)
print('\n')
print('两个数组相加:')
print(np.add(a,b))
print('\n')
print('两个数组相减:')
print(np.subtract(a,b))
print('\n')
print('两个数组相乘:')
print(np.multiply(a,b))
print('\n')
print('两个数组相除:')
print(np.divide(a,b))

# 输出结果
第一个数组:
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]

第二个数组:
[10 10 10]

两个数组相加:
[[10. 11. 12.]
 [13. 14. 15.]
 [16. 17. 18.]]

两个数组相减:
[[-10.  -9.  -8.]
 [ -7.  -6.  -5.]
 [ -4.  -3.  -2.]]

两个数组相乘:
[[ 0. 10. 20.]
 [30. 40. 50.]
 [60. 70. 80.]]

两个数组相除:
[[0.  0.1 0.2]
 [0.3 0.4 0.5]
 [0.6 0.7 0.8]]

numpy.reciprocal()函数返回参数逐元素的倒数。如 1/4 倒数为 4/1

import numpy as np 
 
a = np.array([0.25,  1.33,  1,  100])  
print('我们的数组是:')
print(a)
print('\n')
print('调用 reciprocal 函数:')
print(np.reciprocal(a))

# 输出结果
我们的数组是:
[0.25  1.33  1.  100.]

调用 reciprocal 函数:
[4.	0.7518797	1.	0.01]

numpy.power()函数将第一个输入数组中的元素作为底数,计算它与第二个输入数组中相应元素的幂。

import numpy as np 
 
a = np.array([10,100,1000])  
print('我们的数组是;')
print(a)
print('\n') 
print('调用 power 函数:')
print(np.power(a,2))
print('\n')
print('第二个数组:')
b = np.array([1,2,3])  
print(b)
print('\n')
print('再次调用 power 函数:')
print(np.power(a,b))

# 输出结果
我们的数组是;
[10	100 1000]

调用power函数:
[100	10000	1000000]

第二个数组:
[1 2 3]

再次调用 power 函数:
[10	10000 1000000000]

numpy.mod()计算输入数组中相应元素的相除后的余数。 函数numpy.remainder()也产生相同的结果。

import numpy as np
 
a = np.array([10,20,30]) 
b = np.array([3,5,7])  
print('第一个数组:')
print(a)
print('\n')
print('第二个数组:')
print(b)
print('\n')
print('调用 mod() 函数:')
print(np.mod(a,b))
print('\n')
print('调用 remainder() 函数:')
print(np.remainder(a,b))

# 输出结果
第一个数组:
[10 20 30]

第二个数组:
[3 5 7]

调用mod()函数:
[1 0 2]

调用remainder()函数:
[1 0 2]

NumPy统计函数

NumPy提供了很多统计函数,用于从数组中查找最小元素最大元素百分位标准差方差等。 函数说明如下:

numpy.amin()用于计算数组中的元素沿指定轴的最小值。

numpy.amax()用于计算数组中的元素沿指定轴的最大值。

import numpy as np 
 
a = np.array([[3,7,5],[8,4,3],[2,4,9]])  
print('我们的数组是:')
print(a)
print('\n')
print('调用amin()函数:')
print(np.amin(a,1))
print('\n')
print('再次调用amin()函数:')
print(np.amin(a,0))
print('\n')
print('调用amax()函数:')
print(np.amax(a))
print('\n')
print('再次调用amax()函数:')
print(np.amax(a, axis = 0))

# 输出结果
我们的数组是:
[[3 7 5]
 [8 4 3]
 [2 4 9]]

调用amin()函数:
[3 3 2]

再次调用amin()函数:
[2 4 3]

调用amax()函数:
9

再次调用amax()函数:
[8 7 9]

numpy.ptp()函数计算数组中元素最大值与最小值的差(最大值 - 最小值)。

import numpy as np 
 
a = np.array([[3,7,5],[8,4,3],[2,4,9]])  
print('我们的数组是:')
print(a)
print('\n')
print('调用ptp()函数:')
print(np.ptp(a))
print('\n')
print('沿轴1调用ptp()函数:')
print(np.ptp(a, axis = 1))
print('\n')
print('沿轴0调用ptp()函数:')
print(np.ptp(a, axis = 0))

# 输出结果
我们的数组是:
[[3 7 5]
 [8 4 3]
 [2 4 9]]

调用ptp()函数:
7

沿轴1调用ptp()函数:
[4 5 7]

沿轴0调用ptp()函数:
[6 3 6]

百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。 函数numpy.percentile()接受以下参数。

numpy.percentile(a, q, axis)
参数说明:
    a: 输入数组
    q: 要计算的百分位数,在0~100之间
    axis: 沿着它计算百分位数的轴
import numpy as np 
 
a = np.array([[10, 7, 4], [3, 2, 1]])
print('我们的数组是:')
print(a)
print('调用percentile()函数:')
# 50%的分位数,就是a里排序之后的中位数
print(np.percentile(a,50)) 
# axis为0,在纵列上求
print(np.percentile(a,50,axis=0)) 
# axis为1,在横行上求
print(np.percentile(a,50,axis=1)) 
# 保持维度不变
print(np.percentile(a,50,axis=1,keepdims=True))

# 输出结果
我们的数组是:
[[10  7  4]
 [ 3  2  1]]
调用percentile()函数:
3.5
[6.5 4.5 2.5]
[7. 2.]
[[7.]
 [2.]]

numpy.median()函数用于计算数组a中元素的中位数(中值)

import numpy as np 
 
a = np.array([[30,65,70],[80,95,10],[50,90,60]])  
print('我们的数组是:')
print(a)
print('\n')
print('调用median()函数:')
print(np.median(a))
print('\n')
print('沿轴0调用median()函数:')
print(np.median(a, axis = 0))
print('\n')
print('沿轴1调用median()函数:')
print(np.median(a, axis = 1))

# 输出结果
我们的数组是:
[[30 65 70]
 [80 95 10]
 [50 90 60]]

调用median()函数:
65.0

沿轴0调用median()函数:
[50. 90. 60.]

沿轴1调用median()函数:
[65. 80. 60.]

numpy.mean()函数返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。算术平均值是沿轴的元素的总和除以元素的数量。

import numpy as np 
 
a = np.array([[1,2,3],[3,4,5],[4,5,6]])  
print('我们的数组是:')
print(a)
print('\n')
print('调用mean()函数:')
print(np.mean(a))
print('\n')
print('沿轴0调用mean()函数:')
print(np.mean(a, axis = 0))
print('\n')
print('沿轴1调用mean()函数:')
print(np.mean(a, axis = 1))

# 输出结果
我们的数组是:
[[1 2 3]
 [3 4 5]
 [4 5 6]]

调用mean()函数:
3.6666666666666665

沿轴0调用mean()函数:
[2.66666667 3.66666667 4.66666667]

沿轴1调用mean()函数:
[2. 4. 5.]

numpy.average()函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开。加权平均值即将各数值乘以相应的权数,然后加总求和得到总体值,再除以总的单位数。考虑数组[1,2,3,4]和相应的权重[4,3,2,1],通过将相应元素的乘积相加,并将和除以权重的和,来计算加权平均值。

加权平均值 = (1*4+2*3+3*2+4*1)/(4+3+2+1)

import numpy as np 
 
a = np.array([1,2,3,4])  
print('我们的数组是:')
print(a)
print('\n')
print('调用average()函数:')
print(np.average(a))
print('\n')
# 不指定权重时相当于mean函数
wts = np.array([4,3,2,1])  
print('再次调用average()函数:')
print(np.average(a,weights = wts))
print('\n')
# 如果returned参数设为true,则返回权重的和  
print('权重的和:')
print(np.average([1,2,3,4],weights = [4,3,2,1], returned = True))

# 输出结果
我们的数组是:
[1 2 3 4]

调用average()函数:
2.5

再次调用average()函数:
2.0

权重的和:
(2.0, 10.0)

在多维数组中,可以指定用于计算的轴。

import numpy as np 
 
a = np.arange(6).reshape(3,2)  
print('我们的数组是:')
print(a)
print('\n')
print('修改后的数组:')
wt = np.array([3,5])  
print(np.average(a, axis = 1, weights = wt))
print('\n')
print('修改后的数组:')
print(np.average(a, axis = 1, weights = wt, returned = True))

# 输出结果
我们的数组是:
[[0 1]
 [2 3]
 [4 5]]

修改后的数组:
[0.625 2.625 4.625]

修改后的数组:
(array([0.625, 2.625, 4.625]), array([8., 8., 8.]))

标准差是一组数据平均值分散程度的一种度量。标准差是方差的算术平方根。标准差公式如下:

std = sqrt(mean((x-x.mean())**2))

import numpy as np 
 
print(np.std([1,2,3,4]))

# 输出结果
1.118033988749895

统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数,即mean((x-x.mean())**2)。换句话说,标准差是方差的平方根。

import numpy as np
 
print(np.var([1,2,3,4]))

# 输出结果
1.25

NumPy排序、条件筛选函数

NumPy提供了多种排序的方法。 这些排序函数实现不同的排序算法,每个排序算法的特征在于执行速度,最坏情况性能,所需的工作空间和算法的稳定性。 下表显示了三种排序算法的比较。

种类 速度 最坏情况 工作空间 稳定性
'quicksort'(快速排序) 1 O(n^2) 0
'mergesort'(归并排序) 2 O(n*log(n)) ~n/2
'heapsort'(堆排序) 3 O(n*log(n)) 0

numpy.sort()函数返回输入数组的排序副本。函数格式如下:

numpy.sort(a, axis, kind, order)
参数说明:
    a: 要排序的数组
    axis: 沿着它排序数组的轴,如果没有数组会被展开,沿着最后的轴排序, axis=0按列排序,axis=1按行排序
    kind: 默认为'quicksort'(快速排序)
    order: 如果数组包含字段,则是要排序的字段

import numpy as np  
 
a = np.array([[3,7],[9,1]])  
print('我们的数组是:')
print(a)
print('\n')
print('调用sort()函数:')
print(np.sort(a))
print('\n')
print('按列排序:')
print(np.sort(a, axis =  0))
print('\n')
# 在sort函数中排序字段 
dt = np.dtype([('name','S10'),('age',int)]) 
a = np.array([("raju",21),("anil",25),("ravi", 17), ("amar",27)], dtype = dt)  
print('我们的数组是:')
print(a)
print('\n')
print('按name排序:')
print(np.sort(a, order = 'name'))

# 输出结果
我们的数组是:
[[3 7]
 [9 1]]

调用sort()函数:
[[3 7]
 [1 9]]

按列排序:
[[3 1]
 [9 7]]

我们的数组是:
[(b'raju', 21) (b'anil', 25) (b'ravi', 17) (b'amar', 27)]

按 name 排序:
[(b'amar', 27) (b'anil', 25) (b'raju', 21) (b'ravi', 17)]

numpy.argsort()函数返回的是数组值从小到大的索引值。

import numpy as np 
 
x = np.array([3,  1,  2])  
print('我们的数组是:')
print(x)
print('\n')
print('对x调用argsort()函数:')
y = np.argsort(x)  
print(y)
print('\n')
print('以排序后的顺序重构原数组:')
print(x[y])
print('\n')
print('使用循环重构原数组:')
for i in y:  
    print (x[i], end=" ")

# 输出结果
我们的数组是:
[3 1 2]

对x调用argsort()函数:
[1 2 0]

以排序后的顺序重构原数组:
[1 2 3]

使用循环重构原数组:
1 2 3

numpy.lexsort()用于对多个序列进行排序。把它想象成对电子表格进行排序,每一列代表一个序列,排序时优先照顾靠后的列。

import numpy as np 

# 传入np.lexsort的是一个tuple,排序时首先排nm,顺序为:amar、anil、raju、ravi。综上排序结果为[3 1 0 2]。
nm = ('raju','anil','ravi','amar') 
dv = ('f.y.', 's.y.', 's.y.', 'f.y.') 
ind = np.lexsort((dv,nm))  
print('调用lexsort()函数:') 
print(ind) 
print('\n') 
print('使用这个索引来获取排序后的数据:') 
print([nm[i]+", " + dv[i] for i in ind])

# 输出结果
调用lexsort()函数:
[3 1 0 2]

使用这个索引来获取排序后的数据:
['amar, f.y.', 'anil, s.y.', 'raju, f.y.', 'ravi, s.y.']
函数 描述
msort(a) 数组按第一个轴排序,返回排序后的数组副本。np.msort(a)相等于np.sort(a, axis=0)
sort_complex(a) 对复数按照先实部后虚部的顺序进行排序。
partition(a, kth[, axis, kind, order]) 指定一个数,对数组进行分区
argpartition(a, kth[, axis, kind, order]) 可以通过关键字kind指定算法沿着指定轴对数组进行分区
import numpy as np

# 复数排序
print(np.sort_complex([5,3,6,2,1]))
print(np.sort_complex([1+2j, 2-1j, 3-2j, 3-3j, 3+5j]))
# 输出结果
[1.+0.j 2.+0.j 3.+0.j 5.+0.j 6.+0.j]
[1.+2.j 2.-1.j 3.-3.j 3.-2.j 3.+5.j]

# partition()分区排序:
a = np.array([3, 4, 2, 1])
# 将数组a中所有元素(包括重复元素)从小到大排列,3表示的是排序数组索引为3的数字,比该数字小的排在该数字前面,比该数字大的排在该数字的后面
print(np.partition(a, 3))
# 小于1的在前面,大于3的在后面,1和3之间的在中间
print(np.partition(a,(1,3)))
# 输出结果
[2 1 3 4]
[1 2 3 4]

arr = np.array([46, 57, 23, 39, 1, 10, 0, 120])
# 找到数组的第3小(index=2)的值和第2大(index=-2)的值
print(arr[np.argpartition(arr, 2)[2]])
print(arr[np.argpartition(arr, -2)[-2]])
# 同时找到第3和第4小的值。注意这里,用[2,3]同时将第3和第4小的排序好,然后可以分别通过下标[2]和[3]取得。
print(arr[np.argpartition(arr,[2,3])[2]])
print(arr[np.argpartition(arr,[2,3])[3]])
# 输出结果
10
57
10
23

numpy.argmax()numpy.argmin()函数分别沿给定轴返回最大和最小元素的索引。

import numpy as np 
 
a = np.array([[30,40,70],[80,20,10],[50,90,60]])  
print('我们的数组是:') 
print(a) 
print('\n') 
print('调用argmax()函数:') 
print(np.argmax(a)) 
print('\n') 
print('展开数组:') 
print(a.flatten()) 
print('\n') 
print('沿轴0的最大值索引:') 
maxindex = np.argmax(a, axis = 0)  
print(maxindex) 
print('\n') 
print('沿轴1的最大值索引:') 
maxindex = np.argmax(a, axis = 1)  
print(maxindex) 
print('\n') 
print('调用argmin()函数:') 
minindex = np.argmin(a)  
print(minindex) 
print('\n') 
print('展开数组中的最小值:') 
print(a.flatten()[minindex]) 
print('\n') 
print('沿轴0的最小值索引:') 
minindex = np.argmin(a, axis = 0)  
print(minindex) 
print('\n') 
print('沿轴1的最小值索引:') 
minindex = np.argmin(a, axis = 1)  
print(minindex)

# 输出结果
我们的数组是:
[[30 40 70]
 [80 20 10]
 [50 90 60]]

调用argmax()函数:
7

展开数组:
[30 40 70 80 20 10 50 90 60]

沿轴0的最大值索引:
[1 2 0]

沿轴1的最大值索引:
[2 0 1]

调用argmin()函数:
5

展开数组中的最小值:
10

沿轴0的最小值索引:
[0 1 1]

沿轴1的最小值索引:
[0 2 0]

numpy.nonzero()函数返回输入数组中非零元素的索引。

import numpy as np 
 
a = np.array([[30,40,0],[0,20,10],[50,0,60]])  
print('我们的数组是:')
print(a)
print('\n')
print('调用nonzero()函数:')
print(np.nonzero(a))

# 输出结果
我们的数组是:
[[30 40  0]
 [ 0 20 10]
 [50  0 60]]

调用nonzero()函数:
(array([0, 0, 1, 1, 2, 2], dtype=int64), array([0, 1, 1, 2, 0, 2], dtype=int64))

numpy.where()函数返回输入数组中满足给定条件的元素的索引。

import numpy as np 
 
x = np.arange(9.).reshape(3, 3)  
print('我们的数组是:')
print(x)
print('大于3的元素的索引:')
y = np.where(x > 3)  
print(y)
print('使用这些索引来获取满足条件的元素:')
print(x[y])

# 输出结果
我们的数组是:
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
大于3的元素的索引:
(array([1, 1, 2, 2, 2], dtype=int64), array([1, 2, 0, 1, 2], dtype=int64))
使用这些索引来获取满足条件的元素:
[4. 5. 6. 7. 8.]

numpy.extract()函数根据某个条件从数组中抽取元素,返回满条件的元素。

import numpy as np 
 
x = np.arange(9.).reshape(3, 3)  
print('我们的数组是:')
print(x)
# 定义条件,选择偶数元素
condition = np.mod(x,2) == 0  
print('按元素的条件值:')
print(condition)
print('使用条件提取元素:')
print(np.extract(condition, x))

# 输出结果
我们的数组是:
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
按元素的条件值:
[[True False True]
 [False True False]
 [True False True]]
使用条件提取元素:
[0. 2. 4. 6. 8.]

NumPy字节交换

在几乎所有的机器上,多字节对象都被存储为连续的字节序列。字节顺序,是跨越多字节的程序对象的存储规则。

  • **大端模式:**指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
  • **小端模式:**指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

numpy.ndarray.byteswap()函数将ndarray中每个元素中的字节进行大小端转换。

import numpy as np 
 
import numpy as np 
 
a = np.array([1, 256, 8755], dtype = np.int16)  
print('我们的数组是:')
print(a)
print('以十六进制表示内存中的数据:')
print(map(hex,a))
print(list(map(hex, a)))
# byteswap()函数通过传入true来原地交换 
print('调用 byteswap() 函数:')
print(a.byteswap(True))
print('十六进制形式:')
print (map(hex,a))
print(list(map(hex, a)))
# 我们可以看到字节已经交换了

# 输出结果
我们的数组是:
[   1  256 8755]
以十六进制表示内存中的数据:
<map object at 0x00000229347A3D88>
['0x1', '0x100', '0x2233']
调用 byteswap() 函数:
[  256     1 13090]
十六进制形式:
<map object at 0x00000229347A3608>
['0x100', '0x1', '0x3322']

NumPy副本和视图

副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。

视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。

副本一般发生在:

  • Python序列的切片操作,调用deepCopy()函数。
  • 调用ndarray的copy()函数产生一个副本。

视图一般发生在:

  • numpy的切片操作返回原数据的视图。
  • 调用ndarray的view()函数产生一个视图。

(1)无复制

简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回Python对象的通用标识符,类似于C中的指针。此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。

import numpy as np 
 
a = np.arange(6)  
print('我们的数组是:')
print(a)
print('调用id()函数:')
print(id(a))
print('a赋值给b:')
b = a 
print(b)
print('b拥有相同id():')
print(id(b))
print('修改b的形状:')
b.shape = 3,2  
print(b)
print('a的形状也修改了:')
print(a)

# 输出结果
我们的数组是:
[0 1 2 3 4 5]
调用id()函数:
2375996889168
a赋值给b:
[0 1 2 3 4 5]
b拥有相同id()2375996889168
修改 b 的形状:
[[0 1]
 [2 3]
 [4 5]]
a的形状也修改了:
[[0 1]
 [2 3]
 [4 5]]

(2)视图或浅拷贝

ndarray.view()方会创建一个新的数组对象,该方法创建的新数组的维数变化不会改变原始数据的维数。

import numpy as np 
 
# 最开始 a 是个 3X2 的数组
a = np.arange(6).reshape(3,2)  
print('数组a:')
print(a)
print('创建a的视图:')
b = a.view()  
print(b)
print('两个数组的id()不同:')
print('a的id():')
print(id(a))
print('b的id():' )
print(id(b))
# 修改b的形状,并不会修改a
b.shape =  2,3
print('b的形状:')
print(b)
print('a的形状:')
print(a)

# 输出结果
数组a:
[[0 1]
 [2 3]
 [4 5]]
创建a的视图:
[[0 1]
 [2 3]
 [4 5]]
两个数组的id()不同:
a的id()2375996990448
b的id()2375996617872
b的形状:
[[0 1 2]
 [3 4 5]]
a的形状:
[[0 1]
 [2 3]
 [4 5]]

使用切片创建视图修改数据会影响到原始数组,变量a,b都是arr的一部分视图,对视图的修改会直接反映到原数据中。但是我们观察a,b的id,他们是不同的,也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。

import numpy as np 
 
arr = np.arange(12)
print('我们的数组:')
print(arr)
print('创建切片:')
a=arr[3:]
b=arr[3:]
a[1]=123
b[2]=234
print(arr)
print(id(a),id(b),id(arr[3:]))

# 输出结果
我们的数组:
[ 0  1  2  3  4  5  6  7  8  9 10 11]
创建切片:
[  0   1   2   3 123 234   6   7   8   9  10  11]
2375996635536 2375996634816 2375996921616

(3)副本或深拷贝

ndarray.copy()函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置。

import numpy as np 
 
a = np.array([[10,10],  [2,3],  [4,5]])  
print('数组a:')
print(a)
print('创建a的深层副本:')
b = a.copy()  
print('数组 b:')
print(b)
# b与a不共享任何内容  
print('我们能够写入b来写入a吗?')
print(b is a)
print('修改b的内容:')
b[0,0] = 100  
print('修改后的数组b:')
print(b)
print('a保持不变:')
print(a)

# 输出结果
数组a:
[[10 10]
 [ 2  3]
 [ 4  5]]
创建a的深层副本:
数组 b:
[[10 10]
 [ 2  3]
 [ 4  5]]
我们能够写入b来写入a吗?
False
修改b的内容:
修改后的数组b:
[[100  10]
 [  2   3]
 [  4   5]]
a保持不变:
[[10 10]
 [ 2  3]
 [ 4  5]]

NumPy矩阵库(Matrix)

NumPy中包含了一个矩阵库numpy.matlib,该模块中的函数返回一个矩阵,而不是ndarray对象。一个m×n的矩阵是一个由m行(row)n列(column)元素排列成的矩形阵列。矩阵里的元素可以是数字、符号或数学式。

(1)转置矩阵

NumPy中除了可以使用numpy.transpose函数来对换数组的维度,还可以使用 T 属性。

import numpy as np
 
a = np.arange(12).reshape(3,4)
print('原数组:')
print(a)
print('\n')
print('转置数组:')
print(a.T)

# 输出结果
原数组:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

转置数组:
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]

(2)matlib.empty()

matlib.empty()函数返回一个新的矩阵,语法格式为:

numpy.matlib.empty(shape, dtype, order)
参数说明:
    shape: 定义新矩阵形状的整数或整数元组
    Dtype: 可选,数据类型
    order: C(行序优先) 或者 F(列序优先)

import numpy as np
 
print(np.matlib.empty((2,2)))
# 填充为随机数据

# 输出结果
[[1.36008890e-311 1.69168361e-301]
 [3.42821614e-210 7.46699190e-301]]

(3)numpy.matlib.zeros()

numpy.matlib.zeros()函数创建一个以0填充的矩阵。

import numpy as np 
 
print(np.matlib.zeros((2,2)))

# 输出结果
[[0. 0.]
 [0. 0.]]

(4)numpy.matlib.ones()

numpy.matlib.ones()函数创建一个以1填充的矩阵。

import numpy as np 
 
print(np.matlib.ones((2,2)))

# 输出结果
[[1. 1.]
 [1. 1.]]

(5)numpy.matlib.eye()

numpy.matlib.eye()函数返回一个矩阵,对角线元素为1,其他位置为零。

numpy.matlib.eye(n, M,k, dtype)
参数说明:
    n: 返回矩阵的行数
    M: 返回矩阵的列数,默认为n
    k: 对角线的索引
    dtype: 数据类型

import numpy as np 
 
print(np.matlib.eye(n=3, M=4, k=0, dtype=float))

# 输出结果
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]]

(6)numpy.matlib.identity()

numpy.matlib.identity()函数返回给定大小的单位矩阵。单位矩阵是个方阵,从左上角到右下角的对角线(称为主对角线)上的元素均为1,除此以外全都为0。

import numpy as np 
 
# 大小为 5,类型位浮点型
print(np.matlib.identity(5, dtype=float))

# 输出结果
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]

(7)numpy.matlib.rand()

numpy.matlib.rand()函数创建一个给定大小的矩阵,数据是随机填充的。

import numpy as np 
 
print(np.matlib.rand(3,3))

# 输出结果
[[0.85907694 0.10033233 0.90102019]
 [0.60724393 0.67443377 0.19654135]
 [0.1626346  0.4910893  0.11768052]]

矩阵总是二维的,而ndarray是一个n维数组。 两个对象都是可互换的。

import numpy as np  
 
i = np.matrix('1,2;3,4')  
print(i)
j = np.asarray(i)  
print(j)
k = np.asmatrix(j)  
print(k)

# 输出结果
[[1 2]
 [3 4]]
[[1 2]
 [3 4]]
[[1 2]
 [3 4]]

NumPy线性代数

NumPy提供了线性代数函数库linalg,该库包含了线性代数所需的所有功能,可以看看下面的说明:

函数 描述
dot 两个数组的点积,即元素对应相乘
vdot 两个向量的点积
inner 两个数组的内积
matmul 两个数组的矩阵积
determinant 数组的行列式
solve 求解线性矩阵方程
inv 计算矩阵的乘法逆矩阵

NumPy IO

Numpy可以读写磁盘上的文本数据或二进制数据。

NumPyndarray对象引入了一个简单的文件格式:npy

npy文件用于存储重建ndarray所需的数据、图形、dtype和其他信息。

常用的IO函数有:

  • load()save()函数是读写文件数组数据的两个主要函数,默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为.npy的文件中。
  • savez()函数用于将多个数组写入文件,默认情况,数组是以未压缩的原始二进制格式保存在扩展名为.npz的文件中。
  • loadtxt()savetxt()函数处理正常的文本文件(.txt等)

(1)numpy.save()

numpy.save()函数将数组保存到以.npy为扩展名的文件中。

numpy.save(file, arr, allow_pickle=True, fix_imports=True)
参数说明:
    file:要保存的文件,扩展名为.npy,如果文件路径末尾没有扩展名.npy,该扩展名会被自动加上。
    arr: 要保存的数组
    allow_pickle: 可选,布尔值,允许使用Python pickles保存对象数组,Python中的pickle用于在保存到磁盘文件或从磁盘文件读取之前,对对象进行序列化和反序列化。
    fix_imports: 可选,为了方便Pyhton2中读取Python3保存的数据。

import numpy as np 
 
a = np.array([1,2,3,4,5]) 
# 保存到outfile.npy文件上
np.save('outfile.npy',a) 
# 保存到outfile2.npy文件上,如果文件路径末尾没有扩展名.npy,该扩展名会被自动加上
np.save('outfile2',a)

# 可以看出文件是乱码的,因为它们是Numpy专用的二进制格式后的数据。
# 我们可以使用load()函数来读取数据就可以正常显示了
b = np.load('outfile.npy')  
print(b)

# 输出结果
[1 2 3 4 5]

(2)np.savez()

numpy.savez()函数将多个数组保存到以.npz为扩展名的文件中。

numpy.savez(file, *args, **kwds)
参数说明:
    file:要保存的文件,扩展名为.npz,如果文件路径末尾没有扩展名.npz,该扩展名会被自动加上。
	args: 要保存的数组,可以使用关键字参数为数组起一个名字,非关键字参数传递的数组会自动起名为arr_0, arr_1, … 。
    kwds: 要保存的数组使用关键字名称。

import numpy as np 
 
a = np.array([[1,2,3],[4,5,6]])
b = np.arange(0, 1.0, 0.1)
c = np.sin(b)
# c使用了关键字参数sin_array
np.savez("runoob.npz", a, b, sin_array = c)
r = np.load("runoob.npz")  
print(r.files) # 查看各个数组名称
print(r["arr_0"]) # 数组 a
print(r["arr_1"]) # 数组 b
print(r["sin_array"]) # 数组 c

# 输出结果
['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]

(3)np.savetxt()

savetxt()函数是以简单的文本文件格式存储数据,对应的使用loadtxt()函数来获取数据。

np.loadtxt(FILENAME, dtype=int, delimiter=' ')
np.savetxt(FILENAME, a, fmt="%d", delimiter=",")
# 参数delimiter可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等。

import numpy as np 
 
a = np.array([1,2,3,4,5]) 
np.savetxt('out.txt',a) 
b = np.loadtxt('out.txt')  
print(b)

# 输出结果
[1. 2. 3. 4. 5.]

使用delimiter参数:

import numpy as np 

# arr.shape    # (a,b)
# arr.reshape(m,-1) # 改变维度为m行、d列(-1表示列数自动计算,d=a*b/m)
# arr.reshape(-1,m) # 改变维度为d行、m列(-1表示行数自动计算,d=a*b/m)
a = np.arange(0,10,0.5).reshape(4,-1)
print(a)
np.savetxt("out.txt",a,fmt="%d",delimiter=",") # 改为保存为整数,以逗号分隔
b = np.loadtxt("out.txt",delimiter=",") # load 时也要指定为逗号分隔
print(b)

# 输出结果
[[0.  0.5 1.  1.5 2. ]
 [2.5 3.  3.5 4.  4.5]
 [5.  5.5 6.  6.5 7. ]
 [7.5 8.  8.5 9.  9.5]]
[[0. 0. 1. 1. 2.]
 [2. 3. 3. 4. 4.]
 [5. 5. 6. 6. 7.]
 [7. 8. 8. 9. 9.]]

NumPy Matplotlib

MatplotlibPython的绘图库。 它可与NumPy一起使用,提供了一种有效的MatLab开源替代方案。它也可以和图形工具包一起使用,如PyQtwxPython

参考资料:菜鸟教程
笔者不才,请多交流!!!

欢迎大家关注预览我的博客Blog:HeartLoveLife
能力有限,敬请谅解!!

你可能感兴趣的:(科学计算,数据分析,Python基础,python,numpy)