数组的创建的背景
列表只是一种数据的存储容器,它不具有任何计算能力!
数组的创建
借助于array函数可以将列表或元组转换为数组。
利用arange、linspace、empty等函数生成数组示例
注:empty函数只分配数组所使用的内存,不对数组元素值进行初始化操作,因此它的运行速度是最快的,上述程序中c=np.empty((2,3),int)的返回值是随机的,每次运行都是不一样的。
使用虚数单位“j”生成数组
数组的属性
为了更好地理解和使用数组,了解数组的基本属性是十分必要的。数组的属性及其说明如表所列
属性 | 说明 |
---|---|
ndim | 返回int,表示数组的维数 |
shape | 返回元组,表示数组的尺寸,对于行列的矩阵,返回值为 |
size | 返回int,表示数组的元素总数,等于shape属性返回元组中所有元素的乘积 |
dtype | 返回数据类型 |
itemsize | 返回int,表示数组每个元素的大小(以字节为单位) |
生成一个的上取值的随机整数矩阵,并显示它的各个属性。
生成数学一维向量的三种模式
注:形状为(1,n),(n,1),(n,)的array数组意义是不同的;形状为(n,)的一维数组既可以看成行向量,又可以看成列向量,它的转置不变。
数组元素的索引
NumPy中的array数组与Python基础数据结构列表(list)的区别是:列表中的元素可以是不同的数据类型,而array数组只允许存储相同的数据类型。
①对于一维数组来说,Python原生的列表和NumPy的数组的切片操作都是相同的,无非是记住一个规则:列表名(或数组名)[start: end: step],但不包括索引end对应的值。
②二维数据列表元素的引用方式为a[i][j];array数组元素的引用方式为a[i,j]。
NumPy比一般的Python 序列提供更多的索引方式。除了用整数和切片的一般索引外,数组还可以布尔索引及花式索引。
(1)一般索引
#需要特别注意,python中数据的首个元素的下标是0
如上结果所示,在一维数组的索引中,可以将任意位置的索引组装为列表,用作对应元素的获取;在二维数组中,位置索引必须写成[rows,cols]的形式,方括号的前半部分用于控制二维数组的行索引,后半部分用于控制数组的列索引。如果需要获取所有的行或列元素,那么,对应的行索引或列索引需要用英文状态的冒号表示。
(2)布尔索引
(3)花式索引
花式索引的索引值是一个数组。对于使用一维整型数组作为索引,如果被索引数据是一维数组,那么索引的结果就是对应位置的元素;如果被索引数据是二维数组,那么就是对应下标的行。
对于二维被索引数据来说,索引值可以是二维数据,当索引值为两个维度相同的一维数组组成的二维数组时,以两个维度作为横纵坐标索引出单值后组合成新的一维数组。
数组的修改
这里数组的修改是指数组元素的修改,和数组维数的扩大或缩小。
数组修改示例。
数组的变形
在对数组进行操作时,经常要改变数组的维度。在NumPy中,常用reshape函数改变数据的形状,也就是改变数组的维度。其参数为一个正整数元组,分别指定数组在每个维度上的大小。reshape函数在改变原始数据的形状的同时不改变原始数据的值。如果指定的维度和数组的元素数目不吻合,则函数将抛出异常.
数据变形和转换的一些函数如表所列(假设数组为a,b,相关操作维度是兼容的):
函数 | 功能 | 调用方式 |
---|---|---|
reshape | 改变数组的维度 | a.reshape(m,n,s)把a变成m个n行s列的数组,返回的是视图,a本身不变 |
resize | 改变数组的维度 | a.resize(m,n,s)把a变成m个n行s列的数组,没有返回,改变的是a数组 |
c_ | 列组合 | c_[a,b],构造分块数组[a,b] |
r_ | 行组合 | r_[a,b],构造分块数组 |
ravel | 水平展开数组 | a.ravel()返回的是a的视图 |
flatten | 水平展开数组 | a.flatten()返回的是真实数组,需要分配新的内存空间 |
hstack | 数组横向组合 | hstack((a,b)),输入参数为元组(a,b) |
vstack | 数组纵向组合 | vstack((a,b)) |
concatenate | 数组横向或纵向组合 | concatenate((a,b),axis=1),同hstack concatenate((a,b),axis=0),同vstack |
dstack | 深度组合,如在一副图像数据的二维数组上组合另一幅图像数据 | dstack((a,b)) |
hsplit | 数组横向分割 | hsplit(a,n)把a平均分成n个列数组 |
vsplit | 数组纵向分割 | vsplit(a,m)把a平均分成m个行数组 |
split | 数组横向或纵向分割 | split(a,n,axis=1)同hsplit(a,n); split(a,n,axis=0)同vsplit(a,n) |
dsplit | 沿深度方向分割数组 | dsplit(a,n)沿深度方向平均分成n个数组 |
tolist | 把数组转换成Python列表 | a.tolist() |
reshape和resize变形示例
如上结果所示,虽然reshape和resize都是用来改变数组形状的,但是reshape只是返回改变形状后的视图,数组本身是不变的;而resize没有返回,直接改变数组本身的形状。
如果需要将多维数组降为一维数组,利用ravel、flatten和reshape三种方法均可以实现。
从显示效果看,三种方法是一样的,原数组都没有修改。但我们在平时使用时,flatten()比较合适,在使用过程中flatten()分配了新的内存;ravel()返回的是一个数组的视图,e=b.ravel()是允许的。
数组分割示例。
数组组合效果示例
数组的运算、通用函数和广播运算
四则运算
在NumPy库中,实现四则运算既可以使用运算符号+、-、*、/,也可以使用函数add、substract、multiply、divide。需要注意的是,函数只能接受两个对象的运算,如果需要多个对象的运算,就得使用嵌套方法。
另外还有三个数学运算符,分别是余数、整除和幂次,可以使用符号%、//、**,也可以使用函数fmod、modf和power。但是整除的函数应用会稍微复杂一点,需要写成np.modf(a/b)[1]的格式,因为modf可以返回数值的小数部分和整数部分,而整数部分就是要取的整数值。
数组简单运算示例
比较运算
数组间的比较运算如表所示的六种。
比较运算符及其含义
符号 | 函数 | 含义 |
---|---|---|
> | greater(a,b) | 判断a的元素是否大于b的元素 |
>= | greater_equal(a,b) | 判断a的元素是否大于等于b的元素 |
< l | ess(a,b) | 判断a的元素是否小于b的元素 |
<= | less_equal(a,b) | 判断a的元素是否小于等于b的元素 |
== | equal(a,b) | 判断a的元素是否等于b的元素 |
!= | not_equal(a,b) | 判断a的元素是否不等于b的元素 |
运用比较运算符返回的是bool类型的值,即True和False.
通过上述运行结果可以看出,多维数组通过bool索引返回的都是一维数组;np.where返回的数组保持原来的形状。
ufunc函数
ufunc函数全称为通用函数,是一种能够对数组中的逐个元素进行操作的函数。ufunc函数是针对数组进行操作的,并且都以NumPy数组作为输出。使用ufunc函数比使用math库中的函数效率要高很多。目前NumPy支持超过60多种的通用函数。这些函数包括广泛的操作,如四则运算、求模、取绝对值、幂函数、指数函数、三角函数、位运算、比较运算和逻辑运算等。
ufunc函数效率示例
可以发现对数组的操作,numpy函数整体花费的时间比math模块函数要少得多。
ufunc函数的广播机制
广播(Broadcasting)是指不同形状的数组之间执行算术运算的方式。当使用ufunc函数进行数组计算时,ufunc函数会对两个数组的对应元素进行计算。进行这种计算的前提是两个数组的维度相容。若两个数组的维度不相容时,则NumPy会实行广播机制。但是数组的广播功能是有规则的,如果不满足这些规则,运算时就会出错。数组的主要广播规则为:
(1)各输入数组的维度可以不相等,但必须确保从右到左的对应维度值相等。
(2)如果对应维度值不相等,就必须保证其中一个为1。
NumPy 迭代数组umPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
迭代器最基本的任务的可以完成对数组元素的访问。
接下来我们使用 arange() 函数创建一个 2X3 数组,并使用 nditer 对它进行迭代。
控制遍历顺序
for x in np.nditer(a, order='F'):Fortran order,即是列序优先;
for x in np.nditer(a.T, order='C'):C order,即是行序优先;
nditer类的构造器拥有flags参数,它可以接受下列值:
参数 | 描述 |
---|---|
c_index | 可以跟踪 C 顺序的索引 |
f_index | 可以跟踪 Fortran 顺序的索引 |
multi-index | 每次迭代可以跟踪一种索引类型 |
external_loop | 给出的值是具有多个值的一维数组,而不是零维数组 |
在下面的实例中,迭代器遍历对应于每列,并组合为一维数组。
NumPy.random模块的随机数生成
虽然在Python内置的random模块中可以生成随机数,但是每次只能随机生成一个随机数,而且随机数的种类也不够丰富。建议使用NumPy.random模块的随机数生成函数,一方面可以生成随机向量,另一方面函数丰富。关于各种常见的随机数生成函数,如表所列。
函数 | 说明 |
---|---|
seed(n) | 设置随机数种子 |
beta(a,b,size=None) | 生成Beta分布随机数 |
chisquare(df,size=None) | 生成自由度为df的分布随机数 |
choice(a,size=None,replace=None,p=None) | 从a中有放回地随机挑选指定数量的样本 |
exponential(scale=1.0,size=None) | 生成指数分布随机数 |
f(dfnum,dfden,size=None) | 生成F分布随机数 |
gamma(shape,scale=1.0,size=None) | 生成伽玛分布随机数 |
geometric(p,size=None) | 生成几何分布随机数 |
hypergeometric(ngood,nbad,nsample,size=None) | 生成超几何分布随机数 |
laplace(loc=0.0,scale=1.0,size=None) | 生成Laplace分布随机数 |
logistic(loc=0.0,scale=1.0,size=None) | 生成Logistic分布随机数 |
lognormal(mean=0.0,sigma=1.0,size=None) | 生成对数正态分布随机数 |
negative_binomial(n,p,size=None) | 生成负二项分布随机数 |
multinomial(p,pvals,size=None) | 生成多项分布随机数 |
multivariate_normal(mean,cov[,size]) | 生成多元正态分布随机数 |
normal(loc=0.0,scale=1.0,size=None) | 生成正态分布随机数 |
pareto(a,size=None) | 生成帕累托分布随机数 |
poisson(lam=1.0,size=None) | 生成泊松分布随机数 |
rand(d0,d1,…,dn) | 生成n+1维的[0,1)上均匀分布随机数 |
randn(d0,d1,…,dn) | 生成n+1维的标准正态分布随机数 |
randint(low, high=None, size=None, dtype=‘l’) | 生成区间[low,high)上的随机整数 |
random_sample(size=None) | 生成[0,1)上的随机数 |
standard_t(df,size=None) | 生成标准的分布随机数 |
uniform(low=0.0,hign=1.0,size=None) | 生成区间[low,high)上均匀分布随机数 |
wald(mean,scale,size=None) | 生成Wald分布随机数 |
weibull(a,size=None) | 生成Weibull分布随机数 |
文本文件和二进制文件存取
NumPy提供了多种文件操作函数以方便用户存取数组内容。文件存取的格式分为两类:二进制和文本。而二进制格式的文件又分为NumPy专用的格式化二进制类型和无格式类型。
文本文件的存取
- savetxt()和loadtxt()存取文本文件
savetxt()可以把1维和2维数组保存到文本文件。loadtxt()可以把文本文件中的数据加载到1维和2维数组中。
文本文件存取示例:
文本文件Pdata2_19.txt中存放如下格式的数据:
6 2 6 7 4 2 5 9
4 9 5 3 8 5 8 2
5 2 1 9 7 4 3 3
7 6 7 3 9 2 7 1
2 3 9 5 7 2 6 5
5 5 2 2 8 1 4 3
把其中的数据读入到数组a,并提取数组a的前2行、第2列到第4列的元素,构造一个2行3列的数组b。
文本文件Pdata2_20.txt中存放如下格式的数据:
姓名,年龄,体重,身高
张三,30,75,165
李四,45,60,179
王五,15,39,120
提取其中的数值数据
如果需要处理复杂的数据结构,比如处理缺失数据等情况,可以使用genfromtxt。
genfromtxt读入文本文件数据
它的调用格式为:
genfromtxt(fname, dtype=<class ‘float’>, comments=’#’, delimiter=None, skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None, usecols=None, names=None, excludelist=None, deletechars=None, replace_space=’_’, autostrip=False, case_sensitive=True, defaultfmt=‘f%i’, unpack=None, usemask=False, loose=True, invalid_raise=True, max_rows=None, encoding=‘bytes’)
我们介绍其中的一些常用参数:
(1)fname:指定需要读入数据的文件名。
(2)dtype:指定读入数据的数据类型,默认为浮点型,如果原数据集中含有字符型数据,必须指定数据类型为“str”。
(3)comments:指定注释符,默认为“#”,如果原数据的行首有“#”,将忽略这些行的读入。
(4)delimiter:指定数据集的列分隔符。
(5)skip_header:是否跳过数据集的首行,默认不跳过。
(6)skip_footer:是否跳过数据集的脚注,默认不跳过。
(7)converters:将指定列的数据转换成其他数值。
(8)miss_values:指定缺失值的标记,如果原数据集含指定的标记,读入后这样的数据就为缺失值。
(9)filling_values:指定缺失值的填充值。
(10)usecols:指定需要读入的列。
(11)names:为读入数据的列设置列名称
(12)encoding:如果文件中含有中文,有时需要指定字符编码
纯文本文件Pdata2_21.txt中存放如下数据。分别读取其中的前6行前8列数据、第9列的数值数据、最后一行数据。
6 2 6 7 4 2 5 9 60kg
4 9 5 3 8 5 8 2 55kg
5 2 1 9 7 4 3 3 51kg
7 6 7 3 9 2 7 1 43kg
2 3 9 5 7 2 6 5 41kg
5 5 2 2 8 1 4 -999 52kg
35 37 22 32 41 32 43 38
二进制格式文件存取
tofile()和fromfile()存取二进制格式文件
使用数组对象的tofile()方法可以方便地将数组中的数据以二进制格式写进文件,tofile()输出的数据不保存数组形状和元素类型等信息。因此用fromfile()函数读回数据时需要用户指定元素类型,并对数组的形状进行适当的修改。
load()、save()和savez()存取NumPy专用的二进制格式文件
load()和save()用NumPy专用的二进制格式存取数据,它们会自动处理元素类型和形状等信息。
如果想将多个数组保存到一个文件中,可以使用savez()。savez()的第一个参数是文件名,其后的参数都是需要保存的数组,输出的是一个扩展名为npz的压缩文件。
用解压软件打开“Pdata2_23_2.npz”文件,会发现其中有两个文件:“arr_0.npy”、“arr_1.npy”,其中分别保存着数组c、d的内容。load()自动识别npz文件,并且返回一个类似于字典的对象,可以通过数组名作为键获取数组的内容。