本文所有内容均总结自《利用python进行数据分析》。这本书太无趣了,如果不自己做一点笔记的话,根本读不下去。于是有了这些文章。
一、Numpy概述
Numpy是目前Python数值计算中最为重要的基础包,大多数计算包都提供了基于Numpy的科学函数功能,将Numpy的数组对象作为数据交换的通用语。简而言之,Numpy提供的数组太好用了,大家都喜欢。
我们将使用Numpy的以下几方面功能:
①、ndarry,一种高效的多维数组,提供了基于数组的便携算数操作以及灵活的广播功能。
②、对所有数据进行快速的矩阵计算,无需编写循环程序。
③、对硬盘中的数组数据进行读写的工具,并对内存映射文件进行操作。
④、线性代数、随机数生成以及傅里叶变换。
⑤、用于连接Numpy到C、C++和FORTRAN语言类库的C语言API。
在naive的我看来,这个Numpy库就是把一部分的matlab功能移植到python中。
二、Numpy ndarry:多维数组对象
1、ndarray简介
这是Numpy的核心特征之一,nd就是n维,array就是数组。
它的第一大特征就是可以进行对数组整体进行操作。注意不是矩阵操作。因为数组乘法是对应元素相乘,而不是矩阵乘法。如下:
使用np.random.rand(a,b)可以返回一个a行b列,元素是随机数的矩阵,目测这个随机数的范围是(0,1),保存在data中。
这个data的数据类型就是ndarray。
data*2就是数组中所有元素乘二,data+data就是对应元素相加。相乘用data比较难看出来,所以另外开两个数组:
看,也是对应的元素相乘。也就是说,对array进行计算,相当于对它的每一个元素分别计算,省去了循环的麻烦。
array既然是多维数组,那么就需要知道它的维度。使用a.shape就能够返回a在各个维度上的元素个数啦。比如上面的a,是一个二维数组,shape如下:
这说明a在第一维上有两个元素,在第二维上有三个元素。shape描绘数组的形状,“2”行“2”列。返回的元组的元素个数就是维数。对于维度,也可以用ndim来确定。
知道了维数,多维数组还有一个属性,就是元素的类型。使用a.dtype就可以知道。
2、ndarray生成
生成一个数组主要有以下几种方法:
np.array(a)
np.zeros(10)
np.ones((2,3))
np.empty((2,3,2))
np.full((2,3),1)
如图,对于np.array()方法,无论输入的是元组还是列表,输出的都是它们元素组成的array。
另外,如果输入是二维数组,输出自然也是二维数组。
我们有另外一个函数asarray,它与array的主要区别就在于,当输入类型是array,对于array函数,它将复制数组中的所有元素,然后返回一个array;对于asarray,它首先判断输入是不是array,如果是,就直接返回,如果不是,再复制。
array有一个参数dtype,可以用它指定生成的数组中的元素类型。
下面的zeros、ones、empty的输入参数就是数组在各个维度上的元素数量,比如说输入(2,3)那么zeros就返回一个2行3列元素为0的数组,ones返回的是元素全为1的数组,empty返回元素为空的数组,表现出来也是元素为0,但是并不安全,有时候会返回垃圾数值,因此要全0的最好还是用zero。
注意输入的参数不止一个的时候,要把所有参数用元组包起来。
最后一个函数full,其输入参数有两个,第一个是一个元组,用于描述输出数组的形状,也就是各维度上元素个数;第二个是元素,full会输出一个元素均是这个输入的数组。如下:
另外还有函数eye,identity,用于生成一个对角线为1,其余元素为0的数组。
3、ndarray的数据类型
数据类型和C差不多,有int有float,但是int里面还分几个小类int8,uint8什么的。这个可以自己去看。
重要的一点是数据类型的转换,在C中我们直接在前面加()就可以,但是python没有数据类型这么一说,所以需要借助astype来实现。如下:
将一个字符串列表转换为一个数组,要求元素类型为np.string_,这个类型要求等价于要求类型为S或S4,即长度为4的字符串类型,一定要小心使用,因为python会不告诉你而擅自把列表中的所有元素切到四或四以下。如果我们要求类型为S2,那么则会切到只剩两个字符,这样就有精度损失了。
我觉得特别厉害的一点是astype可以把字符串格式的数字直接转成真正的数字,如下:
注意转换成int8还会报错,转换成float就不会,真是聪明。
4、numpy数组算数
之前说过,ndarray的一大优势在于它可以批量对元素操作而不用循环,这被称之为向量化。
有三条原则:
①、等尺寸的数组之间操作为逐元素操作,就是一一对应。
②、带有标量计算的算数操作,会把计算参数传递给每一个元素。**表示乘方。
③、同尺寸数组间的比较,会生成一个布尔值数组,表明每个元素对应比较的真假。
另外,不同尺寸的数组比较,将会用到广播特性。
5、基础索引与切片
这部分的功能实际上就是让你精确、直白、方便的在一个多维数组中选择一些数据。
比较反直觉的一点在于,在选择出这一些数据之后,对这部分数据进行改动会反应在原来的数组上,我们称选择的这部分数组是一个“视图”,而不是原数据的复制。
如图,arr1是一个数组,arr2是arr1的一个切片,当我更改arr2中的元素,arr1也同步更新。
那问题来了,我要想对数组中某一部分元素进行更改,但不想影响原数组怎么办?使用copy函数。
如图,arr3由555变成了666,但arr1没变。
接下来有点复杂了。由于数组维数可以比二大,我们想要表达某一个元素或者某几个元素会变得困难。
比如说一个三维数组arr3d:
这个高维数组,维数越高越难理解。如果非得把它们映射成线啊面啊体啊,就有点难。我现在用这种方法来定位高维数组中的元素:
比如说arr3d[0,1,2],第一个0,表示要在[ 1, 2, 3], [ 4, 5, 6]里面找,第二个1,表示要在[ 4, 5, 6]里面找,第三个2,表示找到元素6。要是说第一个0表示0号面,第二个1表示第1行,第三个2表示第2列,这就不好解释了。
同样的,我们想选择[4,5,6]这个一维子数组,我们输入arr3d[0,1]即可。同理,选择[ 1, 2, 3], [ 4, 5, 6],输入arr3d[0]即可。
那我们想要[2,5,8,11]怎么办?就是每一个一维子数组的第一个?输入arr3d[:,:,1]即可。
注意,这里的2,5,8,11是一个2*2矩阵,而不是一个4*1向量。
想要[2,5,8]呢?这个做不到。因为这横跨了两个二维子数组,而且不是对称的,没法一次切片得到。可以两次切片,第一次2,5,8,11,第二次2,5,8。
想要[2,3,5,6]是可以的,arr3d[:1,1,1:]即可。第一个:1表示“到1之前”,第三个1:表示“从1开始”。
6、布尔索引
布尔索引即是将布尔表达式当做下标,返回对应的数据。原理就是布尔表达式是通过判断得到的,会返回一个元素为True或False的数组,根据这个数组,返回元素为True的部分。
例如,我们现在有一个1*7的人名数组names:
又有一个7*7的随机数数组rand:
其中每一行对应一个人名,那么我想选择名字为XueChengfei对应的一行该怎么办?
使用rand[names=="XueChengfei"]即可。
我们来看看names=='XueChengfei'这一句返回了什么。
看,返回了一个数组,只有XueChengfei对应的一行为True,于是可以返回该行数据。那么要是人名对应的不是行而是列呢?
很简单,将rand转置转即可。
不能将names=='XueChengfei'返回的数组转置,因为这个数组是一维的,转置并不会由1*7变成7*1,它不变。
我们也可以使用多个条件:
注意各个条件要用括号括起来。
或用~,且用&,非用|。
另外特别重要的一点,布尔索引返回的是拷贝,而不是视图。
7、神奇索引
神奇索引是通过输入“座标”来选择原数组中一些元素的方法,相比于基础索引,它更灵活,但也更复杂。
我们以二维数组为例:
现在我们想要返回一个数组,由arr的第4,3,0,6行组成,这用基础索引是无法实现的,但是用神奇索引可以很容易实现:输入[4,3,0,6]即可。
如果使用负的索引,将从尾部进行选择。
注意,-1是最后一行。
如果我们输入多个数组,那么这多个数组必定长度相同,每个数组对应位置的元素合起来组成一个座标,比如说[3,4,5,6],[1,2,3,1]就意味着我需要第3行第1个,第4行第2个,第5行第3个和第6行第1个。
要想选择子集呢?比如说我想选择上面1,2;1,3;4,2;4,3四个元素作为四个角所形成的矩形中的所有元素,可以输入[3,4,5,6],1:4。
8、数组转置和换轴
超过二维数组的转置就叫换轴,我觉得好难理解,先不用了。二维转置使用arr.T即可。