第5章 pandas入门
pandas含有使数据清洗和分析工作变得更快更简单的数据结构和操作工具。pandas经常和其它工具一同使用,如数值计算工具NumPy和SciPy,分析库statsmodels和scikit-learn,和数据可视化库matplotlib。pandas是基于NumPy数组构建的,特别是基于数组的函数和不使用for循环的数据处理。
pandas是专门为处理表格和混杂数据设计的。而NumPy更适合处理统一的数值数组数据。
使用下面这样的pandas引入约定:
只要在代码中看到pd.就想到这是pandas。因为Series和DataFrame用的次数非常多,所以将其引入本地命名空间中会更方便:
5.1 pandas的数据结构介绍
- Series
Series是一种类似于一维数组的对象,它由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据即可产生最简单的Series:
Series的字符串表现形式为:索引在左边,值在右边。由于没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。可以通过Series的Values和index属性获取其数组表示形式和索引对象:
创建的Series带有一个可以对各个数据点进行标记的索引:
与普通NumPy数组相比,可以通过索引的方式选取Series中的单一或一组值:
使用NumPy函数或类似NumPy的运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引值的链接:
还可以将Series看成是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中:
若数据被存放在Python字典中,可以直接通过这个字典来创建Series:
若只传入一个字典,则结果Series中的索引就是原字典的键(有序排列)。可以传入排好序的字典的键以改变顺序:
使用(missing)或NA表示缺失数据。pandas的isnull和notnull函数可用于检测缺失数据:
Series也有类似的实例方法:
Series会根据运算的索引标签自动对齐数据:
Series的索引可以通过赋值的方式就地修改:
- DataFrame
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共用同一个索引)。DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。
建DataFrame的办法有很多,最常用的一种是直接传入一个由等长列表或NumPy数组组成的字典,结果DataFrame会自动加上索引(跟Series一样),切全部列会被有序排列:
对于特别大的DataFrame,head方法会选取前五行:
若传入的列在数据中找不到,就会在结果中产生缺失值:
通过类似字典标记的方式或属性的方式、将DataFrame的列获取为一个Series:
笔记:IPython提供了类似属性的访问(即frame2.year)和tab补全。frame2[column]适用于任何列的名,但是frame2.column只有在列名是一个合理的Python变量名时才适用。
行可以通过位置或名称的方式进行获取,比如用loc属性:
列可以通过赋值的方式进行修改。例如,可以给那个空的“debt”列赋上一个标量值或一组值:
将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配。若赋值的是一个Series,就会精确匹配DataFrame的索引,所有的空位都将被填上缺失值:
为不存在的列赋值会创建出一个新列。关键字del用于删除列。
作为del的例子,先添加一个新的布尔值的列,state是否为’Ohio’:
不能用frame2.eastern创建新的列。
del方法可以用来删除这列:
注意:通过索引方式返回的列只是相应数据的视图,并不是副本。因此,对返回的Series所做的任何就地修改全都会反映到源DataFrame上。通过Series的copy方法即可指定复制列。
另一种常见的数据形式是嵌套字典:
如果嵌套字典传给DataFrame,pandas就会被解释为:外层字典的键作为列,内层键则作为行索引:
内层字典的键会被合并、排序以形成最终的索引。若明确指定了索引,则不会这样:
由Series组成的字典差不多也是一样的用法:
若设置了DataFrame的index和columns的name属性,则这些信息也会被显示出来:
与Series一样,values属性也会以二维ndarray的形式返回DataFrame中的数据:
若DataFrame各列的数据类型不同,则值数组的dtype就会选用能兼容所有列的数据类型:
- 索引对象
pandas的索引对象负责管理标签和其他元数据(比如轴名称等)。构建Series或DataFrame时,所用到的任何数组或其他序列的标签都会被转换成一个Index:
Index对象是不可变的,因此用户不能对其进行修改:
不可变可以使Index对象在多个数据结构之间安全共享:
除了类似于数组,Index的功能也类似一个固定大小的集合:
与python的集合不同,pandas的Index可以包含重复的标签:
选择重复的标签,会显示所有的结果。
5.2 基本功能
- 重新索引
pandas对象的一个重要方法是reindex,其作用是创建一个新对象,它的数据符合新的索引。例子:
用该Series的reindex将会根据新索引进行重排。若某个索引值当前不存在,就引入缺失值:
对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理。method选项即可达到此目的。例如,使用ffill可以实现前向值填充:
借助DataFrame,reindex可以修改(行)索引和列。只传递一个序列时,会重新索引结果的行:
列可以用columns关键字重新索引:
- 丢弃指定轴上的项
丢弃某条轴上的一个或多个项很简单,只要有一个索引数组或列表即可。由于需要执行一些数据整理和集合逻辑,所有drop方法返回的是一个在指定轴上删除了指定值的新对象:
对于DataFrame,可以删除任意轴上的索引值。为了演示,先新建一个DataFrame例子:
用标签序列调用drop会从行标签(axis 0)删除值:
通过传递axis=1或axis=‘columns’可以删除列的值:
许多函数,如drop,会修改Series或DataFrame的大小或形状,可以就地修改对象,不会返回新的对象:
- 索引、选取和过滤
Series索引(obj[…])的工作方式类似于NumPy数组的索引,只不过Series的索引值不只是整数。例子:
利用标签的切片运算与普通的Python切片运算不同,其末端是包含的:
用切片可以对Series的相应部分进行设置:
用一个值或序列对DataFrame进行索引其实就是获取一个或多个列:
这种索引方式有几个特殊的情况。首先通过切片或布尔型数组选取数据:
选取行的语法data[:2]十分方便。向[ ]传递单一的元素或列表,就可选择列。
另一种用法是通过布尔型DataFrame(比如下面这个由标量比较运算得出的)进行索引:
- 用loc和iloc进行选取
对于DataFrame的行的标签索引,引入了特殊的标签运算符loc和iloc。它们可以让你用类似NumPy的标记,使用轴标签(loc)或整数索引(iloc),从DataFrame选择行和列的子集。
作为示例,通过标签选择一行和多列:
然后用iloc和整数进行选取:
这两个索引函数也适用于一个标签或多个标签的切片:
DataFrame的索引选项:
- 整数索引
如果轴索引含有整数,数据选取总会使用标签。为了更准确,要使用loc(标签)或iloc(整数):
- 算术运算和数据对齐
pandas最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,若存在不同的索引对,则结果的索引就是该索引对的并集。例子:
将它们相加就会产生:
自动的数据对齐操作在不重叠的索引处引入了NA值。缺失值会在算术运算过程中传播。
对于DataFrame,对齐操作会同时发生在行和列上,把它们相加后将会返回一个新的DataFrame,其索引和列为原来那两个DataFrame的并集。如果DataFrame对象相加,没有共同的列或行标签,结果都会是空。
- 在算术方法中填充值
在对不同索引的对象进行算术运算时,希望当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值(比如0):
将它们相加时,没有重叠的位置就会产生NA值:
使用df1的add方法,传入df2以及一个fill_value参数:
下表列出Series和DataFrame的算术方法:
与此类似,在对Series或DataFrame重新索引时,也可以指定一个填充值:
- DataFrame和Series之间的运算
计算一个二维数组与其谋行之间的差:
当从arr减去arr[0],每一行都会执行这个操作。这就叫做广播(broadcasting),DataFrame和Series之间的运算也是如此:
默认情况下,DataFrame和Series之间的算术运算会将Series的索引匹配的DataFrame的列,然后沿着行一直向下广播:
如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集:
若希望匹配行且在列上广播,则必须使用算术运算方法。例如:
传入的轴号就是希望匹配的轴。在本例中,目的是匹配DataFrame的行索引
(axis=‘index’ or axis=0)并进行广播。
- 函数应用和映射
NumPy的ufunc(元素级数组方法)也可用于操作pandas对象:
另一个常见的操作是,将函数应用到由各列或行所形成的一维数组上。DataFrame的apply方法即可实现此功能:
这里的函数f,计算了一个Series的最大值和最小值的差,在frame的每列都执行了一次。结果是一个Series,使用frame的列作为索引。
如果传递axis=‘columns’到apply,这个函数会在每行执行:
传递到apply的函数不是必须返回一个标量,还可以返回由多个值组成的Series:
元素级的Python函数也是可以用的。若想得到frame中各个浮点值的格式化字符串,使用applymap即可:
之所以叫做applymap,是因为Series有一个用于应用元素级函数的map方法:
- 排序和排名
要对行或列索引进行排序(按字典顺序),可使用sort_index方法,它将返回一个已排序的新对象:
对于DataFrame,则可以根据任意一个轴上的索引进行排序:
数据默认是按升序排序的,但也可以降序排序:
若要按值对Series进行排序,可使用其sort_values方法:
在排序时,任何缺失值默认都会被放到Series的末尾:
当排序一个DataFrame时,可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给sort_values的by选项即可达到该目的:
要根据多个列进行排序,传入名称的列表即可:
排名会从1开始一直到数组中有效数据的数量。
Series和DataFrame的rank方法:默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的:
也可以根据值在原数据中出现的顺序给出排名:
这里,条目0和2没有使用平均排名6.5,它们被设成了6和7,因为数据中标签0位于标签2的前面。
也可以按降序进行排名:
DataFrame可以在行或列上计算排名:
排名时用破坏平级关系的方法:
- 带有重复标签的轴索引
带有重复索引值的Series:
索引的is_unique属性可以知道它的值是否是唯一的:
对于带有重复值的索引,数据选取的行为将会有些不同。如果某个索引对应多个值,则返回一个Series;而对应单个值的,则返回一个标量值:
这样会使代码变复杂,因为索引的输出类型会根据标签是否有重复发生变化。对Data Frame的行进行索引时也是如此:
5.3 汇总和计算描述统计
pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。跟对应的NumPy数组方法相比,它们都是基于没有缺失数据的假设而构建的。一个简单的DataFrame:
调用DataFrame的sum方法将会返回一个含有列的和的Series:
传入axis=‘columns’或axis=1将会按行进行求和运算:
NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA。通过skipna选项可以禁用该功能:
约简方法的常用选项:
有些方法(如idxmin和idxmax)返回的是间接统计(比如达到最小值或最大值的索引):
另一些方法则是累计型的:
还有一种方法,它既不是约简型也不是累计型。describe就是一个例子,它用于一次性产生多个汇总统计:
对于非数值型数据,describe会产生另外一种汇总统计:
所有与描述统计相关的方法:
- 相关系数与协方差
有些汇总统计(如相关系数和协方差)是通过参数对计算出来的。来看几个DataFrame,它们的数据来自Yahoo!Finance的股票价格和成交量,使用的是pandas-datareader包(用conda或pip安装):
使用pandas_datareader模块下载了一些股票数据:
注意:此时Yahoo! Finance已经不存在了,因为2017年Yahoo!被Verizon收购了。参阅pandas-datareader文档,可以学习最新的功能。
计算价格的百分数变化:
Series的corr方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。与此类似,cov用于计算协方差:
因为MSTF是一个合理的Python属性,还可以用更简洁的语法选择列:
另一方面,DataFrame的corr和cov方法将以DataFrame的形式分别返回完整的相关系数或协方差矩阵:
利用DataFrame的corrwith方法,可以计算其列或行跟另一个Series或DataFrame之间的相关系数。传入一个Series将会返回一个相关系数值Series(针对各列进行计算):
传入一个DataFrame则会计算按列名配对的相关系数。这里计算百分比变化与成交量的相关系数:
传入axis=‘columns’即可按行进行计算。无论如何,在计算相关系数之前,所有的数据项都会按标签对齐。
- 唯一值、值计数以及成员资格
还有一类方法可以从一维Series的值中抽取信息。例子:
第一个函数是unique,它可以得到Series中的唯一值数组:
返回的唯一值是未排序的,若需要的话,可以对结果再次进行排序(uniques.sort())。相似的,value_counts用于计算一个Series中各值出现的频率:
为了便于查看,结果Series是按值频率降序排列的。value_counts还是一个顶级pandas方法,可用于任何数组或序列:
isin用于判断矢量化集合的成员资格,可用于过滤Series中或DataFrame列中数据的子集:
与isin类似的是Index.get_indexer方法,它可以给你一个索引数组,从可能包含重复值的数组到另一个不同值的数组:
下表为唯一值、值计数、成员资格方法:
可以得到DataFrame中多个相关列的一张柱状图。例如:
将pandas.value_counts传给该DataFrame的apply函数,就会出现:
结果中的行标签是所有列的唯一值。后面的频率值是每一列中这些值的相应计数。