Pandas简介
之前详细介绍了 NumPy 和它的 ndarray
多维数组对象,为 Python 多维数组提供了高效的存储和处理方法。
本章基于前面的知识,继续学习 Pandas 库提供的数据操作方法。Pandas
是在 NumPy
基础上建立的另一个第三方库,提供了一种高效的 DataFrame
数据结构。DataFrame
本质上是一种带行标签和列标签、支持相同类型数据和缺失值的多维数组。Pandas
不仅为带各种标签的数据提供了便利的存储与展示接口,还实现了许多强大的计算、查找和分类等操作。
pandas 在底层存储时使用的是 numpy 的数组,因此在安装 pandas 之前,需要确保已经安装了 numpy 。
在安装完成 pandas
之后,可以导入它检查一下版本号:
和之前导入 numpy 并使用别名 np
一样,之后将导入 pandas 并使用别名 pd
:
Pandas的数据对象
Series对象
pandas 最简单的数据类型是 Series
。Series
对象是一个带索引数据构成的一维数组。可以用一个数组创建 Series
对象,如下所示:
Series
对象将一组数据和一组索引绑定在一起,可以通过 .values
属性获取数据,通过 .index
属性获取索引。.values
属性返回的结果就是底层的 numpy 数组:
.index
属性返回的结果是一个类型为 Index
的索引对象。索引是 pandas 的特点之一,将在后面的内容里详细介绍它。
和 numpy 数组一样,可以通过中括号实现索引或切片:
这么看来,pandas 的 Series
与 numpy 的一维数组很类似。但 Series
为数组提供了一种更加强大的索引系统:numpy 数组通过隐式定义的整数索引获取数值,而 pandas 的 Series
对象用可以手动指定索引与数值关联。
显式索引的定义让 Series
拥有了更好的可读性。例如,索引不再仅仅是整数,还可以是任意想要的类型。如果需要,完全可以用字符串定义索引:
在使用索引访问元素时,可以通过之前定义的字符索引获取数值:
这种数值的访问形式很像 Python 字典,可以将每个索引作为键映射到一个值。因此可以直接使用 Python 的字典创建一个 Series
对象,让两者的类比更加清晰:
由于 Python3.6+ 的字典是有序的,因此创建的 Series
对象索引也默认按照顺序排列。
除了可以使用像字典一样按键获取数值外,Series
的索引还可以用于切片操作:
这种切片是包括终点位置的元素的,这和普通的索引形式不同。后续会详细介绍这种索引规则。
DataFrame对象
pandas 的另一个基础数据结构是 DataFrame
。DataFrame
可以看作是一种二维数组,但它既有行索引,又有列索引,因此它经常被当做一个表格使用。注意,DataFrame
是 pandas 的非常重要的一个数据类型,因为它可以很好地表达日常生活中处理的各种表格结构。DataFrame
与 Excel 中表格或 SQL 中表的概念非常相似,可以实现大多数 Excel 或 SQL 的表操作。
DataFrame
有许多创建方式,每种创建方式都代表着对它的理解。例如,和 Series
对象一样,DataFrame
可以看作一个更灵活的 numpy 二维数组。因此可以直接使用二维数据创建 DataFrame
,只要手动指定符合形状的行列索引即可:
A | B | C | D | |
---|---|---|---|---|
1 | 0 | 1 | 2 | 3 |
2 | 4 | 5 | 6 | 7 |
3 | 8 | 9 | 10 | 11 |
也可以把 DataFrame
看成是一种结构数组,每行表示一个结构元素,行索引表示每个结构元素的索引,列索引则表示的是结构的字段名。因此,当然可以使用 numpy 的结构数组来创建 DataFrame
:
A | B | |
---|---|---|
0 | 0 | 0.0 |
1 | 0 | 0.0 |
2 | 0 | 0.0 |
结构数组的表述便于理解,但实际上可能会带来一些误解。例如,DataFrame
的索引和 numpy 的二维数组索引不太一样:在 numpy 的二维数组里,arr[0]
被认为是一个嵌套数组返回包含的第一个子数组;而在 pandas 中,第一层索引得到的结果是一个列的数据:
对 DataFrame
一种更好的理解方式是看作一个数组字典,每一个索引都可以看作是字典的一个键,对应一个列的数据;这些数据是一系列同种类型的数值,或者说一个 Series
。也就是说,DataFrame
是具有共同索引的若干 Series
对象组合。
因此,使用单个 Series
创建的是一个单列的 DataFrame
:
0 | |
---|---|
bread | 279 |
biscuit | 78 |
strawberry | 26 |
如果能接受这种 DataFrame
的理解方式,不仅容易记住它的创建方式,也有助于明白对它的操作会得到什么样的结果。
创建 DataFrame
的方式非常丰富,只要能表达出这种二维的 {column: series} 的映射关系基本都可以用于创建它。例如,可以使用一组具有相同索引的 Series
对象创建它;由于 Series
可以被看作特殊的字典,因此也可以使用一个二维字典来创建一个 DataFrame
对象:
price | sales | |
---|---|---|
cake | 23 | 5 |
cookie | 6 | 14 |
bread | 10 | 23 |
如果明白“DataFrame
是一组具有相同索引的 Series
对象组合”,就会知道字典的嵌套与被嵌套的关系:内层的字典应该要具有相同的键。
如果能理解这种嵌套关系,那么就可以很自然地明白数据获取方式:第一次索引将以列索引值为键,得到一个列作为字典;第二次索引将以行索引值为键,从得到字典中获取相应的元素:
和 Python 字典一样,Series
和 DataFrame
还支持 item assignment ,对 Series
的操作结果是更新项或添加项,对 DataFrame
的操作结果是更新列或添加列:
price | sales | sum | |
---|---|---|---|
cake | 23 | 5 | 115 |
cookie | 6 | 14 | 84 |
bread | 10 | 23 | 230 |
Index对象
pandas 的 Index
对象是构成 Series
和 DataFrame
显式索引的基础。
Series
是一维的数据,因此需要一个 Index
对象用于获取数据,这个对象被保存在它的 .index
属性中。而二维的 DataFrame
需要两个 Index
对象来定位数据,它们分别是代表行的 .index
属性和代表列的 .columns
属性:
Index
对象可以看作是一个不可变数组,因此可以像创建数组一样创建 Index
对象:
除了没有那么丰富的创建方法外,Index
对象的许多属性与操作都像数组,例如索引与切片:
两者之间的不同在于 Index
对象是不可变的,这种特征使得多个 DataFrame
等类型之间共享索引时更加安全,可以避免修改索引而破坏表的结构。
一种对 Index
更精确的描述是有序集合。pandas 对象被设计用于实现许多操作,如合并数据集,这就要求相同列之间需要合并。Index
对象遵循 Python 标准库的集合 set
数据结构的许多习惯用法,包括并集、交集、差集等:
高版本的 pandas 可能已经弃用了运算符重载的形式,或对其抛出警告,因此一般更推荐直接调用对象的方法实现这些运算。