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

以下内容进行说明。

  • 带有 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

如果对 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

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

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

带有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

也可以指定 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

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

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

也可以用 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

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

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

也可以使用 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

对 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

如果要对整个 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

如果指定标量值、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

也可以将其添加为新列。

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

参数 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

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

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

它似乎比 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

如果只想将方法应用于包含数字和字符串的对象的数字列,如本例所示,您可以按如下方式使用 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

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

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

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

如果指定 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

猜你喜欢

转载自blog.csdn.net/qq_18351157/article/details/127938064