NumPy排序和搜索功能

排序

NumPy 提供了多种排序函数, 这些排序函数可以实现不同的排序算法。
排序算法特征主要体现在以下四个方面:执行速度,最坏情况下的复杂度,所需的工作空间以及算法的稳定性。

下表列举了三种排序算法:

numpy.sort()

numpy.sort() 对输入数组执行排序,并返回一个数组副本
numpy.sort(a, axis, kind, order)

a:要排序的数组;
axis:沿着指定轴进行排序,如果没有指定 axis,默认在最后一个轴上排序,若 axis=0 表示按列排序,axis=1 表示按行排序
kind:默认为 quicksort(快速排序)
order:若数组设置了字段,则 order 表示要排序的字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np 
a = np.array([[3,7],[9,1]])
print('a数组是:')
print(a)
#调用sort()函数
print(np.sort(a))
#按列排序:
print(np.sort(a, axis = 0))
#设置在sort函数中排序字段
dt = np.dtype([('name', 'S10'),('age', int)])
a = np.array([("raju",21),("anil",25),("ravi", 17), ("amar",27)], dtype = dt)
#再次打印a数组
print(a)
#按name字段排序
print(np.sort(a, order = 'name'))

numpy.argsort()

argsort() 沿着指定的轴,对输入数组的元素值进行排序,并返回排序后的元素索引数组

1
2
3
4
5
6
7
8
9
10
import numpy as np 
a = np.array([90, 29, 89, 12])
print("原数组",a)
sort_ind = np.argsort(a)
print("打印排序元素索引值",sort_ind)
#使用索引数组对原数组排序
sort_a = a[sort_ind]
print("打印排序数组")
for i in sort_ind:
print(a[i],end = " ")

numpy.lexsort()

numpy.lexsort() 按键序列对数组进行排序,它返回一个已排序的索引数组,类似于 numpy.argsort()。

1
2
3
4
5
6
7
8
9
import numpy as np 
a = np.array(['a','b','c','d','e'])
b = np.array([12, 90, 380, 12, 211])
ind = np.lexsort((a,b))
#打印排序元素的索引数组
print(ind)
#使用索引数组对数组进行排序
for i in ind:
print(a[i],b[i])
搜索

NumPy 提供了许多可以在数组内执行搜索功能的函数。

numpy.nonzero()

该函数从数组中查找非零元素的索引位置

1
2
3
4
5
import numpy as np 
b = np.array([12, 90, 380, 12, 211])
print("原数组b",b)
print("打印非0元素的索引位置")
print(b.nonzero())

numpy.where()

numpy.where() 的返回值是满足了给定条件的元素索引值。

1
2
3
4
5
import numpy as np 
b = np.array([12, 90, 380, 12, 211])
print(np.where(b>12))
c = np.array([[20, 24],[21, 23]])
print(np.where(c>20))

numpy.extract()
该函数的返回值是满足了给定条件的元素值

1
2
3
4
5
6
7
8
9
10
import numpy as np
x = np.arange(9.).reshape(3, 3)
打印数组x:'
print(x)
#设置条件选择偶数元素
condition = np.mod(x,2)== 0
#输出布尔值数组
print(condition)
#按condition提取满足条件的元素值
print np.extract(condition, x)

numpy.argmax()

该函数返回最大值的的索引,与其相反的函数是 argmin() 求最小值索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
a = np.array([[30,40,70],[80,20,10],[50,90,60]])
#a数组
print (a)
#argmax() 函数
print (np.argmax(a))
#将数组以一维展开
print (a.flatten())
#沿轴 0 的最大值索引:
maxindex = np.argmax(a, axis = 0)
print (maxindex)
#沿轴 1 的最大值索引
maxindex = np.argmax(a, axis = 1)
print (maxindex)

numpy.argmin()

argmin() 求最小值索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
b= np.array([[3,4,7],[8,2,1],[5,9,6]])
print ('数组b:')
print (b)
#调用 argmin()函数
minindex = np.argmin(b)
print (minindex)
#展开数组中的最小值:
print (b.flatten()[minindex])
#沿轴 0 的最小值索引:
minindex = np.argmin(b, axis = 0)
print (minindex)
#沿轴 1 的最小值索引:
minindex = np.argmin(b, axis = 1)
print (minindex)

NumPy副本和视图

对 NumPy 数组执行些函数操作时,其中一部分函数会返回数组的副本,而另一部分函数则返回数组的视图。本节对数组的副本和视图做重点讲解。

其实从内存角度来说,副本就是对原数组进行深拷贝,新产生的副本与原数组具有不同的存储位置。而视图可理解为对数组的引用,它和原数组有着相同的内存位置。

赋值操作

赋值操作是数组引用的一种方法。比如,将 a 数组赋值给变量 b,被赋值后的变量 b 与 a 组具有相同的内存 id。因此,无论操作 a、b 中哪个数组,另一个数组也会受到影响。例如下:

1
2
3
4
5
6
7
8
9
import numpy as np 
a = np.array([[1,2,3,4],[9,0,2,3],[1,2,3,19]])
print("原数组",a)
print("a数组的ID:",id(a))
b = a
print("数组b的id:",id(b))
b.shape = 4,3;
print("b数组形状的更改也会反映到a数组上:")
print(a)

ndarray.view()

ndarray.view() 返回一个新生成的数组副本,因此对该数组的操作,不会影响到原数组。下面看一组示例:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np 
a = np.array([[1,2,3,4],[9,0,2,3],[1,2,3,19]])
print("原数组",a)
print("数组a的ID:",id(a))
b = a.view()
print("数组b的ID:",id(b))
#打印b数组
print(b)
#改变b数组形状
b.shape = 4,3
print("原数组a",a)
print("新数组b",b)

切片创建视图

使用切片可以创建视图数组,若要修改视图的就会影响到原数组

1
2
3
4
5
6
7
8
9
10
import numpy as np
arr = np.arange(10)
print ('数组arr:')
print (arr)
#创建切片修改原数组arr
a=arr[3:]
b=arr[3:]
a[1]=123
b[2]=234
print(arr)

ndarray.copy()

该方法返回原数组的副本,对副本的修改不会影响到原数组

1
2
3
4
5
6
7
8
9
10
11
import numpy as np 
a = np.array([[1,2,3,4],[9,0,2,3],[1,2,3,19]])
print("原数组",a)
print("a数组ID:",id(a))
b = a.copy()
print("b数组ID:",id(b))
print("打印经过copy方法的b数组:")
print(b)
b.shape=4,3
print("原数组",a)
print("经过copy方法的b数组",b)

NumPy字节交换

数据以字节的形式存储在计算机内存中,而存储规则可分为两类,即小端字节序与大端字节序。

小端字节序(little-endian),表示低位字节排放在内存的低地址端,高位字节排放在高地址段,它与大端字节序(big-endian)恰好相反。

对于二进制数 0x12345678,假设从地址 0x4000 开始存放,在大端和小端模式下,它们的字节排列顺序

numpy.ndarray.byteswap()

该函数将数组中每个元素的字节顺序进行大小端调换

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
a = np.array([1, 256, 8755], dtype = np.int16)
#数组a
print(a)
#以16进制形式表示内存中的数据
print(map(hex,a))
#byteswap()函数通过传递True参数在适当的位置进行转换
#调用byteswap()函数
print(a.byteswap(True))
#十六进制形式
print(map(hex,a))

NumPy Matrix矩阵库

NumPy 提供了一个 矩阵库模块numpy.matlib,该模块中的函数返回的是一个 matrix 对象,而非 ndarray 对象。矩阵由 m 行 n 列(m*n)元素排列而成,矩阵中的元素可以是数字、符号或数学公式等。

matlib.empty()

matlib.empty() 返回一个空矩阵,所以它的创建速度非常快。
numpy.matlib.empty(shape, dtype, order)

shape:以元组的形式指定矩阵的形状
dtype:表示矩阵的数据类型
order:有两种选择,C(行序优先) 或者 F(列序优先)

1
2
3
4
import numpy.matlib
import numpy as np
#矩阵中会填充无意义的随机值
print(np.matlib.empty((2,2)))

numpy.matlib.zeros()

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

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

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

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

numpy.matlib.eye()
numpy.matlib.eye() 返回一个对角线元素为 1,而其他元素为 0 的矩阵 。numpy.matlib.eye(n,M,k, dtype)

n:返回矩阵的行数;
M:返回矩阵的列数,默认为 n;
k:对角线的索引;
dtype:矩阵中元素数据类型。

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

numpy.matlib.identity()

该函数返回一个给定大小的单位矩阵,矩阵的对角线元素为 1,而其他元素均为 0。

1
2
3
import numpy.matlib
import numpy as np
print np.matlib.identity(5, dtype = float)

numpy.matlib.rand()
创建一个以随机数填充,并给定维度的矩阵

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

这里需要注意,因为 matrix 只能表示二维数据,而 ndarray 也可以是二维数组,所以两者可以互相转换

1
2
3
4
5
#创建矩阵i
import numpy.matlib
import numpy as np
i = np.matrix('1,2;3,4')
print (i)

实现 matrix 与 ndarray 之间的转换

1
2
3
4
5
6
import numpy.matlib
import numpy as np
j = np.asarray(i)
print (j)
k = np.asmatrix (j)
print (k)

NumPy线性代数

NumPy 提供了 numpy.linalg 模块,该模块中包含了一些常用的线性代数计算方法

dot
两个数组的点积。

vdot
两个向量的点积。

inner
两个数组的内积。

matmul
两个数组的矩阵积。

det
计算输入矩阵的行列式。

solve
求解线性矩阵方程。

inv
计算矩阵的逆矩阵,逆矩阵与原始矩阵相乘,会得到单位矩阵。

numpy.dot()
按照矩阵的乘法规则,计算两个矩阵的点积运算结果。当输入一维数组时返回一个结果值,若输入的多维数组则同样返回一个多维数组结果。输入一维数组,示例如下:

1
2
3
4
import numpy as np
A=[1,2,3]
B=[4,5,6]
print(np.dot(A,B))
1
2
3
4
5
6
7
import numpy as np 
a = np.array([[100,200],
[23,12]])
b = np.array([[10,20],
[12,21]])
dot = np.dot(a,b)
print(dot)

点积运算就是将 a 数组的每一行元素与 b 数组的每一列元素相乘再相加。

numpy.vdot()

该函数用于计算两个向量的点积结果,与 dot() 函数不同。

1
2
3
4
5
import numpy as np 
a = np.array([[100,200],[23,12]])
b = np.array([[10,20],[12,21]])
vdot = np.vdot(a,b)
print(vdot)

numpy.inner()

inner() 方法用于计算数组之间的内积。当计算的数组是一维数组时,它与 dot() 函数相同,若输入的是多维数组则两者存在不同,下面看一下具体的实例。

1
2
3
4
5
6
7
8
9
import numpy as np
A=[[1 ,10],
[100,1000]]
B=[[1,2],
[3,4]]
#inner函数
print(np.inner(A,B))
#dot函数
print(np.dot(A,B))

inner() 函数的计算过程是 A 数组的每一行与 B 数组的每一行相乘再相加,如下所示:
[[11+210 13+104 ]
[1001+10002 1003+10004]]dot() 则表示是 A 数组每一行与 B 数组的每一列相乘。

numpy.matmul()

该函数返回两个矩阵的乘积,假如两个矩阵的维度不一致,就会产生错误。

1
2
3
4
5
import numpy as np 
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = np.array([[23,23,12],[2,1,2],[7,8,9]])
mul = np.matmul(a,b)
print(mul)

numpy.linalg.det()

该函数使用对角线元素来计算矩阵的行列式,计算 2*2(两行两列) 的行列式,示例如下:

[[1,2],
[3,4]]

通过对角线元素求行列式的结果(口诀:“一撇一捺”计算法):

14-23=-2

我们可以使用 numpy.linalg.det() 函数来完成计算。示例如下:

1
2
3
import numpy as np 
a = np.array([[1,2],[3,4]])
print(np.linalg.det(a))

numpy.linalg.solve()

该函数用于求解线性矩阵方程组,并以矩阵的形式表示线性方程的解,如下所示:

1
2
3
3X  +  2 Y + Z =  10  
X + Y + Z = 6
X + 2Y - Z = 2

首先将上述方程式转换为矩阵的表达形式:

方程系数矩阵:
3 2 1
1 1 1
1 2 -1
方程变量矩阵:
X
Y
Z
方程结果矩阵:
10
6
2

如果用 m 、x、n 分别代表上述三个矩阵,其表示结果如下:m*x=n 或 x=n/m

将系数矩阵与结果矩阵传递给 numpy.solve() 函数,即可求出线程方程的解,如下所示:

1
2
3
4
5
6
7
8
9
10
import numpy as np
m = np.array([[3,2,1],[1,1,1],[1,2,-1]])
print ('数组 m:')
print (m)
print ('矩阵 n:')
n = np.array([[10],[6],[2]])
print (n)
print ('计算:m^(-1)n:')
x = np.linalg.solve(m,n)
print (x)

numpy.linalg.inv()

该函数用于计算矩阵的逆矩阵,逆矩阵与原矩阵相乘得到单位矩阵。示例如下:

1
2
3
4
5
import numpy as np 
a = np.array([[1,2],[3,4]])
print("原数组:",a)
b = np.linalg.inv(a)
print("求逆:",b)

NumPy矩阵乘法

矩阵乘法是将两个矩阵作为输入值,并将 A 矩阵的行与 B 矩阵的列对应位置相乘再相加,从而生成一个新矩阵,如下图所示:
注意:必须确保第一个矩阵中的行数等于第二个矩阵中的列数,否则不能进行矩阵乘法运算。

矩阵乘法运算被称为向量化操作,向量化的主要目的是减少使用的 for 循环次数或者根本不使用。这样做的目的是为了加速程序的计算。下面介绍 NumPy 提供的三种矩阵乘法,从而进一步加深对矩阵乘法的理解。

逐元素矩阵乘法
multiple() 函数用于两个矩阵的逐元素乘法,示例如下:

1
2
3
4
5
import numpy as np 
array1=np.array([[1,2,3],[4,5,6],[7,8,9]],ndmin=3)
array2=np.array([[9,8,7],[6,5,4],[3,2,1]],ndmin=3)
result=np.multiply(array1,array2)
result

矩阵乘积运算

matmul() 用于计算两个数组的矩阵乘积。示例如下:

1
2
3
4
5
import numpy as np 
array1=np.array([[1,2,3],[4,5,6],[7,8,9]],ndmin=3)
array2=np.array([[9,8,7],[6,5,4],[3,2,1]],ndmin=3)
result=np.matmul(array1,array2)
print(result)

矩阵点积

dot() 函数用于计算两个矩阵的点积。如下所示:

1
2
3
4
5
import numpy as np 
array1=np.array([[1,2,3],[4,5,6],[7,8,9]],ndmin=3)
array2=np.array([[9,8,7],[6,5,4],[3,2,1]],ndmin=3)
result=np.dot(array1,array2)
print(result)