算数运算和数据对齐
pandas中的一个功能是对不同索引的对象进行算数运算。在运算时,如果存在不同的索引对,那么结果就是它们的并集。
In [122]: s1 = Series([7.3, -2.5, 3.4, 1.5], index=['a','c','d','e'])
In [123]: s2 = Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a','c','e','f','g'])
In [124]: s1
Out[124]:
a 7.3
c -2.5
d 3.4
e 1.5
dtype: float64
In [125]: s2
Out[125]:
a -2.1
c 3.6
e -1.5
f 4.0
g 3.1
dtype: float64
In [126]: s1 + s2
Out[126]:
a 5.2
c 1.1
d NaN
e 0.0
f NaN
g NaN
dtype: float64
可以看到,不重叠的索引处因为数据对齐功能的缘故被引入了NaN
值。相当于s1
中的f、g
索引和s2
中的d
索引本身都为缺失值NaN
,由于n + NaN = NaN
的特性,所以才有了这样的结果。
同样在DataFrame
上也会是这种情况:
In [127]: df1 = DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'),index=['Ohio','Texas','Colorado'])
In [129]: df2 = DataFrame(np.arange(12.).reshape(4, 3), columns=list('bde'), index=['Utah','Ohio','Texas','Oregon'])
In [130]: df1
Out[130]:
b c d
Ohio 0.0 1.0 2.0
Texas 3.0 4.0 5.0
Colorado 6.0 7.0 8.0
In [131]: df2
Out[131]:
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
In [132]: df1 + df2
Out[132]:
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
如何解决这个问题?再看下面的例子:
在算数方法中填充值
pandas对运算设计了几个函数,通过这个函数我们可以预先设置好填充值来解决这个问题。
In [134]: df1.add(df2, fill_value=0)
Out[134]:
b c d e
Colorado 6.0 7.0 8.0 NaN
Ohio 3.0 1.0 6.0 5.0
Oregon 9.0 NaN 10.0 11.0
Texas 9.0 4.0 12.0 8.0
Utah 0.0 NaN 1.0 2.0
add
加法
sub
减法
div
除法
mul
乘法
DataFrame和Series之间的运算
计算二维数组和某行之差
In [135]: arr = np.arange(12).reshape((3,4))
In [136]: arr
Out[136]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [137]: arr[0]
Out[137]: array([0, 1, 2, 3])
In [138]: arr - arr[0]
Out[138]:
array([[0, 0, 0, 0],
[4, 4, 4, 4],
[8, 8, 8, 8]])
数组中的每一行都对该数组进行了运算,这个过程叫做广播。
再来看看DataFrame
和Series
之间的运算:
In [139]: frame = DataFrame(np.arange(12).reshape((4,3)), columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])
In [140]: series = frame.iloc[0]
In [141]: frame
Out[141]:
b d e
Utah 0 1 2
Ohio 3 4 5
Texas 6 7 8
Oregon 9 10 11
In [142]: series
Out[142]:
b 0
d 1
e 2
Name: Utah, dtype: int64
In [143]: frame - series
Out[143]:
b d e
Utah 0 0 0
Ohio 3 3 3
Texas 6 6 6
Oregon 9 9 9
DataFrame
与Series
的运算中匹配到了Utah
这行然后沿着行向下广播得到上面的答案。
如果想在列上广播,那首先想到的肯定是修改axis
选项啦
In [144]: series3 = frame['d']
In [145]: series3
Out[145]:
Utah 1
Ohio 4
Texas 7
Oregon 10
Name: d, dtype: int64
In [146]: frame.sub(series3, axis = 0)
Out[146]:
b d e
Utah -1 0 1
Ohio -1 0 1
Texas -1 0 1
Oregon -1 0 1
在这里我的理解是series3
匹配到了列,沿着列向右广播过去。
函数应用和映射
NumPy的很多方法也可用于操作pandas对象:
In [150]: frame = DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah','Ohio','Texas','Oregon'])
In [151]: frame
Out[151]:
b d e
Utah -0.708756 0.996288 -2.136221
Ohio -0.615091 -1.440153 -0.390829
Texas 0.467176 -0.000329 -3.147984
Oregon -0.107895 1.029447 -0.309974
In [152]: np.abs(frame)
Out[152]:
b d e
Utah 0.708756 0.996288 2.136221
Ohio 0.615091 1.440153 0.390829
Texas 0.467176 0.000329 3.147984
Oregon 0.107895 1.029447 0.309974
还有一种比较好玩的方法是,将函数应用到DataFrame
上。我们可以通过DataFrame
的apply
函数实现此功能:
In [153]: f = lambda x: x.max() - x.min()
In [154]: frame.apply(f)
Out[154]:
b 1.175931
d 2.469600
e 2.838010
dtype: float64
axis
默认为0,以列为目标执行f
函数。
当然反过来也是可以的:
In [155]: frame.apply(f, axis=1)
Out[155]:
Utah 3.132508
Ohio 1.049324
Texas 3.615160
Oregon 1.339421
dtype: float64
以行为目标执行f
函数。
元素级的Python函数也是可以用的,也就是将函数作用到每一个元素:
In [156]: format = lambda x: '%.2f' % x
In [157]: frame.applymap(format)
Out[157]:
b d e
Utah -0.71 1.00 -2.14
Ohio -0.62 -1.44 -0.39
Texas 0.47 -0.00 -3.15
Oregon -0.11 1.03 -0.31
将frame
中的数值转换成了浮点数。
相较于apply
其实有更简便的方式map
, map
函数更针对于单个元素(某列或者某行):
In [158]: frame['e'].map(format)
Out[158]:
Utah -2.14
Ohio -0.39
Texas -3.15
Oregon -0.31
Name: e, dtype: object
接下来会详细出一篇用来区分map
,apply
,applymap
之间的用法与区别的文章。
排序和排名
对行或列索引排序
- 对列进行排序从而将行索引排成了升序
In [169]: frame = DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d','a','b','c'])
In [171]: frame.sort_index()
Out[171]:
d a b c
one 4 5 6 7
three 0 1 2 3
- 对行进行排序从而将列索引排成了升序*
In [170]: frame.sort_index(axis=1)
Out[170]:
a b c d
three 1 2 3 0
one 5 6 7 4
也可以降序排序
In [173]: frame.sort_index(axis=1, ascending=False)
Out[173]:
d c b a
three 0 3 2 1
one 4 7 6 5
如果是想对数据进行排序
In [174]: obj = Series([4, 7, -3, 2])
In [176]: obj.sort_values()
Out[176]:
2 -3
3 2
0 4
1 7
dtype: int64
数据中如果有缺失值,在排序后会强制放到末尾
In [177]: obj = Series([4, np.nan, 7, np.nan, -3, 2])
In [178]: obj.sort_values()
Out[178]:
4 -3.0
5 2.0
0 4.0
2 7.0
1 NaN
3 NaN
dtype: float64
在DataFrame中,可以对一个或者多个列中的值进行排序
In [179]: frame = DataFrame({'b':[4, 7, -3, 2], 'a':[0, 1, 0, 1]})
In [181]: frame.sort_values(by='b')
Out[181]:
b a
2 -3 0
3 2 1
0 4 0
1 7 1
对多个列进行排序的话,优先还是按照数组中第一项来排,也就是下面这个例子中的b
In [182]: frame.sort_values(by=['b','a'])
Out[182]:
b a
2 -3 0
3 2 1
0 4 0
1 7 1
排名
排名和排序不同,排名会在不动索引的情况下对当前数据做一个排名。如果出现平级的情况就会分配一个平均排名。
In [183]: obj = Series([7, -5, 7, 4, 2, 0, 4])
In [184]: obj.rank()
Out[184]:
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64
也可以对排序完的数据按照顺序进行排名
In [186]: obj.rank(method='first')
Out[186]:
0 6.0
1 1.0
2 7.0
3 4.0
4 3.0
5 2.0
6 5.0
dtype: float64
一开始可能看不懂,其实这里应该要这么理解:
In [185]: obj.sort_values()
Out[185]:
1 -5 #1
5 0 #2
4 2 #3
3 4 #4
6 4 #5
0 7 #6
2 7 #7
dtype: int64
下表列出了常用的method
选项
average 默认: 在相等分组中,为各个值分配平均排名
min: 按从小到大进行排名
max: 按从大到小进行排名
first: 按默认排序后的出现顺序进行排名
网友评论