• 53_Pandas中的条件替换值(where, mask)


    53_Pandas中的条件替换值(where, mask)

    我会解释如何在pandas中根据条件赋值。虽然它不使用 if 语句,但它可以处理条件分支,如 if then … 或 if then … else …。

    具体值的替换见后面的文章,替换或删除缺失值NaN。

    以下面的 pandas.DataFrame 为例。

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame({'A': [-20, -10, 0, 10, 20],
                       'B': [1, 2, 3, 4, 5],
                       'C': ['a', 'b', 'b', 'b', 'a']})
    
    print(df)
    #     A  B  C
    # 0 -20  1  a
    # 1 -10  2  b
    # 2   0  3  b
    # 3  10  4  b
    # 4  20  5  a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    以下内容进行说明。

    • 带有 loc、iloc 的布尔索引引用
    • pandas.DataFrame, Series 的 where() 方法
      • False元素可以改变,True元素保持不变
    • pandas.DataFrame, Series 的 mask() 方法
      • True元素可以改变,False元素不变
    • NumPy where() 函数
      • True 和 False 元素都可以更改

    带有 loc、iloc 的布尔索引引用

    可以通过如下编写来根据条件替换标量值。

    df.loc[df['A'] < 0, 'A'] = -100
    df.loc[~(df['A'] < 0), 'A'] = 100
    print(df)
    #      A  B  C
    # 0 -100  1  a
    # 1 -100  2  b
    # 2  100  3  b
    # 3  100  4  b
    # 4  100  5  a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果对 pandas.DataFrame 或 pandas.DataFrame的列(= pandas.Series)进行比较操作,将得到一个 bool 类型的 pandas.DataFrame 或 pandas.Series。

    一个例子是处理 pandas.DataFrame (= pandas.Series) 的列。 ~ 是否定运算符。

    print(df['A'] < 0)
    # 0     True
    # 1     True
    # 2    False
    # 3    False
    # 4    False
    # Name: A, dtype: bool
    
    print(~(df['A'] < 0))
    # 0    False
    # 1    False
    # 2     True
    # 3     True
    # 4     True
    # Name: A, dtype: bool
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用 bool 类型 pandas.Series 作为 loc 或 iloc 行规范将只选择 True 行。 loc由行名和列名指定,iloc由行号和列号指定。

    print(df.loc[df['A'] < 0, 'A'])
    # 0   -100
    # 1   -100
    # Name: A, dtype: int64
    
    • 1
    • 2
    • 3
    • 4

    带有loc和iloc的引用不仅可以用来取值,还可以用来赋值。 bool type pandas.Series 为 True 的行(满足条件的行)和指定的列元素更改为右侧的标量值。

    df.loc[df['A'] < 0, 'A'] = -10
    print(df)
    #      A  B  C
    # 0  -10  1  a
    # 1  -10  2  b
    # 2  100  3  b
    # 3  100  4  b
    # 4  100  5  a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    也可以指定 pandas.Series、列表或数组而不是标量值。相应的行值被替换。

    df.loc[~(df['A'] < 0), 'A'] = df['B']
    print(df)
    #     A  B  C
    # 0 -10  1  a
    # 1 -10  2  b
    # 2   3  3  b
    # 3   4  4  b
    # 4   5  5  a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    到目前为止的示例中,我们已经为现有列的元素赋值,但是指定新的列名会添加一个新列,并允许我们为满足条件的行赋值。

    df.loc[df['B'] % 2 == 0, 'D'] = 'even'
    df.loc[df['B'] % 2 != 0, 'D'] = 'odd'
    print(df)
    #     A  B  C     D
    # 0 -10  1  a   odd
    # 1 -10  2  b  even
    # 2   3  3  b   odd
    # 3   4  4  b  even
    # 4   5  5  a   odd
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    也可以用 and, or 指定多个条件。使用 &, | 将每个条件括在括号中。

    添加新列时,不满足条件的元素将具有缺失值 NaN。请注意,包含 NaN 的列的类型 dtype 将为 float。

    df.loc[~(df['A'] < 0) & (df['C'] == 'b'), 'E'] = df['B'] * 2
    print(df)
    #     A  B  C     D    E
    # 0 -10  1  a   odd  NaN
    # 1 -10  2  b  even  NaN
    # 2   3  3  b   odd  6.0
    # 3   4  4  b  even  8.0
    # 4   5  5  a   odd  NaN
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    根据列的值选择两列之一的过程可以编写如下。

    df.loc[~(df['A'] < 0), 'A'] = 10
    print(df)
    #     A  B  C     D    E
    # 0 -10  1  a   odd  NaN
    # 1 -10  2  b  even  NaN
    # 2  10  3  b   odd  6.0
    # 3  10  4  b  even  8.0
    # 4  10  5  a   odd  NaN
    
    df.loc[df['C'] == 'a', 'F'] = df['A']
    df.loc[df['C'] == 'b', 'F'] = df['B']
    print(df)
    #     A  B  C     D    E     F
    # 0 -10  1  a   odd  NaN -10.0
    # 1 -10  2  b  even  NaN   2.0
    # 2  10  3  b   odd  6.0   3.0
    # 3  10  4  b  even  8.0   4.0
    # 4  10  5  a   odd  NaN  10.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    也可以使用 loc 和 iloc 在列表中指定多个列。

    df.loc[df['C'] == 'a', ['E', 'F']] = 100
    print(df)
    #     A  B  C     D      E    F
    # 0 -10  1  a   odd  100.0  100
    # 1 -10  2  b  even    NaN    2
    # 2  10  3  b   odd    6.0    3
    # 3  10  4  b  even    8.0    4
    # 4  10  5  a   odd  100.0  100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    对 pandas.DataFrame 进行比较操作会得到一个 bool 类型的 pandas.DataFrame,但是它不能被广播,所以像前面的例子一样给它赋值会导致错误。

    print(df < 0)
    #        A      B     C     D      E      F
    # 0   True  False  True  True  False  False
    # 1   True  False  True  True  False  False
    # 2  False  False  True  True  False  False
    # 3  False  False  True  True  False  False
    # 4  False  False  True  True  False  False
    
    print(df[df < 0])
    #       A   B  C     D   E   F
    # 0 -10.0 NaN  a   odd NaN NaN
    # 1 -10.0 NaN  b  even NaN NaN
    # 2   NaN NaN  b   odd NaN NaN
    # 3   NaN NaN  b  even NaN NaN
    # 4   NaN NaN  a   odd NaN NaN
    
    # df[df < 0] = 0
    # TypeError: Cannot do inplace boolean setting on mixed-types with a non np.nan value
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如果要对整个 pandas.DataFrame 应用条件,请使用下面描述的 where() 方法或 mask() 方法。

    • pandas.DataFrame, Series 的 where() 方法
      pandas.DataFrame、pandas.Series 方法有 where()。

    如果指定 pandas.Series 或带有 bool 值元素的数组作为第一个参数,则 True 元素的值仍然是调用源的对象,而 False 元素的值变为 NaN。

    df = pd.DataFrame({'A': [-20, -10, 0, 10, 20],
                       'B': [1, 2, 3, 4, 5],
                       'C': ['a', 'b', 'b', 'b', 'a']})
    print(df)
    #     A  B  C
    # 0 -20  1  a
    # 1 -10  2  b
    # 2   0  3  b
    # 3  10  4  b
    # 4  20  5  a
    
    print(df['A'].where(df['C'] == 'a'))
    # 0   -20.0
    # 1     NaN
    # 2     NaN
    # 3     NaN
    # 4    20.0
    # Name: A, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如果指定标量值、pandas.Series 或数组作为第二个参数,则将使用该值而不是 NaN 作为 False 元素的值。与 NumPy 的 where() 函数不同,不能指定 True 值(保留原始值)。

    print(df['A'].where(df['C'] == 'a', 100))
    # 0    -20
    # 1    100
    # 2    100
    # 3    100
    # 4     20
    # Name: A, dtype: int64
    
    print(df['A'].where(df['C'] == 'a', df['B']))
    # 0   -20
    # 1     2
    # 2     3
    # 3     4
    # 4    20
    # Name: A, dtype: int64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    也可以将其添加为新列。

    df['D'] = df['A'].where(df['C'] == 'a', df['B'])
    print(df)
    #     A  B  C   D
    # 0 -20  1  a -20
    # 1 -10  2  b   2
    # 2   0  3  b   3
    # 3  10  4  b   4
    # 4  20  5  a  20
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    参数 inplace=True 修改原始对象。

    df['D'].where((df['D'] % 2 == 0) & (df['A'] < 0), df['D'] * 100, inplace=True)
    print(df)
    #     A  B  C     D
    # 0 -20  1  a   -20
    # 1 -10  2  b     2
    # 2   0  3  b   300
    # 3  10  4  b   400
    # 4  20  5  a  2000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    pandas.DataFrame 也有一个 where() 方法。指定一个 pandas.DataFrame 或一个二维数组,其元素的 bool 值与调用者大小相同,作为第一个参数的条件。

    print(df < 0)
    #        A      B     C      D
    # 0   True  False  True   True
    # 1   True  False  True  False
    # 2  False  False  True  False
    # 3  False  False  True  False
    # 4  False  False  True  False
    
    print(df.where(df < 0))
    #       A   B  C     D
    # 0 -20.0 NaN  a -20.0
    # 1 -10.0 NaN  b   NaN
    # 2   NaN NaN  b   NaN
    # 3   NaN NaN  b   NaN
    # 4   NaN NaN  a   NaN
    
    print(df.where(df < 0, df * 2))
    #     A   B  C     D
    # 0 -20   2  a   -20
    # 1 -10   4  b     4
    # 2   0   6  b   600
    # 3  20   8  b   800
    # 4  40  10  a  4000
    
    print(df.where(df < 0, 100))
    #      A    B  C    D
    # 0  -20  100  a  -20
    # 1  -10  100  b  100
    # 2  100  100  b  100
    # 3  100  100  b  100
    # 4  100  100  a  100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    pandas.DataFrame, Series 的 mask() 方法

    pandas.DataFrame, pandas.Series 方法有 mask()。

    mask() 方法与 where() 方法相反,第一个参数中条件为 False 的元素仍然是调用者的对象,True 元素变为 NaN 或第二个参数中指定的值。 其他用法同where()。

    df = pd.DataFrame({'A': [-20, -10, 0, 10, 20],
                       'B': [1, 2, 3, 4, 5],
                       'C': ['a', 'b', 'b', 'b', 'a']})
    print(df)
    #     A  B  C
    # 0 -20  1  a
    # 1 -10  2  b
    # 2   0  3  b
    # 3  10  4  b
    # 4  20  5  a
    
    print(df['C'].mask(df['C'] == 'a'))
    # 0    NaN
    # 1      b
    # 2      b
    # 3      b
    # 4    NaN
    # Name: C, dtype: object
    
    print(df['C'].mask(df['C'] == 'a', 100))
    # 0    100
    # 1      b
    # 2      b
    # 3      b
    # 4    100
    # Name: C, dtype: object
    
    df['D'] = df['A'].mask(df['C'] == 'a', df['B'])
    print(df)
    #     A  B  C   D
    # 0 -20  1  a   1
    # 1 -10  2  b -10
    # 2   0  3  b   0
    # 3  10  4  b  10
    # 4  20  5  a   5
    
    df['D'].mask(df['D'] % 2 != 0, df['D'] * 10, inplace=True)
    print(df)
    #     A  B  C   D
    # 0 -20  1  a  10
    # 1 -10  2  b -10
    # 2   0  3  b   0
    # 3  10  4  b  10
    # 4  20  5  a  50
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    它似乎比 where() 更直观,因为第二个参数被分配给满足第一个参数条件(变为 True)的元素。 pandas.DataFrame 也有一个 mask() 方法。

    print(df.mask(df < 0, -100))
    #      A  B     C    D
    # 0 -100  1  -100   10
    # 1 -100  2  -100 -100
    # 2    0  3  -100    0
    # 3   10  4  -100   10
    # 4   20  5  -100   50
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果只想将方法应用于包含数字和字符串的对象的数字列,如本例所示,您可以按如下方式使用 select_dtypes()。

    print(df.select_dtypes(include='number').mask(df < 0, -100))
    #      A  B    D
    # 0 -100  1   10
    # 1 -100  2 -100
    # 2    0  3    0
    # 3   10  4   10
    # 4   20  5   50
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    也可以在仅处理数字列之后连接非数字列。

    df_mask = df.select_dtypes(include='number').mask(df < 0, -100)
    df_mask = pd.concat([df_mask, df.select_dtypes(exclude='number')], axis=1)
    print(df_mask.sort_index(axis=1))
    #      A  B  C    D
    # 0 -100  1  a   10
    # 1 -100  2  b -100
    # 2    0  3  b    0
    # 3   10  4  b   10
    # 4   20  5  a   50
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    NumPy where() 函数

    使用NumPy的where()函数也可以根据条件赋值。

    pandas where() 方法或 mask() 方法中,第二个参数只能是 False 或 True 时赋值的值,调用对象的值按原样用于另一个。。因此,无法执行根据条件选择值的处理(为 True 和 False 指定不同值的处理)。

    在 NumPy where() 函数中,第一个参数是条件,第二个参数是要分配给条件为 True 的元素的值,第三个参数是要分配给条件为 False 的元素的值。可以为第二个和第三个参数指定标量值和数组,并通过广播分配。

    numpy.where() 返回 NumPy 数组 ndarray。

    一维 numpy.ndarray 可以指定为 pandas.DataFrame 的列。

    df = pd.DataFrame({'A': [-20, -10, 0, 10, 20],
                       'B': [1, 2, 3, 4, 5],
                       'C': ['a', 'b', 'b', 'b', 'a']})
    print(df)
    #     A  B  C
    # 0 -20  1  a
    # 1 -10  2  b
    # 2   0  3  b
    # 3  10  4  b
    # 4  20  5  a
    
    print(np.where(df['B'] % 2 == 0, 'even', 'odd'))
    # ['odd' 'even' 'odd' 'even' 'odd']
    
    print(np.where(df['C'] == 'a', df['A'], df['B']))
    # [-20   2   3   4  20]
    
    df['D'] = np.where(df['B'] % 2 == 0, 'even', 'odd')
    print(df)
    #     A  B  C     D
    # 0 -20  1  a   odd
    # 1 -10  2  b  even
    # 2   0  3  b   odd
    # 3  10  4  b  even
    # 4  20  5  a   odd
    
    df['E'] = np.where(df['C'] == 'a', df['A'], df['B'])
    print(df)
    #     A  B  C     D   E
    # 0 -20  1  a   odd -20
    # 1 -10  2  b  even   2
    # 2   0  3  b   odd   3
    # 3  10  4  b  even   4
    # 4  20  5  a   odd  20
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    如果指定 pandas.DataFrame 作为条件,则返回二维 numpy.ndarray。您可以使用原始 pandas.DataFrame 的索引和列创建一个 pandas.DataFrame。

    print(np.where(df < 0, df, 100))
    # [[-20 100 'a' 'odd' -20]
    #  [-10 100 'b' 'even' 100]
    #  [100 100 'b' 'odd' 100]
    #  [100 100 'b' 'even' 100]
    #  [100 100 'a' 'odd' 100]]
    
    df_np_where = pd.DataFrame(np.where(df < 0, df, 100),
                               index=df.index, columns=df.columns)
    
    print(df_np_where)
    #      A    B  C     D    E
    # 0  -20  100  a   odd  -20
    # 1  -10  100  b  even  100
    # 2  100  100  b   odd  100
    # 3  100  100  b  even  100
    # 4  100  100  a   odd  100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    【机器学习笔记13】softmax多分类模型【上篇】完整流程与详细公式推导
    借教室——二分、前缀和、差分
    2022最新IntellJ IDEA诺依开发部署文档
    Dart(17)-top-level概念
    了解《单链表》看这篇就好了(内含动图)!!!
    SpringMVC
    GPIO子系统(三)
    iwebsec靶场 SQL注入漏洞通关笔记11-16进制编码绕过
    squid代理服务器应用
    AI和软件测试结合-使用LLM将自然语言生成TestCase
  • 原文地址:https://blog.csdn.net/qq_18351157/article/details/127938064