1.列表与数组
在python的基础语言部分,我们并没有介绍数组类型,但是像C、Java等语言都是有数组类型的,那python中的列表和数组有何区别呢?
一维数据:都表示一组数据的有序结构
区别:
列表:数据类型可以不同,如:【3.1413,'pi',3.1404,[3.1402,2.34],'3.2376'】
数组:数据类型相同 。如【3.14,34.34,3433.3,343.23】
二维数据:二维数据由多个一维数据构成,是一维数据的集合形式!表格是典型的二维数据!
注意:表格的表头,可以是二维数据的一部分,也可以作为二维数据以外的一部分,这取决于用户对于二维数据的定义和使用!
多维数据:多维数据是在一维数据或者二维数据的基础上拓展形成的!
注意:上面一个是2016年的排名表格,还有一个是2017年的一个排名表格,从这两个表格的跨度来看,这里增加了一个时间维度,从而构成一个多维数据!如果随着时间的发展,那么在时间维度上,数据就会继续累积下去!
除了一维、二维、多维数据之外,还有一种多维数据!高维数据与一维、二维、多维数据不同,高维数据仅使用最基本的二元关系展示数据间的复杂结构。
如下所示:这就是一个高纬数据,这里面没有数据的规整的组织方式,但是却有数据之间的包含关系、数据之间的并列关系,以及数据之间的属性关系等形成的一个数据的组织方式,这里面都是键值对的单元,高维数据就是有键值对将数据组织起来。
2.数据维度的python表示
注意:对于一维数据我们用列表和集合表示,列表是有序的,而集合是无序的。对于python中的二维或者多维数据,我们用列表表示,而列表的元素还可以是列表,这就是一种多维列表,用多维列表来对应多维元素!
对于高维数据,我们使用字典或者数据表示的格式来表示;字典类型也是由键值对构成的一个数据类型,它与高维数据的表达方式基本上是一致的!
我们知道现在公认的数据表达格式主要有3种: JSON,XML,YAML格式,这样的格式可以用来组织数据,是他们之间形成数据的维度和关系。
3.NumPy的数组对象: ndarray
下面我们介绍一个numpy库以及numpy中的ndarray数组类型!
NumPy是一个开源的Python科学计算基础库。它也是整个python目前科学计算和数据分析的最基础的第三方库!NumPy提供了很多功能,主要包含以下一些方面:
1.一个强大的N维数组对象ndarray
2.一组广播功能函数,用来在数组之间进行计算
3.整合C/C++/Fortran等代码的工具
4.线性代数、傅里叶变换、随机数生成等功能!
NumPy是SciPy,Pandas等数据处理或科学计算库的基础。
为了更好的进行科学计算,我们首先要理解NumPy的构成原理,以及其中最关键的数据对象ndarray!
1.NumPy的引用:import numpy as np #注意:这里的np是引入模块numpy的别名,尽管别名可以省略或更改,建议使用上述约定的别名。【如果我们不使用别名,而是直接使用numpy,这样每次调用函数的时候都得是numpy.的方式,代码较长,如果我们使用的是其它别名,那么其它程序员未必熟悉,所以这里我们建议使用的别名为np】
2.python中的数据对象ndarray![有些学员可能会有疑问,在python中我们已经有了列表类型,而列表类型可以表示一维数据、二维数据、多维数据,那么我们为什么需要一个额外的数组类型呢?这里我们给大家举个例子,如下所示:]
如果用传统的python语法,我们来定义:
在上述的运算方式中,我们还是将我们的关注点放在一个一个元素之间的运算上,这并不是一种科学计算的思想方式!,而NumPy使用了另外一种思路,如下所示:
这时在NumPy进行运算的时候没有使用循环!我们的基本思想是将一维数组A和一维数组B当做两个数据,这两个数据在他们维度相同的时候,他们可以直接进行运算!程序帮我们把这两个数据中的每一个元素进行了运算,而编程的程序员只需要考虑A和B只是一个数据就可以啦!这是NumPy中N维数组对象所使用的一个基本原理!
所以对N维数组对象ndarray的一些说明如下:
1.数组对象可以去掉元素间运算所需要的循环,使一维数据更向单个数据,也使得我们程序员编写代码处理数据的程序变得十分简单!
2.通过设置专门的数组对象,经过优化,可以提升这类应用的运算速度,这里同学们可能还不知道,NumPy的底层实现是用C来完成的,也就是说在进行数组运算的时候,底层的C语言会提供非常高效和快速的运算,这样会使得在进行大规模运算的时候,运算时间会比较少!
例如:观测一个现象,每一次它的值都可能是一个整数或者浮点数,他们都是统一的!因此,数组对象采用相同的数据类型,有助于节省运算和存储空间,因为对程序来讲,当它的类型是确定的,那我可能就知道它使用的内存空间是多少,这样在内存分配和存储空间的使用上,就可以做预判,使得空间的使用很有效,所以呢,一方面是在编程上,NumPy使得程序员可以在批量数据处理时得到了简化,一方面在运算性能上,NumPy可以由底层的C语言甚至更底层的运算方法来提高他的运算速度。因此Numpy成为了Python中支持科学计算和数据处理的最基础的库。
我们来进一步介绍ndarray这个数据类型!
数组的下标是从0开始,这点是和列表一致的!我们来看一下ndarray实例,如下所示:(这里需要注意的是,在数据处理这里,我们使用的解释器是IPython,因此我么要熟悉IPython的交互时提示符,如由in、out、[]等组成,如下所示:
这里面展示了用户输入的和程序输出的结果!对于ndarray这里有两个基本的概念:
在轴上每个维度的数据存储在其中,秩表示轴的数量,也就是这个数组类型有多少个维度!这两个基本概念是描述ndarray类型的基本向量和方式!ndarray对象一共有5个基本的运算属性:
如下为ndarray实例:
注意:上面的返回值dtype('int32'),其中的int32在基本的python数据类型中是不存在的,在ndarray中还有很多这样的类型,如下所示:
以上整数类型是有正负之分的,还有一部分整数是没有正负之分的,我们称之为无符号整数,如下所示:
ndarray还支持复数类型,如下所示:
我们知道在python基础数据类型部分,python只支持一种整形,一种浮点型,和一种复数类型,那为什么这里的ndarray支持这么多的类型呢?
我们说ndarray对象都是相同的,也就是一种同质的数组类型,事实上ndarray也可以包含非同质的元素。比如我们生成一个数组,如下所示:
注意:上面的x.shape只返回了行数,并没有返回列数,因为是非同质的,所以列数不固定了,而且x.dtype返回的是o,也就是说是对象类型。
4.ndarray数组的创建和变换
ndarray数组的创建方法:
1.从Python中的列表、元组等类型创建ndarray数组。
2.使用NumPy中函数创建ndarray数组,如:arange,ones,zeros等。
3.从字节流(raw bytes)中创建ndarray数组。
4.从文件中读取特定格式,创建ndarray数组。
下面我们逐一进行讲解:
利用Python中的列表、元组等类型创建ndarray数组,如下所示:
x = np.array(list/tuple)
x = np.array(list,tuple,dtype = np.float32)
这里我们使用dtype来指定数组元素的数据类型,当np.array()不指定dtype时,NumPy将根据读入数据情况关联一个dtype类型。例如,假如读入的数据都是整数,那么NumPy就会指定dtype为整数类型。如下:
2.创建ndarray最常用的方法是使用NumPy中函数创建ndarray数组,如下所示:
注意:python中有一个range()函数可以生成一个递增的序列,那么同样在ndarray中也有一个这样的方法就是np.arange(n)方法,np.arrange(n)方法会返回一个ndarray类型,元素是从0到n-1的整数类型。
而np.ones(shape)可以根据数组的shape形状,形成一个全1的数组。其中shape为元组类型,比如,我们希望定义一个2行3列的二维数据,那么我们就可以shape写为(2,3)
np.zeros(shape)的用法同np.ones(shape)方法。
这里需要注意:向ones、zeros、eye()等方法生成的数组元素类型都是浮点数类型的,除非我们自己通过dtype来指定,而arrange()函数生成的数组元素是整数类型的,具体如下所示:
我们也可以使用它们生成多维数组,例如:我们可以使用np.ones生成一个(2,3,4)这样形状的数组,同时还可以使用x,shape返回它的形状。
我们可以看到2,3,4分别表示的是:在最外层的元素中,有2个元素,每一个元素又有3个维度,那每个维度下又有4个元素。所以这样的shape是由数组的最外层到最内层逐渐变化的一个数据维度的一个表示方式。
除了上述的几个函数,还有几个和他们很类似的几个函数:
这三个函数在进行大规模科学计算的时候,特别重要!此外NumPy中又提供了两个创建ndarray数组的常用方法,分别是:
对于np.linspace()也就是说:给出一个起始值和一个结束值,给出一个你想生成的数组的个数,那么通过这个函数就能生成一个数组。例如:
上面的a = np.linspace(1,10,4)表示我们想生成的数组的起始元素是1,终止元素是10,希望生成4个元素,这时候生成的数组是array([1,4,7,10])!但是使用linspace()生成的数组在不限定元素类型的时候,生成的数据元素是浮点数。在linspace()函数中有一个属性是endpoint,这个属性表示:最后一个元素10是否是生成的4个元素中的一个,如果是False,表示不是其中一个,如果是True表示是其中一个。如上b所示!在不使用endpoint这个参数的时候,我们看到a是使用最后一个元素10作为4个元素中的一个,这也是默认的情况,如果我们将endpoint置为False,那么10 将不作为最后一个元素出现!最后我们还可以使用concatenate()函数将这两个数组合并起来形成一个新的数组。我们看到新数组中既包含了数组a中的元素,也包含了数组b中的元素!
这里有些学生可能会有疑问,为什么NumPy每一次都将生成的元素类型作为浮点数呢?
因为NumPy是用于科学计算的一个库,而在科学计算中,我们往往使用的数据都是浮点数。比如我们进行两个数运算加减乘除,必然可能会出现浮点数,我们观察一个情况获得的值,比如光照值,温度值等都是浮点数。我们很难在一个应用中发现都是整数的情况,因此除了arrange()函数外,NumPy在几乎所有的函数生成数组的时候元素都是浮点型的。
对于一个创建后的ndarray数组,我们可以改变它的维度和元素类型,如下所示:
我们看一下维度变换的一些方法,如下所示:
这里同学们要仔细体会,使用什么方法是不改变原数组的,使用什么方法是要改变原数组的,这些在科学计算中特别重要,使用的时候要特别注意!
下面我们看一个例子:我们使用np.ones()方法生成一个(2,3,4)结构的数组,同时指定元素数据类型为整型,然后把这个数组赋值给变量a!
然后使用a.reshape()将一个3维数组改为2维数组,如下所示:
大家可以看到reshape()之后数组的元素个数和reshape之前的数组的元素个数是没有发生变化的,而且a本身没发生变化,而只是返回值为一个新数组!如果使用a.resize()方法,如下所示:
大家可以看到a数组是发生变化的,所以大家要特别注意:a.reshape()是不改变原数组却新生成一个新数组返回,而a.resize()是直接改变的这个数组,我们可以使用a.flatten()将(2,3,4)这样的多维数组降维为一维数组。如下所示:当我们再使用a的时候我们发现a其实并没有什么变化!而b是被降维之后的一维数组。
NumPy提供了一个改变ndarray数组类型的一个函数,叫astype(),它的使用方式如下所示:
例子:
上面的这种写法要注意:在NumPy中,实际上没有数据类型为np.int类型的,np.int代表的是整数类型这一类,那么程序会将元素解析为整数类型,但是是解析为int-32呢还是int-64呢,那么是由程序自动调节的,所以我们可以简写为np.int,而不必具体到int-8,int-16,int-32,所以此时的a是(2,3,4)维,元素类型为整数的一个数组。下面我们把整数类型变换成浮点数类型,如下所示:
np.float和np.int一样可以代表一类浮点数类型。然后将b输出可以看到b中的每一个元素都是浮点数类型。
注意,对于新数组的任何使用与原数组无关!新数组是原始数组的一个数据的拷贝,换句话说,我们可以通过astype()来做一个原始数组的拷贝!通过astype()可以改变原始数组的类型。这个在我们实际应用中,可能会带来性能上的变化和存储空间上的节省。
此外,ndarray数组也可以转换成一个python中的列表,转变方式就是使用ndarray的一个方法tolist()
也就是:
如上所示:a数组是一个(2,3,4)维度的数组,它的每一个元素都是25,并且将dtype类型定义为int32,每个元素是一个整数类型,然后看一下a的值,然后我们可以通过a.tolist()将这样一个NumPy的数组转换成一个列表,我们看到列表与数组的不同仅仅在于,列表是python中最原始的一种数据类型。那么这种类型中可能占用的空间和运行的速度会比NumPy慢很多,但是说与一些传统的或者说原生的python语言语法相适应的程序中,像列表的转换也是很常见的!
5.ndarray数组的操作
这里所说的操作是指对数组的索引和切片
注意:python的列表提供了从最左侧编号0开始,向右递增,或者从最右侧-1开始,向左递减两种索引方式!那么这两种方式在ndarray的数组中都可以使用!获得一维数组的切片,我们这里使用两个冒号的方式获得!
Numpy中的元素是从第0个开始的!
如下所示:
这里可以看到我们先生成一个一维数组,然后将一维数组转换成(2,3,4)维度的一个3维数组,然后我们通过a[1,2,3]来指定各个维度上元素的序号【例如这里的a[1,2,3]在第一个维度上我们指定第一个元素,在第2个维度上我们指定第2个元素,在第3个维度上我们指定第3个元素,索引我们可以看到最终a[1,2,3]取得的值为23】,从而获取各个维度相对应的元素,因为NumPy中数组的元素是从0开始的!当然还可以和列表一样从右向左从-1开始依次递减的方式进行!
如下所示:我们还是使用a数组
我们在一维数组【和列表类似】中切片使用的是两个冒号组成的这样的逻辑,那么这样的方法在多维数组中同样存在,所谓的多维数组切片,也就是在每个维度上,用户给出一个切片空间,那么将不同的切片空间组织起来形成的一个子数据集的获取方式,如下所示:
例如上面的a[:,1,-3]表示的是不管第一个维度是什么,而第二个维度的索引要求为1,而第三个维度的索引为-3,最终就取到了【5,17】,实际上对于3位数组,我们这里还好理解,如果有更多维度的数据,那么理解起来可能就不会那么直观了!所以每次切片的时候,同学们要慎重和小心的选择你使用的参数,但是在每一个维度上的参数都是可以通过两个冒号的逻辑来去确定和使用的!