文章目录
Pandas数值运算方法
Numpy相比于Python内置列表实现了元素的快速运算,在此基础上,Pandas实现了Numpy数组的显式索引
基于Pandas的显式索引给予了我们强大的数据选择能力
而Pandas是基于Numpy实现的,因此Pandas还实现了数组运算的索引保留和对齐.
对于一元运算,运算结果将保留索引和列标签,对于二元运算将会自动对齐索引
通用函数:保留索引
我们对Pandas的Series和DataFrame对象使用通用函数来进行计算(因为只有Series和DataFrame对象会储存数据)时候,Pandas会自动的保留原有的索引
例如:
array_1=np.random.randint(0,10,5)
array_2=np.random.randint(0,10,15).reshape(5,3)
Series_1=pd.Series(array_1,index=list('abcde'))
DataFrame_1=pd.DataFrame(array_2,columns=list('123'),index=list('abcde'))
print(Series_1)
print('')
print(Series_1**2)
print('\n\n')
print(DataFrame_1)
print('')
print(DataFrame_1**2)
>>>
a 1
b 0
c 6
d 3
e 2
dtype: int64
a 1
b 0
c 36
d 9
e 4
dtype: int64
1 2 3
a 6 6 5
b 3 6 9
c 7 2 6
d 0 9 0
e 8 2 3
1 2 3
a 36 36 25
b 9 36 81
c 49 4 36
d 0 81 0
e 64 4 9
通用函数:索引对齐
Series对象的索引对齐
当我们使用通用函数来对两个或多个Series,DataFrame对象进行运算时,Pandas会自动对齐索引来进行计算
array_1=np.random.randint(0,10,5)
array_2=np.random.randint(0,10,5)
Series_1=pd.Series(array_1,index=list('abcde'))
Series_2=pd.Series(array_2,index=list('edcba'))
print(Series_1)
print(Series_2)
print(Series_1+Series_2)
>>>
a 4
b 5
c 4
d 9
e 2
dtype: int64
e 4
d 0
c 5
b 3
a 5
dtype: int64
a 9
b 8
c 9
d 9
e 6
dtype: int64
注意,如果两个Series具有不同的索引,结果将会如下
array_1=np.random.randint(0,10,5)
array_2=np.random.randint(0,10,5)
Series_1=pd.Series(array_1,index=list('abcde'))
Series_2=pd.Series(array_2,index=list('fdcba'))
print(Series_1)
print(Series_2)
print(Series_1+Series_2)
>>>
a 2
b 1
c 7
d 1
e 6
dtype: int64
f 0
d 4
c 0
b 5
a 9
dtype: int64
a 11.0
b 6.0
c 7.0
d 5.0
e NaN
f NaN
dtype: float64
即参与运算的Series对象所不共有的Index会以NaN(Not a Number)填充
具体运算过程是首先将参与运算的所有Series对象或扩展至具有所有的Index,原Series对象不具有的Index扩充后其值会以NaN填充,所有的数值与NaN运算都是NaN,最后返回一个具有所有Index的Series对象
Series对象的索引对齐是通过Python内置的集合运算规则来实现的
为了避免NaN的污染效果,我们可以使用完整的通用函数,并且指定fill参数来填充NaN
array_1=np.random.randint(0,10,5)
array_2=np.random.randint(0,10,5)
Series_1=pd.Series(array_1,index=list('abcde'))
Series_2=pd.Series(array_2,index=list('fdcba'))
print(Series_1)
print(Series_2)
print(Series_1.add(Series_2,fill_value=0))
>>>
a 9
b 0
c 2
d 1
e 4
dtype: int64
f 3
d 5
c 1
b 6
a 1
dtype: int64
a 10.0
b 6.0
c 3.0
d 6.0
e 4.0
f 3.0
dtype: float64
除此以外,我们还可以找出NaN的位置,然后使用Numpy花哨的索引来让所有的NaN置为0,具体如何处理将在后面讲解
DataFrame对象的索引对齐
与Series对象类似,DataFrame对象的索引对齐几乎一样
array_1=np.random.randint(0,10,(3,4))
array_2=np.random.randint(0,10,(3,4))
DataFrame_1=pd.DataFrame(array_1,columns=list('abcd'),index=list('abc'))
DataFrame_2=pd.DataFrame(array_2,columns=list('abcd'),index=list('cba'))
print(DataFrame_1)
print('')
print(DataFrame_2)
print('')
print(DataFrame_1.add(DataFrame_2))
>>>
a b c d
a 9 8 3 5
b 2 2 4 1
c 2 4 9 8
a b c d
c 0 0 1 7
b 8 4 0 5
a 6 6 5 3
a b c d
a 15 14 8 8
b 10 6 4 6
c 2 4 10 15
对于缺失的行或者列,都会以NaN填充
array_1=np.random.randint(0,10,(3,4))
array_2=np.random.randint(0,10,(3,4))
array_3=np.random.randint(0,10,(3,4))
DataFrame_1=pd.DataFrame(array_1,columns=list('abcd'),index=list('abc'))
DataFrame_2=pd.DataFrame(array_2,columns=list('abcd'),index=list('abd'))
DataFrame_3=pd.DataFrame(array_3,columns=list('abce'),index=list('abc'))
print(DataFrame_1)
print('')
print(DataFrame_2)
print('')
print(DataFrame_3)
print('')
print(DataFrame_1.add(DataFrame_2))
print('')
print(DataFrame_1.add(DataFrame_3))
>>>
a b c d
a 1 4 4 2
b 5 0 5 8
c 4 1 4 3
a b c d
a 8 6 4 4
b 2 6 5 4
d 5 6 0 5
a b c e
a 3 1 9 0
b 1 9 8 4
c 4 4 6 4
a b c d
a 9.0 10.0 8.0 6.0
b 7.0 6.0 10.0 12.0
c NaN NaN NaN NaN
d NaN NaN NaN NaN
a b c d e
a 4 5 13 NaN NaN
b 6 9 13 NaN NaN
c 8 5 10 NaN NaN
同样我们可以调用DataFrame对象内置的add通用函数,调用fill_value属性来避免NaN的污染
array_1=np.random.randint(0,10,(3,4))
array_2=np.random.randint(0,10,(3,4))
array_3=np.random.randint(0,10,(3,4))
DataFrame_1=pd.DataFrame(array_1,columns=list('abcd'),index=list('abc'))
DataFrame_2=pd.DataFrame(array_2,columns=list('abcd'),index=list('abd'))
DataFrame_3=pd.DataFrame(array_3,columns=list('abce'),index=list('abc'))
print(DataFrame_1)
print('')
print(DataFrame_2)
print('')
print(DataFrame_3)
print('')
print(DataFrame_1.add(DataFrame_2,fill_value=0))
print('')
print(DataFrame_1.add(DataFrame_3,fill_value=0))
>>>
a b c d
a 0 3 9 0
b 3 0 9 5
c 0 0 6 9
a b c d
a 4 2 0 0
b 9 5 4 5
d 5 7 8 7
a b c e
a 5 3 1 3
b 2 0 1 6
c 3 0 3 8
a b c d
a 4.0 5.0 9.0 0.0
b 12.0 5.0 13.0 10.0
c 0.0 0.0 6.0 9.0
d 5.0 7.0 8.0 7.0
a b c d e
a 5 6 10 0.0 3.0
b 5 0 10 5.0 6.0
c 3 0 9 9.0 8.0
DataFrame对象与Series对象的索引对齐
同为Series或者同为DataFrame对象之间,索引无法对齐时,将会以NaN填充,但是DataFrame对象与Series对象进行运算时,却会以类似一维数组与二维数组进行广播
但是需要注意的,DataFrame对象与Series对象的索引对齐是按照列索引来进行对齐的
array_1=np.random.randint(0,10,(3,4))
array_2=np.random.randint(0,10,3)
array_3=np.random.randint(0,10,3)
DataFrame_1=pd.DataFrame(array_1,columns=list('abcd'),index=list('123'))
Series_1=pd.Series(array_2,index=list('123'))
Series_2=pd.Series(array_3,index=list('abc'))
print(DataFrame_1)
print(Series_1)
print(Series_2)
print(DataFrame_1-Series_1)
print(DataFrame_1-Series_2)
>>>
a b c d
1 0 6 9 0
2 4 2 6 4
3 0 6 2 8
1 3
2 4
3 2
dtype: int64
a 4
b 3
c 7
dtype: int64
1 2 3 a b c d
1 NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN
a b c d
1 -4.0 3.0 2.0 NaN
2 0.0 -1.0 -1.0 NaN
3 -4.0 3.0 -5.0 NaN
我们如果需要对DataFrame对象的某一行列进行运算,直接使用values属性对底层数组进行操作
注意需要对Series的底层数组升维之后进行操作
array_1=np.random.randint(0,10,(3,4))
array_2=np.random.randint(0,10,3)
DataFrame_1=pd.DataFrame(array_1,columns=list('abcd'),index=list('123'))
Series_1=pd.Series(array_2,index=list('123'))
print(DataFrame_1)
print('')
print(Series_1)
print(DataFrame_1.values-Series_1.values[:,np.newaxis])
>>>
a b c d
1 4 5 5 8
2 6 4 5 8
3 1 1 9 9
1 4
2 6
3 0
dtype: int64
[[ 0 1 1 4]
[ 0 -2 -1 2]
[ 1 1 9 9]]
注意,这里由于Series_1只有三个数字,因此想要能够成功广播就需要将其升维为(3,1)才能够横向广播
Pandas对象的方法
上面介绍了DataFrame对象和Series对象运算时索引对齐和索引保留
下面将介绍Python和Pandas中的方法的运算
Python运算符 | Pandas方法 |
---|---|
+ | add() |
- | sub(),subtract() |
* | mul(),multiply() |
/ | truediv(),div(),divide() |
// | follrdiv() |
% | mod() |
** | pow() |