以下代码默认:import pandas as pd
本节介绍操作Series和DataFrame中的数据的基本手段。
1.1 重新索引
重新索引reindex,其作用是创建一个适应新索引的新对象。调用reindex将会根据新索引进行重排,如果某个索引值当前不存在,就引入缺失值。
1 >>> obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) 2 >>> obj 3 d 4.5 4 b 7.2 5 a -5.3 6 c 3.6 7 dtype: float64 8 >>> obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e']) 9 >>> obj2 10 a -5.3 11 b 7.2 12 c 3.6 13 d 4.5 14 e NaN 15 dtype: float64 16 >>> obj.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0) 17 a -5.3 18 b 7.2 19 c 3.6 20 d 4.5 21 e 0.0 22 dtype: float64 23 >>>
对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理,method选项即可达到此目的。
1 >>> obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) 2 >>> obj3.reindex(range(6), method='ffill') 3 0 blue 4 1 blue 5 2 purple 6 3 purple 7 4 yellow 8 5 yellow 9 dtype: object
下表是可用的method选项。
ffill或pad |
前向填充(或搬运)值 |
bfill或backfill |
后向填充(或搬运)值 |
对于DataFrame,reindex可以修改(行)索引、列,或两个都修改,如果仅传入一个序列,则会重新索引行。
1 >>> frame = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 2 'Texas', 'California']) 3 >>> frame 4 Ohio Texas California 5 a 0 1 2 6 c 3 4 5 7 d 6 7 8 8 >>> frame2 = frame.reindex(['a', 'b', 'c', 'd']) #重新索引行 9 >>> frame2 10 Ohio Texas California 11 a 0.0 1.0 2.0 12 b NaN NaN NaN 13 c 3.0 4.0 5.0 14 d 6.0 7.0 8.0 15 >>> states = ['Texas', 'Utah', 'California'] 16 >>> frame.reindex(columns=states) #使用columns关键字重新索引列 17 Texas Utah California 18 a 1 NaN 2 19 c 4 NaN 5 20 d 7 NaN 8 21 >>> frame.reindex(index=['a', 'b', 'c', 'd'], method='ffill') 22 Ohio Texas California 23 a 0 1 2 24 b 0 1 2 25 c 3 4 5 26 d 6 7 8
下表是reindex函数的各参数及说明。
参数 |
说明 |
index |
用作索引的新序列,既可以是Index实例,也可以是其他序列型的python数据结构,Index会被完全使用,就像没有任何复制一样 |
method |
插值(填充)方式,具体常见之前的表格 |
fill_value |
在重新索引的过程中,需要引入缺失值时使用的替代值 |
limit |
前向或后向填充时的最大填充量 |
level |
在MultiIndex的指定级别上匹配简单索引,否则选取其子集 |
copy |
默认为True,无论无何都复制,否则为False,则新旧相等就不复制 |
1.2 丢弃指定轴上的项
丢弃某条轴上的一个或多个项只要有一个索引数组或列表即可完成。由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个在指定轴上删除了指定值的新对象。
1 >>> obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) 2 >>> new_obj = obj.drop('c') 3 >>> new_obj 4 a 0 5 b 1 6 d 3 7 e 4 8 dtype: int32 9 >>> obj.drop(['d', 'c']) 10 a 0 11 b 1 12 e 4 13 dtype: int32
对于DataFrame,可以删除任意轴上的索引值。
1 >>> data = pd.DataFrame(np.arange(16).reshape((4, 4)), index=['Oh', 'Co', 'Ut', 'New'], columns=['one', 'two', 'three', 'four']) 2 >>> data 3 one two three four 4 Oh 0 1 2 3 5 Co 4 5 6 7 6 Ut 8 9 10 11 7 New 12 13 14 15 8 >>> data.drop('two', axis=1) 9 one three four 10 Oh 0 2 3 11 Co 4 6 7 12 Ut 8 10 11 13 New 12 14 15 14 >>> data.drop(['two', 'four'], axis=1) 15 one three 16 Oh 0 2 17 Co 4 6 18 Ut 8 10 19 New 12 14
1.3 索引、选取和过滤
Series索引(obj[…])的工作方式类似于NumPy数组的索引,只不过Series的索引值不是整数。
1 >>> obj = pd.Series(np.arange(4), index=['a', 'b', 'c', 'd']) 2 >>> obj['b'] 3 1 4 >>> obj[1] 5 1 6 >>> obj[2:4] 7 c 2 8 d 3 9 dtype: int32 10 >>> obj[['b', 'a', 'd']] 11 b 1 12 a 0 13 d 3 14 dtype: int32 15 >>> obj[[1, 3]] 16 b 1 17 d 3 18 dtype: int32 19 >>> obj[obj < 2] 20 a 0 21 b 1 22 dtype: int32 23 >>>
利用标签的切片运算和普通的python切片运算不同,其末端是包含的。
1 >>> obj 2 a 0 3 b 1 4 c 2 5 d 3 6 dtype: int32 7 >>> obj['b':'d'] 8 b 1 9 c 2 10 d 3 11 dtype: int32 12 >>> obj['b':'d'] = 5 #赋值操作 13 >>> obj 14 a 0 15 b 5 16 c 5 17 d 5 18 dtype: int32
对DataFrame进行索引就是获取一个或多个列。
1 >>> data 2 one two three four 3 Oh 0 1 2 3 4 Co 4 5 6 7 5 Ut 8 9 10 11 6 New 12 13 14 15 7 >>> data['two'] 8 Oh 1 9 Co 5 10 Ut 9 11 New 13 12 Name: two, dtype: int32 13 >>> data[['three', 'one']] 14 three one 15 Oh 2 0 16 Co 6 4 17 Ut 10 8 18 New 14 12 19 >>> data[:2] # 通过切片选取行 20 one two three four 21 Oh 0 1 2 3 22 Co 4 5 6 7 23 >>> data[data['three'] > 5] #通过布尔型数组选取行 24 one two three four 25 Co 4 5 6 7 26 Ut 8 9 10 11 27 New 12 13 14 15 28 >>> data < 5 29 one two three four 30 Oh True True True True 31 Co True False False False 32 Ut False False False False 33 New False False False False 34 >>> data[data < 5] = 0 #通过布尔型数组选取行 35 >>> data 36 one two three four 37 Oh 0 0 0 0 38 Co 0 5 6 7 39 Ut 8 9 10 11 40 New 12 13 14 15 41 >>>
DataFrame的索引选项如下表所示:
类型 |
说明 |
obj[val] |
选取DataFrame的单个列或一组列,在一些特殊情况下会比较方便:布尔型数组(过滤行)、切片(行切片)、布尔型DataFrame(根据条件设置值) |
reindex方法 |
将一个或多个轴匹配到新索引 |
xs |
根据标签选取单行或单列,返回一个Series |
1.4 算术运算和数据对齐
pandas可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的所以该索引对的并集。自动的数据对齐操作在不重叠的索引处引入了NaN值,缺失值会在算术运算过程中传播。
1 >>> s1 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd']) 2 >>> s2 = pd.Series([5, 6, 7, 8], index = ['a', 'c', 'e', 'f']) 3 >>> s1 + s2 #加法操作 4 a 6.0 5 b NaN 6 c 9.0 7 d NaN 8 e NaN 9 f NaN 10 dtype: float64 11 >>>
对于DataFrame,对齐操作会同时发生在行和列上。它们相加后会返回一个新的DataFrame,其索引和列为原来那两个DataFrame的并集。
1 >>> df1 = pd.DataFrame(np.arange(9).reshape((3, 3)), columns=list('bcd'), index=['one', 'two', 2 'three']) 3 >>> df2 = pd.DataFrame(np.arange(4).reshape((2, 2)), columns=list('be'), index=['two', 'four']) 4 >>> df1 5 b c d 6 one 0 1 2 7 two 3 4 5 8 three 6 7 8 9 >>> df2 10 b e 11 two 0 1 12 four 2 3 13 >>> df1 + df2 #相加 14 b c d e 15 four NaN NaN NaN NaN 16 one NaN NaN NaN NaN 17 three NaN NaN NaN NaN 18 two 3.0 NaN NaN NaN 19 >>>
1.5 在算术方法中填充值
对不同索引的对象进行算术运算时,当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值。
1 >>> df1 2 b c d 3 one 0 1 2 4 two 3 4 5 5 three 6 7 8 6 >>> df2 7 b e 8 two 0 1 9 four 2 3 10 >>> df1.add(df2, fill_value=0) 11 b c d e 12 four 2.0 NaN NaN 3.0 13 one 0.0 1.0 2.0 NaN 14 three 6.0 7.0 8.0 NaN 15 two 3.0 4.0 5.0 1.0 16 >>> df1.add(df2, fill_value=1) 17 b c d e 18 four 3.0 NaN NaN 4.0 19 one 1.0 2.0 3.0 NaN 20 three 7.0 8.0 9.0 NaN 21 two 3.0 5.0 6.0 2.0 22 >>> df1.reindex(columns=df2.columns, fill_value=0) 23 b e 24 one 0 0 25 two 3 0 26 three 6 0
灵活的算术方法如下表所示:
方法 |
说明 |
add |
用于加法(+)的方法 |
sub |
用于减法(-)的方法 |
div |
用于除法(/)的方法 |
mul |
用于乘法(*)的方法 |
1.6 DataFrame和Series之间的运算
DATaFrame和Series之间的运算由明确的规定。例如计算一个二维数组与其某行之间的差。
1 >>> arr = np.arange(12).reshape((3, 4)) 2 >>> arr 3 array([[ 0, 1, 2, 3], 4 [ 4, 5, 6, 7], 5 [ 8, 9, 10, 11]]) 6 >>> arr[0] 7 array([0, 1, 2, 3]) 8 >>> arr - arr[0] #会进行广播 9 array([[0, 0, 0, 0], 10 [4, 4, 4, 4], 11 [8, 8, 8, 8]])
DataFrame和Series之间的运算会将Series的索引匹配到DataFrame的列,然后沿着行一直向下广播。
1 >>> frame = pd.DataFrame(np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Ut', 'Oh', 'Te', 'Or']) 2 >>> frame 3 b d e 4 Ut 0 1 2 5 Oh 3 4 5 6 Te 6 7 8 7 Or 9 10 11 8 >>> series = pd.Series(np.arange(3), index=['b', 'd', 'e']) 9 >>> series 10 b 0 11 d 1 12 e 2 13 dtype: int32 14 >>> frame - series 15 b d e 16 Ut 0 0 0 17 Oh 3 3 3 18 Te 6 6 6 19 Or 9 9 9 20 >>>
如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集。
1 >>> series2 = pd.Series(range(3), index=list('bef')) 2 >>> series2 3 b 0 4 e 1 5 f 2 6 dtype: int64 7 >>> frame 8 b d e 9 Ut 0 1 2 10 Oh 3 4 5 11 Te 6 7 8 12 Or 9 10 11 13 >>> frame + series2 14 b d e f 15 Ut 0.0 NaN 3.0 NaN 16 Oh 3.0 NaN 6.0 NaN 17 Te 6.0 NaN 9.0 NaN 18 Or 9.0 NaN 12.0 NaN 19 >>>
如果希望匹配行且在列上广播,则必须使用算术运算方法。
1 >>> series3 = frame['d'] 2 >>> frame 3 b d e 4 Ut 0 1 2 5 Oh 3 4 5 6 Te 6 7 8 7 Or 9 10 11 8 >>> series3 9 Ut 1 10 Oh 4 11 Te 7 12 Or 10 13 Name: d, dtype: int32 14 >>> frame.sub(series3, axis=0) 15 b d e 16 Ut -1 0 1 17 Oh -1 0 1 18 Te -1 0 1 19 Or -1 0 1
1.7 函数应用和映射
NumPy的ufuncs(元素级数组方法)也可用于操作pandas对象。
1 >>> frame 2 b d e 3 Ut 0 -3 2 4 Oh 3 -3 5 5 Te 6 -3 8 6 Or 9 -3 11 7 >>> np.abs(frame) 8 b d e 9 Ut 0 3 2 10 Oh 3 3 5 11 Te 6 3 8 12 Or 9 3 11
另一个常见操作,将函数应用到各列或行所形成的一维数组上。DataFrame的apply方法可实现此功能。
1 >>> f = lambda x: x.max() - x.min() 2 >>> frame 3 b d e 4 Ut 0 -3 2 5 Oh 3 -3 5 6 Te 6 -3 8 7 Or 9 -3 11 8 >>> frame.apply(f) 9 b 9 10 d 0 11 e 9 12 dtype: int64 13 >>> frame.apply(f, axis=1) 14 Ut 5 15 Oh 8 16 Te 11 17 Or 14 18 dtype: int64 19 >>>
除标量值外,传递给apply的函数还可以返回由多个值组成的Series。
1 >>> def f(x): 2 ... return pd.Series([x.min(), x.max()], index=['min', 'max']) 3 ... 4 >>> frame 5 b d e 6 Ut 0 -3 2 7 Oh 3 -3 5 8 Te 6 -3 8 9 Or 9 -3 11 10 >>> frame.apply(f) 11 b d e 12 min 0 -3 2 13 max 9 -3 11 14 >>>
元素级的python函数也是可以使用的。例如求frame中各个浮点值的格式化字符串,使用applymap即可。
1 >>> format = lambda x: '%.2f' % x 2 >>> frame.applymap(format) 3 b d e 4 Ut 0.00 -3.00 2.00 5 Oh 3.00 -3.00 5.00 6 Te 6.00 -3.00 8.00 7 Or 9.00 -3.00 11.00
1.8 排序和排名
(1)排序
根据条件对数据集排序(sorting)也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可使用sort_index方法,它返回的是一个已排序的新对象。
1 >>> obj = pd.Series(range(4), index=['d', 'e', 'b', 'c']) 2 >>> obj.sort_index() 3 b 2 4 c 3 5 d 0 6 e 1 7 dtype: int64
对于DataFrame,可以根据任意一个轴上的索引进行排序。
1 >>> frame = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'e', 'b', 'c']) 2 >>> frame.sort_index() 3 d e b c 4 one 4 5 6 7 5 three 0 1 2 3 6 >>> frame.sort_index(axis=1) #对轴1进行排序 7 b c d e 8 three 2 3 0 1 9 one 6 7 4 5 10 >>> frame.sort_index(axis=1, ascending=False) #默认为升序,改为降序 11 e d c b 12 three 1 0 3 2 13 one 5 4 7 6 14 >>>
(2)排名
排名跟排序密切相关,且它会增加一个排名值(从1开始,一直到数组中有效数据的数量)。使用的是rank方法,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的。
这里有点不好理解,可按照下图理解。
原始数据 |
人为的排名 |
method参数值 |
||||
索引 |
值 |
average |
min |
max |
first |
|
0 |
7 |
6 |
6.5 |
6 |
7 |
6 |
1 |
-5 |
1 |
1 |
1 |
1 |
1 |
2 |
7 |
7 |
6.5 |
6 |
7 |
7 |
3 |
4 |
4 |
4.5 |
4 |
5 |
4 |
4 |
2 |
3 |
3 |
3 |
3 |
3 |
5 |
0 |
2 |
2 |
2 |
2 |
2 |
6 |
4 |
5 |
4.5 |
4 |
5 |
5 |
method参数说明。
method |
说明 |
‘average’ |
默认,在相等分组中,为各个值分配平均排名 |
‘min’ |
使用整个分组的最小排名 |
‘max’ |
使用整个分组的最大排名 |
‘first’ |
按值在原始数据中出现顺序分配排名 |
示例:
1 >>> obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) 2 >>> obj.rank() 3 0 6.5 4 1 1.0 5 2 6.5 6 3 4.5 7 4 3.0 8 5 2.0 9 6 4.5 10 dtype: float64 11 >>> obj 12 0 7 13 1 -5 14 2 7 15 3 4 16 4 2 17 5 0 18 6 4 19 dtype: int64 20 >>> obj.rank(method='first') #根据值在原数据中出现的顺序给出排名 21 0 6.0 22 1 1.0 23 2 7.0 24 3 4.0 25 4 3.0 26 5 2.0 27 6 5.0 28 dtype: float64 29 >>> obj.rank(ascending=False, method='max') #按降序进行排名 30 0 2.0 31 1 7.0 32 2 2.0 33 3 4.0 34 4 5.0 35 5 6.0 36 6 4.0 37 dtype: float64
DataFrame可以在行或列上计算排名:
1 >>> frame = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]}) 2 >>> frame 3 b a c 4 0 4.3 0 -2.0 5 1 7.0 1 5.0 6 2 -3.0 0 8.0 7 3 2.0 1 -2.5 8 >>> frame.rank(axis=1) 9 b a c 10 0 3.0 2.0 1.0 11 1 3.0 1.0 2.0 12 2 1.0 2.0 3.0 13 3 3.0 2.0 1.0
1.9 带有重复值的轴索引
pandas并不强制要求轴标签唯一。对于带有重复值的索引,数据选取的型位将会有所不同。如果某个索引对应多个值,则返回一个Series;而对应单个值的,则返回一个标量值。DataFrame也是如此。
1 >>> obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c']) 2 >>> obj 3 a 0 4 a 1 5 b 2 6 b 3 7 c 4 8 dtype: int64 9 >>> obj.index.is_unique 10 False 11 >>> obj['a'] 12 a 0 13 a 1 14 dtype: int64 15 >>> obj['c'] 16 4