Professional Documents
Culture Documents
学习目标
认识 NumPy 数组对象,会创建 NumPy 数组。
熟悉 ndarray 对象的数据类型,并会转换数据类型。
掌握数组运算方式。
掌握数组的索引和切片。
会使用数组进行数据处理。
熟悉线性代数模块和随机数模块的使用。
2.6 数组的重塑和转置
2.6.1 数组重塑
2.6.2 数组合并
【例 2-】concatenate 函数合并数组。
arr1 = np.arange(6).reshape(3,2)
arr2 = arr1*2
print('横向组合为:\n',np.concatenate((arr1,arr2),axis = 1))
print('纵向组合为:\n',np.concatenate((arr1,arr2),axis = 0))
运行结果:
横向组合为:
[[ 0 1 0 2]
[ 2 3 4 6]
[ 4 5 8 10]]
纵向组合为:
[[ 0 1]
[ 2 3]
[ 4 5]
[ 0 2]
[ 4 6]
[ 8 10]]
2.6.3 数组分割
2.6.4 数组转置
数组的转置指的是将数组中的每个元素按照一定的规则进行位置变换。NumPy 提供了
transpose ()方法和 T 属性两种实现形式。其中,简单的转置可以使用 T 属性,它其实就是进
行轴对换而已。
【示例】将现在有个 3 行 4 列的二维数组使用 T 属性对数组转置后,形成的是一个 4 行
3 列的新数组。
import numpy as np
arr = np.arange(12).reshape(3, 4)
print("创建的二维数组为:\n",arr)
print("使用 T 属性对数组进行转置:\n",arr.T)
运行结果:
创建的二维数组为:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
使用 T 属性对数组进行转置:
[[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]]
在 NumPy 中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。例如,3D 空间中有
个点的坐标[1,2,1]是一个秩为 1 的数组,因为它只有一个轴。这个轴有 3 个元素,所以我
们说它的长度为 3。
在下面的示例中,数组有 2 个轴,第一个轴的长度为 2,第二个轴的长度为 3。
array([[1, 0, 0],
[ 0, 1, 2]] )
高维数据执行某些操作(如转置)时,需要指定维度编号,这个编号是从 0 开始的,然
后依次递增 1。其中,位于纵向的轴(y 轴)的编号为 0,位于横向的轴(X 轴)的编号为 1,
以此类推。
维度编号示意图如图 2-9 所示。
图 2-9 维度编号图示
对于高维度的数组而言,transpose()方法需要得到一个由轴编号组成的元组,才能对这
些轴进行转置。
【示例】transpose()方法对高维数组的转置。
import numpy as np
arr = np.arange(16).reshape((2, 2, 4))
print("输出三维数组:\n",arr)
print("三维数组形状为:\n",arr.shape)
arr_new = arr.transpose(1, 2, 0) # 使用 transpose()方法对数组进行转置
print("三维数组转置后为:\n",arr_new)
运行结果:
输出三维数组:
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
三维数组形状为:
(2, 2, 4)
三维数组转置后为:
[[[ 0 8]
[ 1 9]
[ 2 10]
[ 3 11]]
[[ 4 12]
[ 5 13]
[ 6 14]
[ 7 15]]]
从运行结果来看,上述数组 arr 的 shape 是(2,2,4),表示是一个三维数组,也就是说
有三个轴,每个轴都对应着一个编号,分别为 0、1、2。
如果希望对 arr 进行转置操作,就需要对它的 shape 中的排序进行调换。也就是说,当
使用 transpose()方法对数组的 shape 进行变换时,需要以元组的形式传入 shape 的编号,比
如(1,2,0)。如果调用 transpose()方法时传入“(0,1,2)”,则数组的 shape 不会发生任何
变化。
在某些情况下,我们可能只需要转换其中的两个轴,这时我们可以使用 ndarray 提供的
swapaxes()方法实现,该方法需要接收一对轴编号,比如 arr.swapaxes(1, 0) 。
表 2-5 常见二元通用函数
【示例】一元和二元通用函数的使用。
import numpy as np
arr = np.array([4, 9, 16])
print("一元通用函数的使用:")
print("求数组的平方根:\n",np.sqrt(arr))
print("求数组的绝对值:\n",np.abs(arr))
print("求数组的平方:\n",np.square(arr))
x = np.array([12, 9, 13, 15])
y = np.array([11, 10, 4, 8])
print("二元通用函数的使用:",)
print("计算两个数组的和:\n",np.add(x, y))
print("计算两个数组的乘积:\n", np.multiply(x, y))
print("两个数组元素级最大值的比较:\n",np.maximum(x, y))
print("执行元素级的比较操作:\n",np.greater(x, y))
运行结果:
一元通用函数的使用:
求数组的平方根:
[2. 3. 4.]
求数组的绝对值:
[ 4 9 16]
求数组的平方:
[ 16 81 256]
二元通用函数的使用:
计算两个数组的和:
[23 19 17 23]
计算两个数组的乘积:
[132 90 52 120]
两个数组元素级最大值的比较:
[12 10 13 15]
执行元素级的比较操作:
[ True False True True]
NumPy 数组可以将许多数据处理任务转换为简洁的数组表达式,它处理数据的速度要
比内置的 Python 循环快了至少一个数量级,所以,我们把数组作为处理数据的首选。接下
来,本节将讲解如何利用数组来处理数据,包括条件逻辑、统计、排序、检索数组元素以及
唯一化。
2.8.1 将条件逻辑转为数组运算
2.8.2 数组统计运算
2.8.3 数组排序
NumPy 的排序方式有直接排序和间接排序。直接排序是对数据直接进行排序,间接排
序是指根据一个或多个键值对数据集进行排序。
在 NumPy 中,直接排序经常使用 sort 函数,间接排序经常使用 argsort 函数和 lexsort
函数。
sort 函数是最常用的排序方法,函数调用改变原始数组,无返回值。sort 语法格式:
sort(a,axis,kind,order)
参数说明:
a:要排序的数组
axis:使得 sort 函数可以沿着指定轴对数据集进行排序。axis=1 为沿横轴排序;axis=0 为
沿纵横排序;axis=None,将数组平坦化之后进行排序。
kind:排序算法,默认为 quicksort
order:如果数组包含字段,则是要排序的字段。
【示例】利用 sort()方法对数组排序。
import numpy as np
arr = np.array([[4, 1, 7], [3, 9, 6], [8, 5, 2]])
arr_copy = arr
print("输出原数组:\n",arr)
arr.sort()
print("输出排序后的数组:\n",arr)
arr_copy.sort(0) # 沿着编号为 0 的轴对元素排序
print("沿着编号为 0 的轴对元素排序:\n",arr_copy)
从上述代码可以看出,当调用 sort()方法后,数组 arr 中数据按行从小到大进行排序。需
要注意的是,使用 sort()方法排序会修改数组本身。
使用 argsort 函数和 lexsort 函数,可以在给定一个或多个键时,得到一个由整数构成的
索引数组,索引值表示数据数据在新的序列中的位置。
【示例 2-】使用 argsort 函数和 lexsort 函数进行排序。
import numpy as np
arr = np.array([7,9,5,2,9,4,3,1,4,3])
print('原数组:',arr)
print('排序后:',arr.argsort())
# 返回值为数组排序后的下标排列
print('显示较大的 5 个数:',arr[arr.argsort()][-5:])
a = [1,5,7,2,3,-2,4]
b = [9,5,2,0,6,8,7]
ind=np.lexsort((b,a))
print('ind:',ind)
tmp=[(a[i],b[i])for i in ind]
print('tmp:',tmp)
运行结果:
原数组: [7 9 5 2 9 4 3 1 4 3]
排序后: [7 3 6 9 5 8 2 0 1 4]
显示较大的 5 个数: [4 5 7 9 9]
ind: [5 0 3 4 6 1 2]
tmp: [(-2, 8), (1, 9), (2, 0), (3, 6), (4, 7), (5, 5), (7, 2)]
2.8.4 检索数组元素
在 NumPy 中,all()函数用于判断整个数组中的元素的值是否全部满足条件,如果满足条
件返回 True,否则返回 False。
any()函数用于判断整个数组中的元素至少有一个满足条件就返回 True,否则返回 False。
【示例】使用 all()和 any()函数检索数组元素。
import numpy as np
arr = np.array([[4, -1, -7], [3, -9, 6], [8,-5, 2]])
arr_copy = arr
print("输出原数组:\n",arr)
print("arr 的所有元素是否有一个大于 0:\n",np.any(arr > 0))
print("arr 的所有元素是否都大于 0:\n",np.all(arr > 0) )
运行结果:
输出原数组:
[[ 4 -1 -7]
[ 3 -9 6]
[ 8 -5 2]]
arr 的所有元素是否有一个大于 0:
True
arr 的所有元素是否都大于 0:
False
2.8.5 重复数据与去重(唯一化)
在数学中经常会看到矩阵,而在程序中常用的是数组,可以简单理解为,矩阵是数学的
概念,而数组是计算机程序设计领域的概念。在 NumPy 中,矩阵是数组的分支,数组和矩
阵有些时候是通用的,二维数组也称为矩阵。
2.9.1 矩阵创建
运行结果:
创建 3*3 的 0(零)矩阵:
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
创建 2*3 的 1 矩阵:
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
创建 1~10 之间的随机整数矩阵:
[[2 9 9]
[9 8 4]
[5 6 5]]
创建 3*3 的对角矩阵:
[[1 0 0]
[0 1 0]
[0 0 1]]
创建 3*3 的对角线(1,2,3)矩阵:
[[1 0 0]
[0 2 0]
[0 0 3]]
2.9.2 矩阵运算
如果两个矩阵的大小相同,我们可以使用算术运算符“+”
“一”“牢”和“/”对矩阵
进行加、减、乘、除的运算。
【示例】矩阵的加、减、乘和除运算。
import numpy as np
# 创建矩阵
data_1 = np.mat([[1,2],[3,4],[5,6]])
data_2 = np.mat([1,2])
print("输出两个矩阵:\n 矩阵一:\n",data_1,'\n 矩阵二:\n',data_2)
print("输出两个矩阵的和:\n",data_1 + data_2)
print("输出两个矩阵的差:\n",data_1 - data_2)
print("输出两个矩阵的除:\n",data_1 / data_2)
data_3 = [[1,2],[3,4]]
print("输出两个矩阵的积:\n",data_1 * data_3)
运行结果:
输出两个矩阵:
矩阵一:
[[1 2]
[3 4]
[5 6]]
矩阵二:
[[1 2]]
输出两个矩阵的和:
[[2 4]
[4 6]
[6 8]]
输出两个矩阵的差:
[[0 0]
[2 2]
[4 4]]
输出两个矩阵的除:
[[1. 1.]
[3. 2.]
[5. 3.]]
输出两个矩阵的积:
[[ 7 10]
[15 22]
[23 34]]
矩阵的乘法运算,要求左边矩阵的列和右边矩阵的行数要一致。两个矩阵直接相乘,称
之为矩阵相乘。矩阵相乘是第一个矩阵中与该元素行号相同的元素与第二个矩阵与该元素列
号相同的元素,两两相乘后再求和。例如,1*1+2*3=7,是第一行元素与第二个矩阵与该元
素列号相同的元素,两两相乘后再求和得到。
要实现矩阵对应元素之间的相乘可以使用 multiply 函数。
数组运算和矩阵运算的一个关键区别是,矩阵相乘使用的是点乘。点乘,也称点积,是
数组中元素对应位置一一相乘之后求和的操作,在 NumPy 中专门提供了点乘方法,即 dot
方法,该方法返回的是两个数组的点积。
【示例】矩阵乘法的 dot()方法,求数组的点积。
import numpy as np
arr_x = np.array([[1, 2, 3], [4, 5, 6]])
arr_y = np.array([[1, 2], [3, 4], [5, 6]])
result = arr_x.dot(arr_y) # 等价于 np.dot(arr_x, arr_y)
print("输出两个矩阵的点积:\n",result)
运算结果:
输出两个矩阵的积:
[[22 28]
[49 64]]
矩阵点积的条件是矩阵 A 的列数等于矩阵 B 的行数,假设 A 为 m X p 的矩阵,B 为 p X
n 的矩阵,那么矩阵 A 与 B 的乘积就是一个 m X n 的矩阵 C,其中矩阵 C 的第 i 行第 j 列的
元素可以表示为:
2.9.3 矩阵转换
1.矩阵转置
矩阵转置与数组转置一样需要使用 T 属性。
2.矩阵求逆
矩阵要可逆,否则意味着该矩阵为奇异矩阵(即矩阵的行列式的值为 0)。矩阵求逆主
要使用 I 属性。
【示例】求矩阵的转置和逆。
import numpy as np
arr = np.mat([[1, 3, 3], [4, 5, 6], [7, 12, 9]])
arr_copy = arr
print("输出原矩阵:\n",arr)
print("输出转置后的矩阵:\n",arr.T)
print("输出矩阵的逆运算:\n",arr.I)
运行结果:
输出原矩阵:
[[ 1 3 3]
[ 4 5 6]
[ 7 12 9]]
输出转置后的矩阵:
[[ 1 4 7]
[ 3 5 12]
[ 3 6 9]]
输出矩阵的逆运算:
[[-0.9 0.3 0.1 ]
[ 0.2 -0.4 0.2 ]
[ 0.43333333 0.3 -0.23333333]]
2.10 数组读/写
2.10.1 读/写二进制文件
NumPy 提供了多种文件操作函数存取数组内容。文件存取的格式分为两类:二进制和
文本。二进制格式的文件又分为 NumPy 专用的格式化二进制类型和无格式类型。NumPy 中
读/写二进制文件的方法有以下两种。
(1)NumPy. load("文件名.npy"):从二进制的文件中读取数据。
(2)NumPy. save("文件名[.npy]"),arr):以二进制的格式保存数据。
它们会自动处理元素类型和 shape 等信息,使用它们读/写数组就非常方便。但是
np.save 输出的文件很难用其他语言编写的程序读入。
【例 2】数组的读与写。
import numpy as np
arr = np.arange(1,13).reshape(3,4)
print(arr)
np.save('arr.npy', arr) # np.save("arr", a)
data_arr = np.load( 'arr.npy' )
print(data_arr)
运行结果:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
2.10.2 读/写文本文件
NumPy 中读/写文本文件的主要方法有以下几种。
(1)NumPy. Ioadtxt("文件名.xt",delimiter=","):把文件加载到一个二维数组中。
(2)NumPy. savetxt( “文件名.txt”,arr, fmt="%d",delimiter=","):将数组写到某种分隔符
隔开的文本文件中。
(3)NumPy.genfromtxt("文件名.xt",delimiter=","):结构化数组和缺失数据。
【例 2-】读/写文本文件。
import numpy as np
arr_1 = np.arange(0,12,1).reshape(4,-1)
np.savetxt("arr_1_out.txt", arr_1)
#缺省按照'%.18e'格式保存数值
print(np.loadtxt("arr_1_out.txt"))
np.savetxt("arr_2_out.txt",arr_1, fmt = "%d", delimiter = ",")
#改为保存为整数,以逗号分隔
print(np.loadtxt("arr_2_out.txt",delimiter = ",")) # 读入的时候也需要指定逗号分隔
运行结果:
[[ 0. 1. 2.]
[ 3. 4. 5.]
[ 6. 7. 8.]
[ 9. 10. 11.]]
[[ 0. 1. 2.]
[ 3. 4. 5.]
[ 6. 7. 8.]
[ 9. 10. 11.]]
2.10.3 读取 CSV 文件
CSV 文件是一种常见的文件格式,用来存储批量数据(一维二维) 。
将数据写入 CSV 文件的方法:
1.np.savetxt(fname,array,fmt='%.18e',delimiter=None)
主要参数说明:
frame : 文件、字符串或产生器,可以是.gz 或.bz2 的压缩文件
array : 存入文件的数组
fmt : 写入文件的格式,例如:%d %.2f %.18e
delimiter :分割字符串,默认是任何空格。 例如: a = np.arange(100).reshape(5,20)
2.np.savetxt('a.csv',a,fmt='%d',delimiter=',')
主要参数说明:
np.loadtxt(fname,dtype=np.float,delimiter=None,unpack=False)
frame : 文件、字符串或产生器,可以是.gz 或.bz2 的压缩文件
dtype : 数据类型,可选
delimiter :分割字符串,默认是任何空格。
unpack :读入数据写入一个数组 如果是 True,读入属性将分别写入不同变量
例如: b = np.loadtxt('a.csv',delimiter=',')
b = np.loadtxt('a.csv',dtype = np.int,delimiter=',')
csv 文件的局限性:csv 只能有效存储一维和二维数组。
np.savetxt() 与 np.loadtxt() 只能有效存取一维和二维数据。
小结
习题
一、填空题
1.在 NumPy 中,可以使用数组对象________执行一些科学计算。
2.如果 ndarray.ndim 执行的结果为 2,则表示创建的是_____维数组。
3.NumPy 的数据类型是由一个类型名和元素________的数字组成。
4.如果两个数组的大小(ndarray.shape)不同,则它们进行算术运算时会出现________
机制。
5.花式索引是 NumPy 的一个术语,是指用整数________进行索引。
二、判断题
1.通过 empty()函数创建的数组,该数组中没有任何的元素。( )
2.如果没有明确地指明数组中元素的类型,则默认为 float64。 ( )
3.数组之间的任何算术运算都会将运算应用到元素级。( )
4.多维数组操作索引时,可以将切片与整数索引混合使用。( )
5.当通过布尔数组索引操作数组时,返回的数据是布尔数组中 False 对应位置的值。 ( )
三、选择题
1.下列选项中,用来表示数组维度的属性是( ) 。
A.ndim
B.shape
C.size
D.dtype
2.下面代码中,创建的是一个 3 行 3 列数组的是( ) 。
1.arr = np.array([1, 2, 3])
2.arr = np.array([[1, 2, 3], [4, 5, 6]])
3.arr = np.array([[1, 2], [3, 4]])
4.np.ones((3, 3))
3.请阅读下面一段程序:
arr_2d = np.array([[11, 20, 13],[14, 25, 16],[27, 18, 9]])
print(arr_2d[1, :1])
执行上述程序后,最终输出的结果为( ) 。
A.[14]
B.[25]
C.[14, 25]
D.[20, 25]
4.请阅读下面一段程序:
arr = np.arange(6).reshape(1, 2, 3)
print(arr.transpose(2, 0, 1))
执行上述程序后,最终输出的结果为( ) 。
A.
[[[2 5]]
[[0 3]]
[[1 4]]]
B.
[[[1 4]]
[[0 3]]
[[2 5]]]
C.
[[[0 3]]
[[1 4]]
[[2 5]]]
D.
[[[0]
[3]]
[[1]
[4]]
[[2]
[5]]]
5.下列函数或方法中,用来表示矢量化三元表达式的是( ) 。
A.where()
B.cumsum()
C.sort()
D.unique()
四、简答题
1.什么是矢量化运算?
2.实现数组广播机制需要满足哪些条件?
五、程序题
1.创建一个数组,数组的 shape 为(5,0),元素都是 0。
2.创建一个表示国际象棋棋盘的 8*8 数组,其中,棋盘白格用 0 填充,棋盘黑格用 1 填
充。