第五章
5.2.4整数索引
虽然我们可以使用整数索引对pandas对象执行索引,但是有时候会产生歧义,为了统一,最好使用loc
和iloc
对pandas对象进行索引。
要注意的是用于标签的loc
与用于整数的iloc
在处理整数索引值的时候是不一样的,loc
会带着尾部的值。
>>>ser = pd.Series(np.arange(3.))
>>>ser
0 0.0
1 1.0
2 2.0
dtype: float64
>>>ser.loc[:1]
0 0.0
1 1.0
dtype: float64
>>>ser.iloc[:1]
0 0.0
dtype: float64
5.2.5算术和数据对齐
不同索引的对象之间可以进行算术行为,如果两个想加的对象之间存在不同的索引对,则返回的索引将是索引对的并集。
对Series对象来说,没有交叠的标签位置上,内部数据对齐会产生缺失值。
>>>s1 = pd.Series(np.random.randn(3), index=['a', 'b', 'c'])
>>>s1
a -0.100878
b 2.362527
c 0.573888
dtype: float64
>>>s2 = pd.Series(np.random.randn(4), index=['a', 'c', 'e', 'f'])
>>>s2
a -1.208521
c -0.626216
e -0.458916
f 0.044199
dtype: float64
>>>s1 + s2
a -1.309399
b NaN
c -0.052328
e NaN
f NaN
dtype: float64
对于DataFrame来说,在行和列上都会执行补齐,返回的DataFrame是每个DataFrame的索引和列的并集,并由缺失值补充维重叠的部分。
>>>df1 = pd.DataFrame(np.arange(9.).reshape((3,3)), index=['cat', 'dog', 'lion'], columns=list('bcd'))
>>>df2 = pd.DataFrame(np.arange(12.).reshape((4,3)), index=['seal', 'dog', 'cat', 'pandas'], columns=list('bde'))
>
>>>df1
b c d
cat 0.0 1.0 2.0
dog 3.0 4.0 5.0
lion 6.0 7.0 8.0
>>>df2
b d e
seal 0.0 1.0 2.0
dog 3.0 4.0 5.0
cat 6.0 7.0 8.0
pandas 9.0 10.0 11.0
>>>df3 = df1 + df2
>>>df3
b c d e
cat 6.0 NaN 9.0 NaN
dog 6.0 NaN 9.0 NaN
lion NaN NaN NaN NaN
pandas NaN NaN NaN NaN
seal NaN NaN NaN NaN
如果将两个行和列完全不同的DataFrame对象想加,结果将全部为空。
5.2.5.1使用填充值的算术方法
当轴标签在一个对象中存在而在另一个对象中不存在时,add
方法的fill_value
允许我们将缺失值填充为我们希望的其他值,这并不是将执行算术操作后的新对象中的缺失值填充为其他值,而是在另一个对象中不存在轴标签下填充值。
>>>df1.add(df2)
b c d e
cat 6.0 NaN 9.0 NaN
dog 6.0 NaN 9.0 NaN
lion NaN NaN NaN NaN
pandas NaN NaN NaN NaN
seal NaN NaN NaN NaN
#新对象中的index是以df1为准的
>>>df1.add(df2, fill_value=0)
b c d e
cat 6.0 1.0 9.0 8.0
dog 6.0 4.0 9.0 5.0
lion 6.0 7.0 8.0 NaN
常用的灵活算术方法, r代表翻转,例如除以div
与被除以rdiv
。
方法 | 描述 |
---|---|
add, radd | 加法 + |
sub, rsub | 减法 - |
div, rdiv | 除法 / |
floordiv, rfloordiv | 整除 // |
mul, rmul | 乘法 * |
pow, rpow | 幂次方 ** |
5.2.5.2 DataFrame和Series间的操作
>>>arr = np.arange(12.).reshape((3,4))
>>>arr - arr[0]
array([[0., 0., 0., 0.],
[4., 4., 4., 4.],
[8., 8., 8., 8.]])
>>>arr + arr[0]
array([[ 0., 2., 4., 6.],
[ 4., 6., 8., 10.],
[ 8., 10., 12., 14.]])
在array数组中,当我们从arr中删去arr[1]时,减法在每一行都进行了操作,这也称为广播
。同理,加法的时候也是一样的。所以要注意这里的减法操作不是删除行。
在Series和DataFrame中与此是类似的。默认情况下,Series和DataFrame中的数学操作会将Series的索引和DataFrame列进行匹配,并广播到各行。
>>>frame1 = pd.DataFrame(np.arange(9.).reshape((3,3)), index=['cat', 'dog', 'lion'], columns=list('bcd'))
>>>frame1
b c d
cat 0.0 1.0 2.0
dog 3.0 4.0 5.0
lion 6.0 7.0 8.0
>>>series1 = frame1.loc['cat']
>>>series1
b 0.0
c 1.0
d 2.0
Name: cat, dtype: float64
>>>frame1 - series1
b c d
cat 0.0 0.0 0.0
dog 3.0 3.0 3.0
lion 6.0 6.0 6.0
那我们如果想要在行上进行匹配,在列上进行广播呢?这时候需要设置axis='index'
。
>>>series2 = frame1.loc[:,'b']
>>>series2
cat 0.0
dog 3.0
lion 6.0
Name: b, dtype: float64
>>>frame1.sub(series2, axis='index')
b c d
cat 0.0 1.0 2.0
dog 0.0 1.0 2.0
lion 0.0 1.0 2.0
5.2.6函数应用和映射
NumPy的通用函数(逐元素的方法)对pandas对象也有效:
>>>frame2 = pd.DataFrame(np.arange(12.).reshape((4,3)), index=['seal', 'dog', 'cat', 'pandas'], columns=list('bde'))
>>>frame2
b d e
seal 0.0 1.0 2.0
dog 3.0 4.0 5.0
cat 6.0 7.0 8.0
pandas 9.0 10.0 11.0
>>>np.sum(frame2)
b 18.0
d 22.0
e 26.0
dtype: float64
>>>np.mean(frame2, axis=1)
seal 1.0
dog 4.0
cat 7.0
pandas 10.0
dtype: float64
此外,在DataFrame还有将函数应用到一行或者一列的一维数组上的apply
函数,默认情况下是在0
轴上进行的,可以设置axis=1
来在行上进行操作。
>>>f = lambda x: x.max() - x.min()
>>>frame2.apply(f)
b 9.0
d 9.0
e 9.0
dtype: float64
还有可以将函数用于逐元素
的applymap
函数:
>>>f1 = lambda x: x**2
>>>frame2.applymap(f1)
b d e
seal 0.0 1.0 4.0
dog 9.0 16.0 25.0
cat 36.0 49.0 64.0
pandas 81.0 100.0 121.0
上面的函数使用的applymap
的命名,这是因为map
在这里指将一个逐元素函数应用到Series上:
>>>frame2.loc['pandas'].map(f1)
b 81.0
d 100.0
e 121.0
Name: pandas, dtype: float64
>>>frame2.loc[:, 'e'].map(f1)
seal 4.0
dog 25.0
cat 64.0
pandas 121.0
Name: e, dtype: float64
5.2.7 排序和排名
这里的排序分为两种:一种是按行或者索引进行的排序,使用sort_index()
方法;另一种是对对象中的值进行排序,使用的是sort_values()
方法。默认的排序是升序的,使用ascending=False
获得降序。
Series中的排序:
>>>obj = pd.Series(np.random.randn(4), index=['b', 'd', 'c', 'a'])
>>>obj
b -2.441784
d -1.353572
c -0.578262
a 0.524475
dtype: float64
>>>obj.sort_index()
a 0.524475
b -2.441784
c -0.578262
d -1.353572
dtype: float64
>>>obj.sort_values(ascending=False)
a 0.524475
c -0.578262
d -1.353572
b -2.441784
dtype: float64
DataFrame中的排序,使用by
关键字来对特定的列进行值排序,当要对多个列进行排序时,为by
传入列名的列表即可,当前一列出现重复时,会在重复的地方继续排序。
>>>frame1 = pd.DataFrame(np.random.randn(8).reshape(4, 2), index=list('bcda'), columns=['three', 'one'])
>>>frame1
three one
b -1.890790 -1.932137
c -0.909324 0.572570
d 0.440387 -0.774289
a -0.167510 2.033475
>>>frame1.sort_index()
three one
a -0.167510 2.033475
b -1.890790 -1.932137
c -0.909324 0.572570
d 0.440387 -0.774289
#在three列中存在重复元素时,重复的地方会按one列进行排序
>>>frame1.sort_values(by=['three', 'one'])
three one
b -1.890790 -1.932137
c -0.909324 0.572570
a -0.167510 2.033475
d 0.440387 -0.774289
排名(rank) 是指对数组从1到有效数据点分配名词的操作。
它跟numpy.argsort
产生的间接排下索引差不多, 只不过它可以根据某种规则破坏平级关系,默认情况下通过将平均排名
分配到每个组来打破平级关系。使用ascending=False
获得降序。
>>>obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
>>>obj.rank()
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64
上面有的值仍有相同的排名,通过传入参数method='first'
,来按观测到的顺序
排名,对于相同的值,会按标签的顺序决定其先后位次。
>>>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
在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
#默认在0轴方向上,按列排名
>>>frame.rank(method='first')
b a c
0 3.0 1.0 2.0
1 4.0 3.0 3.0
2 1.0 2.0 4.0
3 2.0 4.0 1.0
#在1轴方向上,按行排名
>>>frame.rank(method='first', 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
排名中平级关系打破的方法
方法 | 描述 |
---|---|
‘average’ | 默认在每个组中分配平均排名 |
‘min’ | 对整个组使用最小排名 |
‘max’ | 对整个组使用最大排名 |
‘first’ | 按照值在数据中出现的次序排名 |
‘dense’ | 类似于min,但组间排名总是增加1,而不是一个组中相等的元素数量 |