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