第十四天
接下来学习Pandas工具。
Pandas是在Numpy基础上建立的新程序库,提供了一种高效的DataFrame数据结构。DataFrame本质上是一种带有行标签和列标签、支持相同类型数据和缺失值的多维数组。Pandas不仅为带各种标签的数据提供了便利的存储界面,还实现了许多强大的操作。尤其它的Series和DataFrame对象,为数据我们处理那些消耗大量时间的数据清理任务提供了捷径。
Pandas对象简介
如果从底层视角观察Pandas对象,可以把它们看成增强版的Numpy结构化数组,行列都不再只是简单的整数索引,还可以带上标签。Pandas有三个基本数据结构:Series
、DataFrame
和Index
。
一、Series对象
Pandas的Series对象是一个待索引数据构成的一维数组。可以用一个数组创建Series对象。
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0]) data # 0 0.25 1 0.50 2 0.75 3 1.00 dtype:float64
从上面的结果中发现Series对象将一组数据和一组索引绑定在一起,我们可以通过values属性和index属性获取数据。values属性返回的结果与Numpy数组类似:
data.values # array([0.25, 0.5, 0.75, 1.])
index属性返回的结果是一个类型为pd.Index
的类数组对象。
data.index # RangeIndex(start=0, stop=4, step=1)
和Numpy数组一样,数据可以通过Python的中括号索引标签获取:
data[1] # 0.5 data[1:3] # 1 0.5 2 0.75
1.Serise是通用的Numpy数组
Numpy数组通过隐式定义的整数索引获取数值,而Pandas的Series对象用一种显式定义的索引与数值关联。显式索引的定义让Series对象拥有了更强的能力。索引不再仅仅是整数,还可以是任意想要的类型。如果需要,完全可以用字符串定义索引。
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd']) data # a 0.25 b 0.50 c 0.75 d 1.00 dtype:float64 ---------------- 也可以使用不连续或不按顺序的索引: data = pd.Series([0.25, 0.5, 0.75, 1.0], index=[2, 5, 3, 7]) data[5] # 0.5
2.Series是特殊的字典
可以把Pandas的Series对象看成一种特殊的Python字典。字典是一种将任意键映射到一组任意值的数据结构,而Series对象其实是一种将类型键映射到一组类型值的数据结构。
我们可以直接用Python的字典创建一个Series对象,让Series对象与字典的类比更加清晰。
population_dict = {'california':'333', 'texas':'222', 'newyork':'111'} population = pd.Series(population_dict) ------------ population california 333 texas 222 newyork 111
用 字典创建Series对象时,其索引默认按照顺序排列。典型的字典数值获取方式仍然有效:
population['california'] # 333
和字典不同,Series对象还支持数值形式的操作,比如切片:
population['california':'texas'] # california 333 texas 222
3.创建Series对象
刚刚我们已经看到过集中创建Pandas的Series对象的方法,都是类似与下面这样的形式:
pd.Series(data, index=index) # 其中index是一个可选的参数,data参数支持多种数据类型 # data是一个列表或Numpy数组 pd.Series([2, 4, 6]) # 0 2 1 4 2 6 dtype=int64 ------------------ # data是一个标量,创建的Series对象会重复填充到每个索引上 pd.Series(5, index=[100, 200, 300]) # 100 5 200 5 300 5 dtype=int64 ------------------ # data是一个字典,index默认是排序的字典键 pd.Series({2:'a', 1:'b', 3:'c'}) # 1 b 2 a 3 c dtype=object
无论哪种形式,我们都可以通过显示指定索引筛选需要的结果。另外需要注意的是,Series对象只会保留显示定义的键值对。
二、DataFrame对象
Pandas的另一个基础数据结构是DataFrame对象。和Series对象一样,DataFrame既可以作为一个通用型Numpy数组,也可以看作特殊的Python字典。
1.DataFrame是通用的Numpy数组
如果将Series 类比为带灵活索引的一维数组,那么DataFrame 就可以看作是一种既有灵活 的行索引,又有灵活列名的二维数组。就像你可以把二维数组看成是有序排列的一维数组 一样,你也可以把DataFrame 看成是有序排列的若干Series 对象。这里的“排列”指的是 它们拥有共同的索引。
#美国五个州面积的数据创建一个新的Series area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297, 'Florida': 170312, 'Illinois': 149995} area = pd.Series(area_dict) area ------------------- # California 423967 Florida 170312 Illinois 149995 New York 141297 Texas 695662 dtype: int64 ------------------- # 再结合之前创建的population 的Series 对象,用一个字典创建一个包含这些信息的二维 对象: states = pd.DataFrame({'population':population, 'area':area}) states 输出: area population California 423967 38332521 Florida 170312 19552860 Illinois 149995 12882135 New York 141297 19651127 Texas 695662 26448193
和Series对象一样,DataFrame也有一个index属性可以获取索引标签:
states.index # Index(['California', 'Florida', 'Illinois', 'New York', 'Texas'], dtype='object')
另外,DataFrame还有columns属性,是存放列标签的Index对象:
states.columns # Index(['area', 'population'], dtype='object')
因此,DataFrame可以看作一种通用的Numpy二维数组,它的行与列都可以通过索引获取。
2.DataFrame是特殊的字典
与Series 类似,我们也可以把DataFrame 看成一种特殊的字典。字典是一个键映射一个值,而DataFrame 是一列映射一个Series 的数据。例如,通过'area' 的列属性可以返回包含面积数据的Series 对象:
states['area'] # California 423967 Florida 170312 Illinois 149995 New York 141297 Texas 695662 Name: area, dtype: int64
3.创建DataFrame对象
Pandas的DataFrame对象可以通过许多方式创建
(1)通过单个Series对象创建。DataFrame是一组Series对象的集合,可以用单个Series创建一个单列的DataFrame:
pd.DataFrame(population, columns=['population']) # population California 38332521 Florida 19552860 Illinois 12882135 New York 19651127 Texas 26448193
(2)通过字典列表创建。任何元素是字典的列表都可以变成DataFrame。
data = [{'a':i, 'b':2*i} for i in range(3)] pd.DataFrame(data) # a b 0 0 0 1 1 2 2 2 4
即使字典中有些键的值不存在,Pandas也会用缺失值NaN来表示:
pd.DataFrame([{'a':1, 'b':2}, {'b':3, 'c':4}]) # a b c 0 1.0 2 NaN 1 NaN 3 4.0
(3)通过Series对象字典创建。就像之前我们用过的那样,DataFrame 也可以用一个由Series 对象构成的字典创建:
pd.DataFrame({'population':population, 'area':area})
(4)通过Numpy二维数组创建。由于Pandas 的DataFrame与结构化数组十分相似,因此可以通过结构化数组创建DataFrame:
A = np.zeros(3, dtype=[('A', 'i8'), ('B', 'f8')]) # array([(0, 0.0), (0, 0.0), (0, 0.0)], dtype=[('A', '<i8'), ('B', '<f8')]) pd.DataFrame(A) # A B 0 0 0.0 1 0 0.0 2 0 0.0
三、Pandas的Index对象
我们已经发现,Series 和DataFrame 对象都使用便于引用和调整的显式索引。Pandas 的Index 对象是一个很有趣的数据结构,可以将它看作是一个不可变数组或有序集合(实际上是一个多集,因为Index 对象可能会包含重复值)。
index = pd.Index([2, 3, 5, 7 ,11]) index # Int64Index([2, 3, 5, 7, 11], dtype='int64')
1.将Index看作不可变数组
Index对象的许多操作都像数组。例如,可以通过标准的Python的取值方法获取数值,也可以通过切片获取数值:
index[1] # 3 index[::2] # Int64Index([2, 5, 11], dtype='int64')
Index对象还有许多与Numpy数组相似的属性:
print(index.size, indes.shape, index.ndim, index.dtype) # 5 (5,) 1 int64
Index 对象与NumPy 数组之间的不同在于,Index 对象的索引是不可变的,也就是说不能通过通常的方式进行调整。Index 对象的不可变特征使得多个DataFrame 和数组之间进行索引共享时更加安全,尤其是可以避免因修改索引时粗心大意而导致的副作用。
2.将Index看作有序集合
Pandas 对象被设计用于实现许多操作,如连接(join)数据集,其中会涉及许多集合操作。Index 对象遵循Python 标准库的集合(set)数据结构的许多习惯用法,包括并集、交集、差集等。
indexA = pd.Index([1, 3, 5, 7, 9]) indexB = pd.Index([2, 3, 5, 7, 11]) indexA & indexB # 交集 # Int64Index([3, 5, 7], dtype='int64') indexA | indexB # 并集 # Int64Index([1, 2, 3, 5, 7, 9, 11], dtype='int64')