一、重建索引(Reindex)
1 | obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) |
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
对Series对象应用reindex函数后,将按参数指定的新索引进行重建数据,索引对应的数据如果本来不存在,那么会引进缺失值(NaN)。
1 | obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e']) |
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
与时间序列(Time Series)的有序数据类似,Series可以在重建索引时,method选项可以指定中间数据填充的模式。举例,method选项指定为ffill,会向前填充中间原不存在的数据。
1 | obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) |
0 blue
2 purple
4 yellow
dtype: object
1 | obj3.reindex(range(6), method='ffill') #重建索引后,原索引标签中间原先没有的标签对应的数据则会根据前面的数据往前填充。 |
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object
对DataFrame来说,reindex函数可以调整行或列或者两者。若只传入一个序列,则只重建行索引。
1 | frame = pd.DataFrame(np.arange(9).reshape((3, 3)),index=['a', 'c', 'd'],columns=['Ohio', 'Texas', 'California']) |
Ohio | Texas | California | |
---|---|---|---|
a | 0 | 1 | 2 |
c | 3 | 4 | 5 |
d | 6 | 7 | 8 |
1 | frame2 = frame.reindex(['a', 'b', 'c', 'd']) #只重建行 |
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 |
指定columns关键字,可调整列索引。
1 | states = ['Texas', 'Utah', 'California'] |
Texas | Utah | California | |
---|---|---|---|
a | 1 | NaN | 2 |
c | 4 | NaN | 5 |
d | 7 | NaN | 8 |
同时调整行和列,使用loc方法会使语义更加明确。
1 | frame.loc[['a', 'b', 'c', 'd'], states] |
Texas | Utah | California | |
---|---|---|---|
a | 1.0 | NaN | 2.0 |
b | NaN | NaN | NaN |
c | 4.0 | NaN | 5.0 |
d | 7.0 | NaN | 8.0 |
reindex函数参数选项
参数 | 说明 |
---|---|
index | 指定一个序列作为调整后的序列。可以是Index对象或其他python类序列 |
method | 间行填充方法, ‘ffill’向前填充,’bfill’向后填充. |
fill_value | 缺失值填充值 |
limit | 填充时,填充间行的最大数 |
tolerance | 填充时,不准确匹配时,填充间行的最大数 |
level | 多重索引的层次中匹配简单索引,否则选择其子集 |
copy | 是否拷贝原索引数据,如果新索引与老索引相等 |
二、使用drop函数从一条轴上删除元素
1.删除Series中的元素
1 | import numpy as np |
a 0.0
b 1.0
c 2.0
d 3.0
e 4.0
dtype: float64
1 | new_obj = obj.drop('c') #删掉索引为c的元素 |
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
1 | obj |
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
1 | obj.drop(['d', 'c']) #删除d、c两个元素 |
a 0.0
b 1.0
e 4.0
dtype: float64
2.指定轴删除DataFrame的行或列
1 | data = pd.DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],columns=['one', 'two', 'three', 'four']) |
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
1 | data.drop(['Colorado', 'Ohio']) #沿0轴(行)删除,即根据行的索引删除行 |
one | two | three | four | |
---|---|---|---|---|
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
1 | data.drop('two', axis=1) #沿1轴(列)删除,跟根据列的标签删除指定列 |
one | three | four | |
---|---|---|---|
Ohio | 0 | 2 | 3 |
Colorado | 4 | 6 | 7 |
Utah | 8 | 10 | 11 |
New York | 12 | 14 | 15 |
1 | data.drop(['two', 'four'], axis='columns') #axis参数可以指定为columns,与指定为1作用相同。 |
one | three | |
---|---|---|
Ohio | 0 | 2 |
Colorado | 4 | 6 |
Utah | 8 | 10 |
New York | 12 | 14 |
1 | obj |
a 0.0
b 1.0
c 2.0
d 3.0
e 4.0
dtype: float64
1 | obj.drop('c', inplace=True) #就地修改原对象,使用inplace参数需小心,因为被删掉的元素都被销毁了。 |
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
三、索引、选择、筛选
对Series索引操作
1 | obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd']) |
a 0.0
b 1.0
c 2.0
d 3.0
dtype: float64
1 | obj['b'] #按照索引标签定位对象 |
1.0
1 | obj[1] #也可以按照位置进行索引 |
1.0
1 | obj[2:4] #切片 |
c 2.0
d 3.0
dtype: float64
1 | obj[['b', 'a', 'd']] #多个索引标签 |
b 1.0
a 0.0
d 3.0
dtype: float64
1 | obj[[1, 3]] #多个索引位置 |
b 1.0
d 3.0
dtype: float64
1 | obj[obj < 2] #使用条件表达式 |
a 0.0
b 1.0
dtype: float64
Series使用索引标签切片与普通Numpy切片不同之处是Series切片时最后的元素是包含在内的。
1 | obj['b':'c'] |
b 1.0
c 2.0
dtype: float64
使用切片表达式对多个元素进行赋值
1 | obj['b':'c'] = 5 |
a 0.0
b 5.0
c 5.0
d 3.0
dtype: float64
对DataFrame的切片、索引操作生成一列或多列元素。
1 | data = pd.DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],columns=['one', 'two', 'three', 'four']) |
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
使用列标签进行索引,得到对应的列
1 | data['two'] |
Ohio 1
Colorado 5
Utah 9
New York 13
Name: two, dtype: int32
1 | data[['three', 'one']] |
three | one | |
---|---|---|
Ohio | 2 | 0 |
Colorado | 6 | 4 |
Utah | 10 | 8 |
New York | 14 | 12 |
行选择
1 | data[:2] #行选择的简便形式 |
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
1 | data[data['three'] > 5] #逻辑表达式,选择行 |
one | two | three | four | |
---|---|---|---|---|
Colorado | 4 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
使用布尔DataFrame进行选择,用法与Numpy的二维数组是类似的。
1 | data < 5 |
one | two | three | four | |
---|---|---|---|---|
Ohio | True | True | True | True |
Colorado | True | False | False | False |
Utah | False | False | False | False |
New York | False | False | False | False |
1 | data[data < 5] = 0 #小于5的元素赋值为0 |
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 0 | 0 | 0 |
Colorado | 0 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
使用loc或iloc进行行选择
loc是用索引标签进行行选择,iloc使用整数索引进行行选择。
1 | data.loc['Colorado', ['two', 'three']] #选择Colorado行的two和three这两列的对应元素 |
two 5
three 6
Name: Colorado, dtype: int32
1 | data.iloc[2, [3, 0, 1]] #选择第3行的four、one、two这三列的对应元素 |
four 11
one 8
two 9
Name: Utah, dtype: int32
1 | data.iloc[2] #第三行 |
one 8
two 9
three 10
four 11
Name: Utah, dtype: int32
1 | data.iloc[[1, 2], [3, 0, 1]] #第2、3行的第4、1、2列的对应元素 |
four | one | two | |
---|---|---|---|
Colorado | 7 | 0 | 5 |
Utah | 11 | 8 | 9 |
上面的对一个或多个标签进行的索引的方法也可应用于切片
1 | data.loc[:'Utah', 'two'] #Utah行之前的行的two列元素 |
Ohio 0
Colorado 5
Utah 9
Name: two, dtype: int32
1 | data.iloc[:, :3][data.three > 5] #先选择所有的行,前3列,再使用逻辑表达式筛选 |
one | two | three | |
---|---|---|---|
Colorado | 0 | 5 | 6 |
Utah | 8 | 9 | 10 |
New York | 12 | 13 | 14 |
DataFrame的索引类型
类型 | 说明 |
---|---|
df[val] | 选择单列或多列,特殊用法:布尔值数组,切片,布尔值DataFrame |
df.loc[val] | 根据标签选择行 |
df.loc[:, val] | 根据标签选择列 |
df.loc[val1, val2] | 同时选择行、列 |
df.iloc[where] | 根据整数位置选择行 |
df.iloc[:, where] | 根据整数位置选择列 |
df.iloc[where_i, where_j] | 根据整数位置同时选择行、列 |
df.at[label_i, label_j] | 根据行、列标签选择一个标量值 |
df.iat[i, j] | 根据整数位置选择标量值 |
reindex | 根据行、列标签选择 |
get_value, set_value | 根据行列标签读取值或赋值 |
四、整数索引产生的问题
1 | ser = pd.Series(np.arange(3.)) #不适用索引标签,索引缺省为整数序列 |
0 0.0
1 1.0
2 2.0
dtype: float64
1 | ser[2] #因为是整数标签,使用的是pandas Series中的索引对象进行索引。2是索引对象[0,1,2]中的元素,所以能正常读取。 |
2.0
没有标签的情况下,使用整数位置索引,用-1取最后一个数,产生错误。因为Ser中的索引为整数0,1,2,没有-1。在python的内建索引机制中,-1是取最后一个数,而pandas是按照其索引对象来定位的,所以python内建的索引机制与pandas的索引机制在这里产生了混淆。
1 | ser[-1] # Series索引对象[0,1,2]中不包含-1,因此出错。 |
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-60-3cbe0b873a9e> in <module>()
----> 1 ser[-1]
D:\Anaconda3\lib\site-packages\pandas\core\series.py in __getitem__(self, key)
599 key = com._apply_if_callable(key, self)
600 try:
--> 601 result = self.index.get_value(self, key)
602
603 if not is_scalar(result):
D:\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in get_value(self, series, key)
2475 try:
2476 return self._engine.get_value(s, k,
-> 2477 tz=getattr(series.dtype, 'tz', None))
2478 except KeyError as e1:
2479 if len(self) > 0 and self.inferred_type in ['integer', 'boolean']:
pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_value()
pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_value()
pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc()
pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()
pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()
KeyError: -1
1 | ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c']) |
使用标签的Series,因为Series的索引对象不是整数,因此使用整数索引时不会产生混淆,只可能用python内建索引机制进行选择,选择是最后一个元素。所以,为避免索引对象的混淆,使用索引标签是推荐行为。
1 | ser2[-1] #与ser不同,这里是python内建索引机制,因此-1是读取最后一个数 |
2.0
1 | ser[:1] #同样,切片操作也是面向标签的。所以,因为Ser是整数索引,没有索引标签,所以这里选择的Series的整数标签行,而不是python的内建索引机制。 |
0 0.0
dtype: float64
1 | ser.loc[:1] #如果用pandas的loc函数,则选择对象的意义很明确,loc函数的结果包含最后的数的 |
0 0.0
1 1.0
dtype: float64
五、数学运算与数据对齐
pandas的一个重要特性是两个不同索引的对象进行数学运算会如何表现。如,这两个对象的索引不同,讲这两个对象相加,如果索引对不相同,那么结果对象的索引是参加运算的两个对象的索引的并集。如果你对数据库熟悉的话,则可以理解成索引标签的outer连接。
1 | s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e']) |
a 7.3
c -2.5
d 3.4
e 1.5
dtype: float64
1 | s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1],index=['a', 'c', 'e', 'f', 'g']) |
a -2.1
c 3.6
e -1.5
f 4.0
g 3.1
dtype: float64
1 | s1 + s2 #索引标签d只在s1中,f、g只在s2中,结果是两个合集 |
a 5.2
c 1.1
d NaN
e 0.0
f NaN
g NaN
dtype: float64
对DataFrame来说,行和列两个方向都要对齐
1 | df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'),index=['Ohio', 'Texas', 'Colorado']) |
b | c | d | |
---|---|---|---|
Ohio | 0.0 | 1.0 | 2.0 |
Texas | 3.0 | 4.0 | 5.0 |
Colorado | 6.0 | 7.0 | 8.0 |
1 | df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'),index=['Utah', 'Ohio', 'Texas', 'Oregon']) |
b | d | e | |
---|---|---|---|
Utah | 0.0 | 1.0 | 2.0 |
Ohio | 3.0 | 4.0 | 5.0 |
Texas | 6.0 | 7.0 | 8.0 |
Oregon | 9.0 | 10.0 | 11.0 |
1 | df1 + df2 #两者之和,只在索引标签和列标签并集的位置数值相加,其他位置都是NaN |
b | c | d | e | |
---|---|---|---|---|
Colorado | NaN | NaN | NaN | NaN |
Ohio | 3.0 | NaN | 6.0 | NaN |
Oregon | NaN | NaN | NaN | NaN |
Texas | 9.0 | NaN | 12.0 | NaN |
Utah | NaN | NaN | NaN | NaN |
所以,如果两个DataFrame没有共同的索引标签或行标签,加(减)运算的结果将全为NaN。
1 |
|
A | |
---|---|
0 | 1 |
1 | 2 |
1 | df2 = pd.DataFrame({'B': [3, 4]}) |
B | |
---|---|
0 | 3 |
1 | 4 |
1 | df1 - df2 #两者没有共同的列,所以所有的数值都是NaN |
A | B | |
---|---|---|
0 | NaN | NaN |
1 | NaN | NaN |
以填充数值进行算数运算
对不同索引的对象进行算数运算,如果一个对象轴中的数据在另一个对象中找不到对应的标签,可以指定填充值进行填充。
1 | df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)),columns=list('abcd')) |
a | b | c | d | |
---|---|---|---|---|
0 | 0.0 | 1.0 | 2.0 | 3.0 |
1 | 4.0 | 5.0 | 6.0 | 7.0 |
2 | 8.0 | 9.0 | 10.0 | 11.0 |
1 | df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)),columns=list('abcde')) |
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 0.0 | 1.0 | 2.0 | 3.0 | 4.0 |
1 | 5.0 | NaN | 7.0 | 8.0 | 9.0 |
2 | 10.0 | 11.0 | 12.0 | 13.0 | 14.0 |
3 | 15.0 | 16.0 | 17.0 | 18.0 | 19.0 |
1 | df1 + df2 #缺失值的计算仍是缺失值 |
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 0.0 | 2.0 | 4.0 | 6.0 | NaN |
1 | 9.0 | NaN | 13.0 | 15.0 | NaN |
2 | 18.0 | 20.0 | 22.0 | 24.0 | NaN |
3 | NaN | NaN | NaN | NaN | NaN |
1 | df1.add(df2, fill_value=0) #对df1和df2中的缺失值指定为0,然后再计算。 |
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 0.0 | 2.0 | 4.0 | 6.0 | 4.0 |
1 | 9.0 | 5.0 | 13.0 | 15.0 | 9.0 |
2 | 18.0 | 20.0 | 22.0 | 24.0 | 14.0 |
3 | 15.0 | 16.0 | 17.0 | 18.0 | 19.0 |
对于Series和DataFrame的Reindex函数,也可以指定缺失填充值
1 | df1.reindex(columns=df2.columns, fill_value=0) #对df1使用df2的列名重新创建索引,缺失的列填充为0. |
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 0.0 | 1.0 | 2.0 | 3.0 | 0 |
1 | 4.0 | 5.0 | 6.0 | 7.0 | 0 |
2 | 8.0 | 9.0 | 10.0 | 11.0 | 0 |
灵活的算数运算函数
函数 | 描述 |
---|---|
add, radd | 相加,radd是把对象翻为右参数,下同 |
sub, rsub | 相减 |
div, rdiv | 相除 |
floordiv, rfloordiv | 地板除(//) |
mul, rmul | 乘法 |
pow, rpow | 指数 |
1 | 1 / df1 |
a | b | c | d | |
---|---|---|---|---|
0 | inf | 1.000000 | 0.500000 | 0.333333 |
1 | 0.250000 | 0.200000 | 0.166667 | 0.142857 |
2 | 0.125000 | 0.111111 | 0.100000 | 0.090909 |
1 | df1.rdiv(1) #df1.rdiv(1)与1/df1等价。 |
a | b | c | d | |
---|---|---|---|---|
0 | inf | 1.000000 | 0.500000 | 0.333333 |
1 | 0.250000 | 0.200000 | 0.166667 | 0.142857 |
2 | 0.125000 | 0.111111 | 0.100000 | 0.090909 |
DateFrame和Series之间的运算
与numpy支持不同维度的数组之间的运算类似,pandas也支持DataFrame和Series之间的运算。
1 | arr = np.arange(12.).reshape((3, 4)) |
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
1 | arr[0] |
array([ 0., 1., 2., 3.])
1 | arr - arr[0] #DataFrame与其第一行的差 |
array([[ 0., 0., 0., 0.],
[ 4., 4., 4., 4.],
[ 8., 8., 8., 8.]])
上例中,Numpy数组的每一行都会减去第一行,而不是只是第一行参加运算。这就是广播(broadcasting)。在pandas中,也有类似广播模式。
1 | frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),columns=list('bde'),index=['Utah', 'Ohio', 'Texas', 'Oregon']) |
b | d | e | |
---|---|---|---|
Utah | 0.0 | 1.0 | 2.0 |
Ohio | 3.0 | 4.0 | 5.0 |
Texas | 6.0 | 7.0 | 8.0 |
Oregon | 9.0 | 10.0 | 11.0 |
1 | series = frame.iloc[0] |
b 0.0
d 1.0
e 2.0
Name: Utah, dtype: float64
1 | frame - series |
b | d | e | |
---|---|---|---|
Utah | 0.0 | 0.0 | 0.0 |
Ohio | 3.0 | 3.0 | 3.0 |
Texas | 6.0 | 6.0 | 6.0 |
Oregon | 9.0 | 9.0 | 9.0 |
缺省状况下,DataFrame与Series的差是以Series的索引去匹配DataFrame的列,逐行广播运算。
如果一个索引的值在DataFrame列中或Series索引之一中不存在,那么结果对象会合并DataFrame列名及Series索引名以重建为新的索引。
1 | series2 = pd.Series(range(3), index=['b', 'e', 'f']) |
b | d | e | f | |
---|---|---|---|---|
Utah | 0.0 | NaN | 3.0 | NaN |
Ohio | 3.0 | NaN | 6.0 | NaN |
Texas | 6.0 | NaN | 9.0 | NaN |
Oregon | 9.0 | NaN | 12.0 | NaN |
如果想要改变上述缺省行为,想要DataFrame按列广播,在行上进行匹配,那么可以用算数函数,并指定轴参数加以改变。
1 | series3 = frame['d'] |
Utah 1.0
Ohio 4.0
Texas 7.0
Oregon 10.0
Name: d, dtype: float64
1 | frame |
b | d | e | |
---|---|---|---|
Utah | 0.0 | 1.0 | 2.0 |
Ohio | 3.0 | 4.0 | 5.0 |
Texas | 6.0 | 7.0 | 8.0 |
Oregon | 9.0 | 10.0 | 11.0 |
1 | frame.sub(series3, axis='index') #指定按列进行运算并广播运算。 |
b | d | e | |
---|---|---|---|
Utah | -1.0 | 0.0 | 1.0 |
Ohio | -1.0 | 0.0 | 1.0 |
Texas | -1.0 | 0.0 | 1.0 |
Oregon | -1.0 | 0.0 | 1.0 |
六、函数应用及映射
numpy通用函数同样使用于pandas。
1 | frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'),index=['Utah', 'Ohio', 'Texas', 'Oregon']) |
b | d | e | |
---|---|---|---|
Utah | -0.058971 | 0.962351 | 0.886096 |
Ohio | -1.397272 | -0.207003 | 0.198786 |
Texas | -0.293349 | 0.303266 | -0.037189 |
Oregon | -1.263869 | 0.745421 | -1.587822 |
1 | np.abs(frame) #求绝对值 |
b | d | e | |
---|---|---|---|
Utah | 0.058971 | 0.962351 | 0.886096 |
Ohio | 1.397272 | 0.207003 | 0.198786 |
Texas | 0.293349 | 0.303266 | 0.037189 |
Oregon | 1.263869 | 0.745421 | 1.587822 |
另外一个常用的操作是在一维数组上应用的函数可以应用到每一行或每一列。DataFrame的apply方法的具体用法:
1 | f = lambda x: x.max() - x.min() |
b 1.338300
d 1.169354
e 2.473918
dtype: float64
如果指定axis=column
参数,则可按行应用f
函数:
1 | frame.apply(f, axis='columns') |
Utah 1.021322
Ohio 1.596058
Texas 0.596615
Oregon 2.333243
dtype: float64
大部分普通的数组统计函数(如sum和mean)都是DataFrame函数,因此apply函数并无使用的必要。
传递给apply的函数并非一定要返回一个标量,它也可以返回一个Series对象,即可返回一组值。
1 | def f(x): |
b | d | e | |
---|---|---|---|
min | -1.397272 | -0.207003 | -1.587822 |
max | -0.058971 | 0.962351 | 0.886096 |
元素智能(element-wise)函数也可以应用在此。比如,要对DataFrame对象的每一个元素按格式字符串格式化,可以如下例这样使用applymap函数:
1 | format = lambda x: '%.2f' % x #保留两位小数的格式化字符串 |
b | d | e | |
---|---|---|---|
Utah | -0.06 | 0.96 | 0.89 |
Ohio | -1.40 | -0.21 | 0.20 |
Texas | -0.29 | 0.30 | -0.04 |
Oregon | -1.26 | 0.75 | -1.59 |
applymap函数名称的由来是因为Series有一个对应的map函数:
1 | frame['e'].map(format) |
Utah 0.89
Ohio 0.20
Texas -0.04
Oregon -1.59
Name: e, dtype: object
七、排序
按照某个标准对数据集进行排序是另一个重要的内建操作。按照行名或列名的词义进行排序使用sort_index
函数,其返回结果为一个新的排好序的对象。
1 | obj = pd.Series(range(4), index=['d', 'a', 'b', 'c']) |
a 1
b 2
c 3
d 0
dtype: int32
1 | frame = pd.DataFrame(np.arange(8).reshape((2, 4)),index=['three', 'one'],columns=['d', 'a', 'b', 'c']) |
1 | frame.sort_index() #缺省,按行排序 |
d | a | b | c | |
---|---|---|---|---|
one | 4 | 5 | 6 | 7 |
three | 0 | 1 | 2 | 3 |
1 | frame.sort_index(axis=1) #也可以使用axis=1参数按列进行排序 |
a | b | c | d | |
---|---|---|---|---|
three | 1 | 2 | 3 | 0 |
one | 5 | 6 | 7 | 4 |
1 | frame.sort_index(axis=1, ascending=False) #也可以降序排序 |
d | c | b | a | |
---|---|---|---|---|
three | 0 | 3 | 2 | 1 |
one | 4 | 7 | 6 | 5 |
对Series对象,可以使用sort_vlues对数值进行排序,而不是按照索引的顺序。
1 | obj = pd.Series([4, 7, -3, 2]) |
2 -3
3 2
0 4
1 7
dtype: int64
缺值的位置排到后面。
1 | obj = pd.Series([4, np.nan, 7, np.nan, -3, 2]) |
4 -3.0
5 2.0
0 4.0
2 7.0
1 NaN
3 NaN
dtype: float64
对DataFrame按值排序,可以指定一列或多列作为排序的关键字。
1 | frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]}) |
a | b | |
---|---|---|
0 | 0 | 4 |
1 | 1 | 7 |
2 | 0 | -3 |
3 | 1 | 2 |
1 | frame.sort_values(by='b') #b列作为排序关键字 |
a | b | |
---|---|---|
2 | 0 | -3 |
3 | 1 | 2 |
0 | 0 | 4 |
1 | 1 | 7 |
1 | frame.sort_values(by=['a', 'b']) #a列为主关键字,b列为次关键字 |
a | b | |
---|---|---|
2 | 0 | -3 |
0 | 0 | 4 |
3 | 1 | 2 |
1 | 1 | 7 |
Ranking排名
rank函数返回从小到大排序的下标,即给予每个数值排序后所在的位置和名次。对于平级的数,rank是通过“为各组分配一个平均排名”的方式破坏评级关系。
1 | obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) |
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64
对于平级的数,也可以不使用平均排名的办法,而是可以使用位置在前面的数的排名就靠前。
向下面的列子,对0和2这两个位置的数,虽然平级,但是给予位置0的数的评级为6.0,位置2的数的评级为7.0,而不是6.5,因为使用的首次相遇策略。
1 | obj.rank(method='first') |
0 6.0
1 1.0
2 7.0
3 4.0
4 3.0
5 2.0
6 5.0
dtype: float64
也可以降序排列,相同评级使用最大数。
1 | obj.rank(ascending=False, method='max') |
0 2.0
1 7.0
2 2.0
3 4.0
4 5.0
5 6.0
6 4.0
dtype: float64
数值相等的元素分组的评级计算方法:
方法 | 说明 |
---|---|
‘average’ | 缺省:对组内元素赋值平均值 |
‘min’ | 对分组内元素都使用最小值 |
‘max’ | 对分组内元素都是用最大值 |
‘first’ | 使用数值在数据中出现的顺序 |
‘dense’ | 与’min’类似,但是组间评级依次加1 |
1 | obj.rank(method='dense') #稠密模式,评级依次加1,中间无空值 |
0 5.0
1 1.0
2 5.0
3 4.0
4 3.0
5 2.0
6 4.0
dtype: float64
1 | obj.rank(method='min') #排名中间可能有空值,该例子没有5 |
0 6.0
1 1.0
2 6.0
3 4.0
4 3.0
5 2.0
6 4.0
dtype: float64
DataFrame的数值排名可以按行或列
1 | frame = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1],'c': [-2, 5, 8, -2.5]}) |
a | b | c | |
---|---|---|---|
0 | 0 | 4.3 | -2.0 |
1 | 1 | 7.0 | 5.0 |
2 | 0 | -3.0 | 8.0 |
3 | 1 | 2.0 | -2.5 |
1 | frame.rank(axis='columns') |
a | b | c | |
---|---|---|---|
0 | 2.0 | 3.0 | 1.0 |
1 | 1.0 | 3.0 | 2.0 |
2 | 2.0 | 1.0 | 3.0 |
3 | 2.0 | 3.0 | 1.0 |
八、重复标签的索引
上面的例子中,DataFrame的索引标签都是唯一的。很多pandas函数(如reindex)要求索引标签是唯一的,但这不是强制的。我们来看一个重复索引标签的Series的例子:
1 | obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c']) |
a 0
a 1
b 2
b 3
c 4
dtype: int32
index对象的is_unique属性可以告诉你索引标签是否是唯一的:
1 | obj.index.is_unique |
False
索引标签是否唯一影响数据选取的结果。如果索引标签对应多条数据,那么选取结果为Series对象,否则为一个标量。
1 | obj['a'] |
a 0
a 1
dtype: int32
1 | obj['c'] |
4
这样的结果会使代码变得复杂,因为根据索引标签是否唯一得到的结果可能不是一种类型。这对DataFrame也是一样的。
1 | df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b']) |
0 | 1 | 2 | |
---|---|---|---|
a | -0.290790 | -0.402699 | 1.277095 |
a | 0.785005 | 2.835915 | -0.318999 |
b | -0.141299 | -2.397378 | -0.010815 |
b | -1.472500 | 1.807394 | -2.828368 |
1 | df.loc['b'] |
0 | 1 | 2 | |
---|---|---|---|
b | -0.141299 | -2.397378 | -0.010815 |
b | -1.472500 | 1.807394 | -2.828368 |