1.1 NumPy数组的创建与保存
创建NumPy数组一般有以下3种方法。
● 通过传入可迭代对象创建,这是基本方法。
● 使用NumPy内部功能函数创建,这是一种通用方法。
● 读取外部数据创建。
1.1.1 使用基本方法创建数组
基本方法是对已知可迭代对象创建ndarray数组,即通过在NumPy提供的array()方法中传入可迭代对象来创建数组。这种方法通常是在已知所有元素的情况下使用的。
基本方法的实现格式:np.array([可迭代对象])。
那什么是可迭代对象?Python可以对列表、元组、字典、字符串等类型的数据使用for...in...循环语法,从其中依次读取数据,我们把这样的过程称为遍历,也叫迭代。所以,我们把能够通过for...in...这类语句迭代读取一条条数据供用户使用的对象称为可迭代对象。
在NumPy中创建数组的基本方法如下。
【动动手练习1-1】 使用基本方法创建数组
>>>import numpy as np >>> np.array([0, 1, 2, 3, 4]) #接收一个列表作为参数 array([0, 1, 2, 3, 4]) >>> np.array([[11, 12, 13],[21, 22, 23]]) #创建一个2*3的二维数组 array([[11, 12, 13], [21, 22, 23]]) >>> np.array([[[1,2,3],[1,2,0]],[[5,6,7],[9,8,7]]]) #创建一个 2*2*3 的三维数组,可以将其理解为由两个或更多个二维数组组成三维数组。同样地,四维数组可以被理解为由两个或更多 个三维数组生成 array([[[1, 2, 3], [1, 2, 0]], [[5, 6, 7], [9, 8, 7]]]) >>> np.array((0, 1, 2, 3, 4)) #接收一个元组作为参数 array([0, 1, 2, 3, 4]) #np.array()方法可以在创建数组的同时指定数据类型 >>> np.array([0, 1, 2, 3, 4], dtype=float) #注意数据类型使用dtype定义 array([0., 1., 2., 3., 4.]) #还可以将创建整数列表的range()函数返回的可迭代对象作为参数 >>> np.array(range(5)) array([0, 1, 2, 3, 4]) >>> np.array(range(10, 20, 2)) array([10, 12, 14, 16, 18]) >>>type(np.array(range(5))) #查看变量类型 numpy.ndarray
ndarray是同一个数据类型的数组,后面会有更详细的介绍。实现以下语句,查看返回的ndarray各元素的值。
np.array([0, 1, 2, 3, 4], dtype=str) np.array([0, 1, 2, 3, 4], dtype=bool)
1.1.2 使用通用方法创建数组
通用方法指的是由NumPy提供的np.arange()、np.linspace()、np.ones()、np.zeros()、np.eye()、np.full()、np.random.random()、np.random.randint()方法直接生成数组。这些方法可以按照某种规则生成一个数组,并不需要传入已知的可迭代对象。
【动动手练习1-2】 使用通用方法创建数组
(1)np.arange()方法。
前面我们将range()函数的结果传递给np.array(),是对已知可迭代对象创建ndarray数组,这和NumPy中的np.arange()方法实现的功能是一样的。np.arange()方法是直接生成数组,可以说np.arange()方法就是NumPy中的range()方法。
>>> np.arange(5) array([0, 1, 2, 3, 4]) >>> np.arange(10, 20, 2) array([10, 12, 14, 16, 18])
(2)np.linspace()方法。
np.linspace()方法以等间距的形式划分给定的数来创建数组。
>>> np.linspace(10, 20, 5) #将10~20的数等距取5个 array([10. , 12.5, 15. , 17.5, 20. ])
(3)np.ones()方法。
np.ones()方法用于创建一个元素值全为1的数组,接收一个列表或者元组作为参数,这些参数决定创建数组的维数。
>>> np.ones([2]) #创建一个一维数组 array([1., 1.]) >>> np.ones([2, 2]) #创建一个二维数组 array([[1., 1.], [1., 1.]]) >>>np.ones([2, 3, 3],dtype=int) #创建一个三维数组,该数组由2个3*3的二维数组组成 array([[[1, 1, 1], [1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]]])
(4)np.zeros()方法。
np.zeros()方法用于创建一个元素值全为0的数组,接收一个列表或者元组作为参数。
>>> np.zeros([3]) #创建一个一维数组,参数是一个列表[3] array([0., 0., 0.]) >>> np.zeros((3, 3)) #创建一个二维数组,参数是一个元组(3, 3) array([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])
(5)np.eye()方法。
np.eye()方法用于创建一个从左上角到右下角的对角线上的元素值全为1,其余元素值全为0的数组(单位矩阵)。注意,np.eye()方法的参数可不再是列表或者元组了。
>>> np.eye(3, 3) #注意np.eye()方法与np.zeros()、np.ones()方法参数的区别,np.eye()方法的参数是两个数值 array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) >>> np.eye(2, 3) array([[1., 0., 0.], [0., 1., 0.]])
可以将对称的矩阵(如上面的np.eye(3, 3))简写为np.eye(3),其结果是相同的。
当然,以上生成数组的数值类型默认是浮点型,如果设置为其他数值类型可使用dtype定义。
(6)np.full()方法。
np.full()方法可以创建一个填充给定数值的数组。数组由两个参数组成:第1个参数是定义数组形状的列表或元组,第2个参数是需要填充的数值。
>>> np.full((2, 3), 3) #创建一个2*3的数组,所有元素都填充3 array([[3, 3, 3], [3, 3, 3]])
(7)np.random.random()方法。
np.random.random()方法用于创建一个元素值为0~1的随机数数组,接收一个列表或者元组作为参数。
>>> np.random.random((3, 3)) #创建一个3行3列的二维数组 array([[0.19414645, 0.2306415 , 0.08072019], #数组元素是随机产生的 [0.68814308, 0.48019088, 0.61438206], [0.5361477 , 0.33779769, 0.38549407]])
(8)np.random.randint()方法。
既然有np.random.random()方法,就会有np.random.randint()方法,也就是取随机整数的方法。不过这个np.random.randint()方法参数的形式与Python的random.random()不太一样,具体请看下面的实例。
>>>import random >>>random.random() #取0~1的随机数 0.4481402883460749 >>>random.randint(10,20) #取10~20的随机整数 15 #注意np.random.randint()方法与Python的random.random()方法的异同 >>> np.random.randint(1, 10, 3) #从1~10中随机取3个整数创建一维数组 array([6, 4, 6]) >>> np.random.randint(1, 10,(2,3)) #创建2行3列的二维数组,参数(2,3)是数组形状 array([[7, 4, 3], [9, 1, 6]])
数组形状就是数组的维数。事实上,比较np.random.randint()方法与Python的random.random()方法,我们就会发现,Python的random.random()方法主要是实现一个随机数,而np.random.randint()方法是一次生成一个数组的随机数,并且可以定义不同的数组形状。
1.1.3 读取外部数据创建数组
数据分析离不开对数据的获取,NumPy也支持从外部读取数据来创建数组,例如从硬盘中读取CSV、TXT等文本文件来创建数组。np.loadtxt()是NumPy中读取文件的一个方法(NumPy还有其他读文件的方法,本书只介绍该方法),其一般用法:np.loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0,usecols=None, unpack=False)。
各参数说明如下。
● fname:要读取的文件、文件名或生成器。
● dtype:数据类型,默认为浮点型。
● comments:注释,默认是#。
● delimiter:分隔符,默认是空格。
● converters:转换器,可以对读入的数据设置转换操作,一般与转换函数配合使用。
● skiprows:跳过前几行读取,默认是0,必须是整型。
● usecols:要读取哪些列,0是第1列。例如,usecols = (1,4,5)将提取第2、5和6列。默认读取所有列。
● unpack:如果为True,将分列读取,有多少列就返回多少个向量数组;如果为默认的False,则分行读取,将读取的列合并为一个向量元素。
上面给出了np.loadtxt()方法所有的关键字参数,下面我们只对感兴趣的参数给出示例。
【动动手练习1-3】 读取外部数据创建NumPy数组
在d盘的data目录下创建一个id.csv文件,文件内容如下。(表示路径的方式有“/”和“\\”两种,本书统一采用“\\”)
id,height,length 1,100,101 2,200,230 3,300,350
通过NumPy读取数据。
>>> np.loadtxt('d:\\data\\id.csv',delimiter=',',skiprows=1) #也可以写成 #np.loadtxt(fname='d:\\data\\id.csv',delimiter=',',skiprows=1) array([[ 1., 100., 101.], #按行输出 [ 2., 200., 230.], [ 3., 300., 350.]]) >>>np.loadtxt('d:\\data\\id.csv',delimiter=',',skiprows=1,unpack=True)# 增加unpack参数 array([[ 1., 2., 3.], #按列输出,一列为一维 [100., 200., 300.], [101., 230., 350.]])
第1个参数fname为'd:\\data\\id.csv',是读取的文件名称。
第2个参数delimiter是指定读取文件中数据的分割符。
第3个参数skiprows是选择跳过的行数。
我们可以比较unpack参数的作用,默认行数据为数组元素。将其值设为True,则按列输出。
读取外部数据的方法还有np.genfromtxt()等,在此不再介绍,读者可自行查阅相关知识学习。
1.1.4 将数组保存为文本文件
np.savetxt()方法需要2个参数:第1个参数是文件名,数据类型为字符串;第2个参数是被写入文件的数据,数据类型为ndarray对象。
需要说明的是,写入的ndarray数组元素数据为字符串内容时,写入会出错。这是因为NumPy是一个数学计算包,侧重数值的处理,只能写入数值数据。另外,使用NumPy可直接导入数值数据,但读字符串会出错,如果必须读入文本数据,一般会使用转换器对应的函数将文本转换为数值。
下面举例说明使用np.savetxt()方法写入文本文件。
【例题1-1】 将NumPy数组保存为文件
>>>import numpy as np >>> matrix=np.eye(2).astype('int') #生成对称矩阵二维数组,并将其值转换为整数 >>> matrix #查看矩阵数组 array([[1, 0], #显示结果 [0, 1]]) >>> matrix.dtype #查看矩阵二维数组的数据类型 dtype('int32') #显示为32位的整数 >>> np.savetxt('d:\\data\\eys.txt',matrix) #使用np.savetxt()方法写入文本文件
写入文本文件的结果如图1-1所示。
图1-1 使用np.savetxt()方法写入文本文件的结果
从图1-1可以看出,ndarray对象中的元素数据类型原本为整型,但写入文件时转变为浮点型。同样,使用np.loadtxt()方法载入数据时,即使原来文本中数据的类型为整型,载入后转换为ndarray数组的数据类型也会默认变成浮点型,读者可自行试验。