You are on page 1of 20

第2章 NumPy 数组计算

学习目标
认识 NumPy 数组对象,会创建 NumPy 数组。
熟悉 ndarray 对象的数据类型,并会转换数据类型。
掌握数组运算方式。
掌握数组的索引和切片。
会使用数组进行数据处理。
熟悉线性代数模块和随机数模块的使用。

NumPy 是 Numerical Python 的简称,是在 1995 年诞生的 Python 库 Numeric 的基础上建


立起来的,属于 Python 语言的一个开源数值计算的扩展程序库。Numpy 包含了数组计算、
数值积分、傅里叶变换和线性代数运算等功能。

2.6 数组的重塑和转置

2.6.1 数组重塑

数组重塑实际是更改数组的形状,例如,将原来 2 行 3 列的数组重塑为 3 行 2 列的数


组。在 NumPy 中主要使用 reshape 方法,该方法用于改变数组的形状。与 reshape 相反的方
法是数据散开(ravel)或数据扁平化(flatten) 。
一维数组重塑就是将数组重塑为多行多列的数组。 多维数组重塑同样使用 reshape 方法。
【示例】使用 reshape 方法实现数组重塑。
import numpy as np
arr = np.arange(6)
print("创建的一维数组为:\n",arr)
arr2d = arr.reshape(2,3)
print("由一维变二维数组为:\n",arr2d)
arr2d = np.array([[1,4,7],[2,5,8]])
arr2d_new = arr2d.reshape(3,2)
print("改变数组维度为:\n",arr2d_new)
arr2d_r = arr2d.ravel()
print("数据散开为:\n",arr2d_r)
运行结果:
创建的一维数组为:
[0 1 2 3 4 5]
由一维变二维数组为:
[[0 1 2]
[3 4 5]]
改变数组维度为:
[[1 4]
[7 2]
[5 8]]
数据散开为:
[1 4 7 2 5 8]
要注意的是,数组重塑是基于数组元素不发生改变的情况下实现的,重塑后的数组所包
含的元素个数必须与原数组的元素个数相同,如果数组元素发生改变,程序就会报错。即数
据重塑不会改变原来的数组。

2.6.2 数组合并

数组合并用于多个数组间的操作,NumPy 使用 hstack、vstack 和 concatenate 函数完成


数组的组合。
横向合并是将 ndarray 对象构成的元组作为参数,传给 hstack 函数。
纵向合并是使用 vstack 对象将数组合并。
【示例 2-】数组纵、横合并。
import numpy as np
arr1 = np.array([[1,2],[3,4],[5,6]])
arr2 = np.array([[10,20],[30,40],[50,60]])
h_arr = np.hstack((arr1,arr2))
print("横向方向合并数据后的数组:\n",h_arr)
v_arr = np.vstack((arr1,arr2))
print("纵向方向合并数据后的数组:\n",v_arr)
运行结果:
横向方向合并数据后的数组:
[[ 1 2 10 20]
[ 3 4 30 40]
[ 5 6 50 60]]
纵向方向合并数据后的数组:
[[ 1 2]
[ 3 4]
[ 5 6]
[10 20]
[30 40]
[50 60]]

【例 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 数组分割

与数组合并相反,NumPy 提供了 hsplit、vsplit 和 split 分别实现数组的横向、纵向和指


定方向的分割。
import numpy as np
arr = np.arange(16).reshape(4,4)
print("输出数组:\n",arr)
h_arr = np.hsplit(arr,2)
print("横向分割数组为:\n",h_arr)
v_arr = np.vsplit(arr,2)
print("纵向分割数组为:\n",v_arr)
运行结果:
输出数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
横向分割数组为:
[array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]]), array([[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15]])]
纵向分割数组为:
[array([[0, 1, 2, 3],
[4, 5, 6, 7]]), array([[ 8, 9, 10, 11],
[12, 13, 14, 15]])]
同样,split 在参数 axis=1 时实现数组的横向分割,axis=0 时则进行纵向分割。

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.7 NumPy 通用函数(ufunc)

通用函数是一种针对 ndarray 中的所有数据执行元素级运算的函数,函数返回的是一个


新的数组。
在 NumPy 中,提供了诸如“sin” 、“cos”和“exp”等常见的数学函数,这些函数叫做
通用函数( ufunc)。ufunc 函数针对数组进行操作,而且以 NumPy 数组作为输出。
通常情况下,我们将 ufunc 中接收一个数组参数的函数称为一元通用函数,而接收两个
数组参数的则称为二元通用函数。表 2-4 和表 2-5 列举了一些常见的一元和二元通用函数。
表 2-4 常见一元通用函数

表 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]

2.8 NumPy 数据处理与统计分析

NumPy 数组可以将许多数据处理任务转换为简洁的数组表达式,它处理数据的速度要
比内置的 Python 循环快了至少一个数量级,所以,我们把数组作为处理数据的首选。接下
来,本节将讲解如何利用数组来处理数据,包括条件逻辑、统计、排序、检索数组元素以及
唯一化。

2.8.1 将条件逻辑转为数组运算

NumPy 的 where()函数是三元表达式 x if condition else y 的矢量化版本。


【示例】 假设有两个数值类型的数组和一个布尔类型的数组,当 arr_con 的元素值为 True
时,从 arr_ x 数组中获取一个值,否则从 arr_y 数组中获取一个值。
import numpy as np
arr_x = np.array([1, 5, 7])
arr_y = np.array([2, 6, 8])
arr_con = np.array([True, False, True])
result = np.where(arr_con, arr_x, arr_y)
print(result)
运算结果:
[1 6 7]
上述代码中调用 np.where()时,传入的第 1 个参数 arr_con 表示判断条件,它可以是一
个布尔值,也可以是一个数组,这里传入的是一个布尔数组。
当满足条件(从 arr_con 中取出的元素为 True)时,则会获取 arr_x 数组中对应位置的
值。由于 arr_con 中索引为 0、2 的元素为 True,所以取出 arr_x 中相应位置的元素 1、7。
当不满足条件(从 arr_con 中取出的元素为 False)时,则会获取 arr_y 数组中对应位置
的值。由于 arr_con 中索引为 1 的元素为 False,所以取出 arr_y 中相应位置的元素 6。
从输出结果可以看出,使用 where()函数进行数组运算后,返回了一个新的数组。

2.8.2 数组统计运算

NumPy 中提供了很多用于统计分析的函数,常见的有 sum、mean、std、var、min 和 max


等,比如计算数组极大值、极小值以及平均值等。几乎所有的统计函数在针对二维数组时都
需要注意轴的概念。当 axis 参数为 0 时,表示沿着纵轴进行计算;当 axis=1 时表示沿横轴
进行计算。表 2-6 列举了 NumPy 数组中与统计运算相关的方法。
表 2-6 NumPy 数组中与统计运算相关的方法

需要注意的是,当使用 ndarray 对象调用 cumsum()和 cumprod()方法后,产生的结果是


一个由中间结果组成的数组。
【示例】数组统计函数的应用。
import numpy as np
arr = np.arange(10)
print("输出数组元素:",arr)
print("所有数组元素求和:",arr.sum())
print("所有数组元素求平均值:",arr.mean())
print("所有数组元素求最小值:",arr.min())
print("所有数组元素求最大值:",arr.max())
print("所有数组元素求最小值的索引:",arr.argmin())
print("所有数组元素求最大值的索引:",arr.argmax())
print("所有数组元素求累计和:",arr.cumsum())
print("所有数组元素求累计积:",arr.cumprod())
运行结果:
输出数组元素: [0 1 2 3 4 5 6 7 8 9]
所有数组元素求和: 45
所有数组元素求平均值: 4.5
所有数组元素求最小值: 0
所有数组元素求最大值: 9
所有数组元素求最小值的索引: 0
所有数组元素求最大值的索引: 9
所有数组元素求累计和: [ 0 1 3 6 10 15 21 28 36 45]
所有数组元素求累计积: [0 0 0 0 0 0 0 0 0 0]

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 中,可以通过 unique 函数找


到数组中的唯一值并返回已排序的结果,其中的参数 return_counts 设置为 True 时可以返回
每个取值出现的次数。
1.去重复数据
【示例 2-】数组内数据去重。
import numpy as np
color_list = np.array(['黑色','红色','蓝色','蓝色','白色','红色','红色'])
print('原数组:',color_list)
print('去重后的数组:',np.unique(color_list))
print('数据出现次数:',np.unique(color_list,return_counts=True))
运行结果:
原数组: ['黑色' '红色' '蓝色' '蓝色' '白色' '红色' '红色']
去重后的数组: ['白色' '红色' '蓝色' '黑色']
数 据 出 现次 数 : (array([' 白 色 ', '红 色 ', '蓝色 ', '黑色 '], dtype='<U2'), array([1, 3, 2, 1],
dtype=int64))
2.数据重复
统计分析中有时需要把一个数据重复若干次,在 NumPy 中主要使用 tile 和 repeat 函数
实现数据重复。
(1)tile 函数的格式:
title(a, reps)
其中参数 a 表示要重复的数组,reps 表示重复次数。
【示例 2-】使用 title 函数实现数据重复。
import numpy as np
arr = np.arange(5)
print('原数组:',arr)
dup_arr = np.tile(arr,3)
print('重复 3 次数据:\n', dup_arr)
运行结果:
原数组: [0 1 2 3 4]
重复 3 次数据:
[0 1 2 3 4 0 1 2 3 4 0 1 2 3 4]
(2)repeat 函数的格式:
repeat ( a, reps, axis=None)
其中,参数 a 是需要重复的数组元素,参数 reps 是重复次数,参数 axis 指定沿着哪个
轴进行重复;axis=0 表示按行进行元素重复,axis=1 表示按列进行元素重复。
【示例 2-】使用 repeat 函数实现数据重复。
import numpy as np
arr = np.arange(5)
print('原数组:',arr)
dup_arr = np.tile(arr,3)
print('重复数据 3 次:\n',dup_arr )
dup_arr_2 = np.array([[1,2,3],[4,5,6]])
print('重复数据处理:\n',dup_arr_2.repeat(2,axis=0))
运行结果:
原数组: [0 1 2 3 4]
重复数据 3 次:
[0 1 2 3 4 0 1 2 3 4 0 1 2 3 4]
重复数据处理:
[[1 2 3]
[1 2 3]
[4 5 6]
[4 5 6]]
3.判断数组元素是否存在
一个 in1d()函数用于判断数组中的元素是否在另一个数组中存在,该函数返回的是一个
布尔型的数组。
【示例】从一个元组中去重和判断一个数组元素是否在另一个数组中。
import numpy as np
arr = np.array([16, 19, 18, 23, 14, 8, 14])
print("输出原数组:\n",arr)
print("输出去掉重复元素后的数组:\n",np.unique(arr))
arr_2 = [16,18]
print("判断一个数组中的元素是否在另一数组中存在:\n",np.in1d(arr,arr_2))
运行结果:
输出原数组:
[16 19 18 23 14 8 14]
输出去掉重复元素后的数组:
[ 8 14 16 18 19 23]
判断一个数组中的元素是否在另一数组中存在:
[ True False True False False False False]
NumPy 提供的有关集合的函数还有很多,表 2-7 列举了数组集合运算的常见函数。
表 2-7 数组集合运算的常见函数

2.9 NumPy 矩阵的基本操作

在数学中经常会看到矩阵,而在程序中常用的是数组,可以简单理解为,矩阵是数学的
概念,而数组是计算机程序设计领域的概念。在 NumPy 中,矩阵是数组的分支,数组和矩
阵有些时候是通用的,二维数组也称为矩阵。
2.9.1 矩阵创建

NumPy 函数库中存在两种不同的数据类型(矩阵 matrix 和数组 array),它们都可以用


于处理行列表示的数组元素,虽然它们看起来很相似,但是在这两个数据类型上执行相同的
数学运算时,可能得到不同的结果。
在 NumPy 中,矩阵应用十分广泛。例如,每个图像可以被看作为像素值矩阵。假设一
个像素值仅为 0 和 1,那么 256 X 256 大小的图像就是一个 256 X 256 的矩阵。
【示例】创建一个矩阵,判断类型后并输出。
import numpy as np
data_one = np.mat('1 4 7;2 5 8')
data_two = np.mat([[3,6,9],[6,6,6]])
print("输出矩阵 1:\n",data_one)
print("输出矩阵 1 的类型为:\n",type(data_one))
print("输出矩阵 2:\n",data_two)
print("输出矩阵 2 的类型为:\n",type(data_two))
运行结果:
输出矩阵 1:
[[1 4 7]
[2 5 8]]
输出矩阵 1 的类型为:
<class 'numpy.matrix'>
输出矩阵 2:
[[3 6 9]
[6 6 6]]
输出矩阵 2 的类型为:
<class 'numpy.matrix'>
从运行结果来看,mat 函数创建的是矩阵类型。
【示例】利用 mat 函数生成常见的矩阵。
import numpy as np
data_1 = np.mat(np.zeros((3,3)))
print("创建 3*3 的 0(零)矩阵:\n",data_1)
data_2 = np.mat(np.ones((3,3)))
print("创建 2*3 的 1 矩阵:\n",data_2)
data_3 = np.mat(np.random.randint(1,10,size=(3,3)))
print("创建 1~10 之间的随机整数矩阵:\n",data_3)
data_4 = np.mat(np.eye(3,3,dtype=int))
print("创建 3*3 的对角矩阵:\n",data_4)
b = [1,2,3]
data_5 = np.mat(np.diag(b))
print("创建 3*3 的对角线(1,2,3)矩阵:\n",data_5)

运行结果:
创建 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 列的
元素可以表示为:

上述矩阵 arr_x 与 arr_y 的乘积如图 2-10 所示。


* =

图 2-10 矩阵 arr x 与 arr_y 的乘积


numpy.linalg 模块中有一组标准的矩阵分解运算以及诸如逆和行列式之类的方法,linalg
模块中还提供了其他很多有用的函数,具体如表 2-8 所示。
表 2-8 linalg 模块的常见函数

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() 只能有效存取一维和二维数据。
小结

本章主要针对科学计算库 NumPy 进行了介绍,包括 ndarry 数组对象的属性和数据类型、数


组的运算、索引和切片操作、数组的转置和轴对称、NumPy 通用函数、线性代数模块、随机
数模块以及使用数组进行数据处理的相关操作。
通过本章的学习,希望大家能熟练使用 NumPy 包,为后面章节的学习奠定基础。

习题

一、填空题
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 填
充。

You might also like