Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理

Pandas 系列文章:


专栏:

推荐学习资料与网站:


这里是一段防爬虫文本,请读者忽略。
本文原创首发于 CSDN,作者 TRHX。
博客首页:https://itrhx.blog.csdn.net/
本文链接:https://itrhx.blog.csdn.net/article/details/106743778
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!

【01x00】Pandas 算术运算

Pandas 继承了 NumPy 的功能,NumPy 的基本能力之一是快速对每个元素进行运算,既包括基本算术运算(加、减、乘、除),也包括更复杂的运算(三角函数、指数函数和对数函数等)。具体可以参考 NumPy 系列文章。

【01x01】使用 NumPy 通用函数

因为 Pandas 是建立在 NumPy 基础之上的,所以 NumPy 的通用函数同样适用于 Pandas 的 Series 和 DataFrame 对象,如下所示:

>>> import pandas as pd
>>> import numpy as np
>>> rng = np.random.RandomState(42)
>>> ser = pd.Series(rng.randint(0, 10, 4))
>>> ser
0    6
1    3
2    7
3    4
dtype: int32
>>> 
>>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])
>>> obj
   A  B  C  D
0  6  9  2  6
1  7  4  3  7
2  7  2  5  4

使用 NumPy 通用函数,生成的结果是另一个保留索引的 Pandas 对象:

>>> import pandas as pd
>>> import numpy as np
>>> rng = np.random.RandomState(42)
>>> ser = pd.Series(rng.randint(0, 10, 4))
>>> ser
0    6
1    3
2    7
3    4
dtype: int32
>>> 
>>> np.exp(ser)
0     403.428793
1      20.085537
2    1096.633158
3      54.598150
dtype: float64
>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])
>>> np.sin(obj * np.pi / 4)
          A             B         C             D
0 -1.000000  7.071068e-01  1.000000 -1.000000e+00
1 -0.707107  1.224647e-16  0.707107 -7.071068e-01
2 -0.707107  1.000000e+00 -0.707107  1.224647e-16

【01x02】数据对齐

Pandas 最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。自动的数据对齐操作会在不重叠的索引处引入缺失值,即 NaN,缺失值会在算术运算过程中传播。

Series 对象的数据对齐操作:

>>> import pandas as pd
>>> obj1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
>>> obj2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
>>> obj1
a    7.3
c   -2.5
d    3.4
e    1.5
dtype: float64
>>> 
>>> obj2
a   -2.1
c    3.6
e   -1.5
f    4.0
g    3.1
dtype: float64
>>>
>>> obj1 + obj2
a    5.2
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64

DataFrame 对象的数据对齐操作会同时发生在行和列上:

>>> import pandas as pd
>>> obj1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
>>> obj2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
>>> obj1
            b    c    d
Ohio      0.0  1.0  2.0
Texas     3.0  4.0  5.0
Colorado  6.0  7.0  8.0
>>> 
>>> obj2
          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
>>> 
>>> obj1 + obj2
            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

【01x03】DataFrame 与 Series 之间的运算

首先回忆 NumPy 中的广播(参见:《Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割》),跟不同维度的 NumPy 数组一样,DataFrame 和 Series 之间算术运算也是有明确规定的。首先回忆一下 NumPy 中不同维度的数组之间的运算:

>>> import numpy as np
>>> 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.]])

可以看到每一行都进行了减法运算,这正是 NumPy 中的广播,而 DataFrame 与 Series 之间的运算也类似,默认情况下,DataFrame 和 Series 之间的算术运算会将 Series 的索引匹配到 DataFrame 的列,然后沿着行一直向下广播:

>>> import numpy as np
>>> import pandas as pd
>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])
>>> frame
      b     d     e
AA  0.0   1.0   2.0
BB  3.0   4.0   5.0
CC  6.0   7.0   8.0
DD  9.0  10.0  11.0
>>> 
>>> series = frame.iloc[0]
>>> series
b    0.0
d    1.0
e    2.0
Name: AA, dtype: float64
>>> 
>>> frame - series
      b    d    e
AA  0.0  0.0  0.0
BB  3.0  3.0  3.0
CC  6.0  6.0  6.0
DD  9.0  9.0  9.0

如果某个索引值在 DataFrame 的列或 Series 的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集:

>>> import numpy as np
>>> import pandas as pd
>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])
>>> frame
      b     d     e
AA  0.0   1.0   2.0
BB  3.0   4.0   5.0
CC  6.0   7.0   8.0
DD  9.0  10.0  11.0
>>> 
>>> series = pd.Series(range(3), index=['b', 'e', 'f'])
>>> series
b    0
e    1
f    2
dtype: int64
>>> 
>>> frame + series
      b   d     e   f
AA  0.0 NaN   3.0 NaN
BB  3.0 NaN   6.0 NaN
CC  6.0 NaN   9.0 NaN
DD  9.0 NaN  12.0 NaN

如果希望匹配行且在列上广播,则必须使用算术运算方法,在方法中传入的轴(axis)就是希望匹配的轴。在下例中,我们的目的是匹配 DataFrame 的行索引(axis=’index’ or axis=0)并进行广播:

>>> import numpy as np
>>> import pandas as pd
>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])
>>> frame
      b     d     e
AA  0.0   1.0   2.0
BB  3.0   4.0   5.0
CC  6.0   7.0   8.0
DD  9.0  10.0  11.0
>>> 
>>> series = frame['d']
>>> series
AA     1.0
BB     4.0
CC     7.0
DD    10.0
Name: d, dtype: float64
>>> 
>>> frame.sub(series, axis='index')
      b    d    e
AA -1.0  0.0  1.0
BB -1.0  0.0  1.0
CC -1.0  0.0  1.0
DD -1.0  0.0  1.0

【01x04】Pandas 算术方法

完整的 Pandas 算术方法见下表:

方法 副本 描述
add() radd() 加法(+)
sub()、subtract() rsub() 减法(-)
mul()、multiply() rmul() 乘法(*)
pow() rpow() 指数(**)
truediv()、div()、divide() rdiv() 除法(/)
floordiv() rfloordiv() 底除(//)
mod() rmod() 求余(%)

副本均为原方法前加了个 r,它会翻转参数:

>>> import pandas as pd
>>> obj = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))
>>> obj
     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 / obj
       a         b         c         d
0    inf  1.000000  0.500000  0.333333
1  0.250  0.200000  0.166667  0.142857
2  0.125  0.111111  0.100000  0.090909
>>> 
>>> obj.rdiv(1)
       a         b         c         d
0    inf  1.000000  0.500000  0.333333
1  0.250  0.200000  0.166667  0.142857
2  0.125  0.111111  0.100000  0.090909

这里是一段防爬虫文本,请读者忽略。
本文原创首发于 CSDN,作者 TRHX。
博客首页:https://itrhx.blog.csdn.net/
本文链接:https://itrhx.blog.csdn.net/article/details/106743778
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!

【02x00】处理缺失值

在现实中遇到的数据很少是干净整齐的,许多数据集都会有数据缺失的现象,缺失值主要有三种形式:null、NaN(NAN,nan) 或 NA。

【02x01】fill_value() 指定值与缺失值进行运算

使用 add, sub, div, mul 等算术方法时,通过 fill_value 指定填充值,未对齐的数据将和填充值做运算。

Series 中的应用:

>>> import pandas as pd
>>> obj1 = pd.Series([1, 2, 3, 4, 5])
>>> obj2 = pd.Series([6, 7])
>>> 
>>> obj1
0    1
1    2
2    3
3    4
4    5
dtype: int64
>>> 
>>> obj2
0    6
1    7
dtype: int64
>>> 
>>> obj1.add(obj2)
0    7.0
1    9.0
2    NaN
3    NaN
4    NaN
dtype: float64
>>> 
>>> obj1.add(obj2, fill_value=-1)
0    7.0
1    9.0
2    2.0
3    3.0
4    4.0
dtype: float64

DataFrame 中的应用:

>>> import pandas as pd
>>> import numpy as np
>>> obj1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))
>>> obj2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))
>>> 
>>> obj2.loc[1, 'b'] = np.nan
>>> 
>>> obj1
     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
>>> 
>>> obj2
      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
>>> 
>>> obj1 + obj2
      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
>>> 
>>> obj1.add(obj2, fill_value=10)
      a     b     c     d     e
0   0.0   2.0   4.0   6.0  14.0
1   9.0  15.0  13.0  15.0  19.0
2  18.0  20.0  22.0  24.0  24.0
3  25.0  26.0  27.0  28.0  29.0

【02x02】isnull() / notnull() 判断缺失值

isnull():为缺失值时为 True,否则为 False

notnull() 为缺失值时为 False,否则为 True

>>> import numpy as np
>>> import pandas as pd
>>> obj = pd.Series([1, np.nan, 'hello', None])
>>> obj
0        1
1      NaN
2    hello
3     None
dtype: object
>>> 
>>> obj.isnull()
0    False
1     True
2    False
3     True
dtype: bool
>>> 
>>> obj.notnull()
0     True
1    False
2     True
3    False
dtype: bool

【02x03】dropna() 删除缺失值

dropna() 方法用于返回一个删除了缺失值的新 Series 或 DataFrame 对象。

在 Series 对象当中,dropna() 方法的语法如下(其他参数用法可参考在 DataFrame 中的应用):

Series.dropna(self, axis=0, inplace=False, how=None)

官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.dropna.html

>>> import numpy as np
>>> import pandas as pd
>>> obj = pd.Series([1, np.nan, 'hello', None])
>>> obj
0        1
1      NaN
2    hello
3     None
dtype: object
>>> 
>>> obj.dropna()
0        1
2    hello
dtype: object

在 DataFrame 对象中,dropna() 方法的语法如下:

DataFrame.dropna(self, axis=0, how='any', thresh=None, subset=None, inplace=False)

官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html

参数 描述
axis 确定是否删除包含缺失值的行或列
0'index':删除包含缺失值的行。1'columns':删除包含缺失值的列
how 'any':如果存在任何NA值,则删除该行或列。'all':如果所有值都是NA,则删除该行或列
thresh 设置行或列中非缺失值的最小数量

不传递任何参数,将会删除任何包含缺失值的整行数据:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])
>>> obj
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6
>>> 
>>> obj.dropna()
     0    1  2
1  2.0  3.0  5

指定 axis 参数,删除包含缺失值的行或列:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])
>>> obj
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6
>>> 
>>> obj.dropna(axis='columns')
   2
0  2
1  5
2  6

指定 how 参数,'any':如果存在任何NA值,则删除该行或列。'all':如果所有值都是NA,则删除该行或列:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])
>>> obj
     0    1  2   3
0  1.0  NaN  2 NaN
1  2.0  3.0  5 NaN
2  NaN  4.0  6 NaN
>>> obj.dropna(axis='columns', how='all')
     0    1  2
0  1.0  NaN  2
1  2.0  3.0  5
2  NaN  4.0  6

指定 thresh 参数,设置行或列中非缺失值的最小数量,以下示例中,第一行和第三行只有两个非缺失值,所以会被删除:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])
>>> obj
     0    1  2   3
0  1.0  NaN  2 NaN
1  2.0  3.0  5 NaN
2  NaN  4.0  6 NaN
>>>
>>> obj.dropna(axis='rows', thresh=3)
     0    1  2   3
1  2.0  3.0  5 NaN

【02x04】fillna() 填充缺失值

fillna() 方法可以将缺失值替换成有效的数值。

在 Series 对象中,fillna() 方法的语法如下:

Series.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)

官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.fillna.html

参数 描述
value 用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值
指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值
不在dict / Series / DataFrame中的值将不被填充。此值不能是列表
method 填充方法:None
‘pad’ / ‘ffill’:将上一个有效观测值向前传播到下一个有效观测值
‘backfill’ / ‘bfill’:使用下一个有效观察值来填补空白
axis 0 or ‘index’,要填充缺失值的轴
>>> import pandas as pd
>>> obj = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
>>> obj
a    1.0
b    NaN
c    2.0
d    NaN
e    3.0
dtype: float64
>>> 
>>> obj.fillna(0)
a    1.0
b    0.0
c    2.0
d    0.0
e    3.0
dtype: float64
>>> 
>>> obj.fillna(method='ffill')
a    1.0
b    1.0
c    2.0
d    2.0
e    3.0
dtype: float64
>>> 
>>> obj.fillna(method='bfill')
a    1.0
b    2.0
c    2.0
d    3.0
e    3.0
dtype: float64

在 DataFrame 对象中,fillna() 方法的语法如下:

DataFrame.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)

官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.fillna.html

参数 描述
value 用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值
指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值
不在dict / Series / DataFrame中的值将不被填充。此值不能是列表
method 填充方法:None
‘pad’ / ‘ffill’:将上一个有效观测值向前传播到下一个有效观测值
‘backfill’ / ‘bfill’:使用下一个有效观察值来填补空白
axis 0 or ‘index’1 or ‘columns’,要填充缺失值的轴

在 DataFrame 对象中的用法和在 Series 对象中的用法大同小异,只不过 axis 参数多了一个选择:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])
>>> obj
     0    1  2   3
0  1.0  NaN  2 NaN
1  2.0  3.0  5 NaN
2  NaN  4.0  6 NaN
>>> 
>>> obj.fillna(method='ffill', axis=1)
     0    1    2    3
0  1.0  1.0  2.0  2.0
1  2.0  3.0  5.0  5.0
2  NaN  4.0  6.0  6.0

这里是一段防爬虫文本,请读者忽略。
本文原创首发于 CSDN,作者 TRHX。
博客首页:https://itrhx.blog.csdn.net/
本文链接:https://itrhx.blog.csdn.net/article/details/106743778
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!

本文链接:https://www.itbob.cn/article/027/
本站所有原创文章采用 CC BY-NC-ND 4.0 许可协议进行许可!