使用条件在pandas dataframe中生成新列

use*_*999 16 python conditional calculated-columns pandas

我有一个像这样的pandas数据框:

   portion  used
0        1   1.0
1        2   0.3
2        3   0.0
3        4   0.8
Run Code Online (Sandbox Code Playgroud)

我想基于used列创建一个新列,所以df看起来像这样:

   portion  used    alert
0        1   1.0     Full
1        2   0.3  Partial
2        3   0.0    Empty
3        4   0.8  Partial
Run Code Online (Sandbox Code Playgroud)
  • alert基于创建新列
  • 如果used1.0,alert应该是Full.
  • 如果used0.0,alert应该是Empty.
  • 否则,alert应该是Partial.

最好的方法是什么?

Ffi*_*ydd 34

您可以定义一个函数,它返回不同的状态"Full","Partial","Empty"等,然后df.apply用于将函数应用于每一行.请注意,您必须传递关键字参数axis=1以确保它将函数应用于行.

import pandas as pd

def alert(c):
  if c['used'] == 1.0:
    return 'Full'
  elif c['used'] == 0.0:
    return 'Empty'
  elif 0.0 < c['used'] < 1.0:
    return 'Partial'
  else:
    return 'Undefined'

df = pd.DataFrame(data={'portion':[1, 2, 3, 4], 'used':[1.0, 0.3, 0.0, 0.8]})

df['alert'] = df.apply(alert, axis=1)

#    portion  used    alert
# 0        1   1.0     Full
# 1        2   0.3  Partial
# 2        3   0.0    Empty
# 3        4   0.8  Partial
Run Code Online (Sandbox Code Playgroud)

  • 很好的例子。为了使代码更清晰一点(并且由于您使用的是 `axis=1`),您可以将参数 `c` 重命名为 `row`,这样很明显您可以访问函数中的行。 (2认同)

Pri*_*mer 31

或者你可以这样做:

import pandas as pd
import numpy as np
df = pd.DataFrame(data={'portion':np.arange(10000), 'used':np.random.rand(10000)})

%%timeit
df.loc[df['used'] == 1.0, 'alert'] = 'Full'
df.loc[df['used'] == 0.0, 'alert'] = 'Empty'
df.loc[(df['used'] >0.0) & (df['used'] < 1.0), 'alert'] = 'Partial'
Run Code Online (Sandbox Code Playgroud)

它提供相同的输出,但在10000行上运行速度快约100倍:

100 loops, best of 3: 2.91 ms per loop
Run Code Online (Sandbox Code Playgroud)

然后使用申请:

%timeit df['alert'] = df.apply(alert, axis=1)

1 loops, best of 3: 287 ms per loop
Run Code Online (Sandbox Code Playgroud)

我想这个选择取决于你的数据帧有多大.


Zer*_*ero 11

使用np.where,通常很快

In [845]: df['alert'] = np.where(df.used == 1, 'Full', 
                                 np.where(df.used == 0, 'Empty', 'Partial'))

In [846]: df
Out[846]:
   portion  used    alert
0        1   1.0     Full
1        2   0.3  Partial
2        3   0.0    Empty
3        4   0.8  Partial
Run Code Online (Sandbox Code Playgroud)

计时

In [848]: df.shape
Out[848]: (100000, 3)

In [849]: %timeit df['alert'] = np.where(df.used == 1, 'Full', np.where(df.used == 0, 'Empty', 'Partial'))
100 loops, best of 3: 6.17 ms per loop

In [850]: %%timeit
     ...: df.loc[df['used'] == 1.0, 'alert'] = 'Full'
     ...: df.loc[df['used'] == 0.0, 'alert'] = 'Empty'
     ...: df.loc[(df['used'] >0.0) & (df['used'] < 1.0), 'alert'] = 'Partial'
     ...:
10 loops, best of 3: 21.9 ms per loop

In [851]: %timeit df['alert'] = df.apply(alert, axis=1)
1 loop, best of 3: 2.79 s per loop
Run Code Online (Sandbox Code Playgroud)


tdy*_*tdy 6

用于np.select()>2 个条件

给定 >2 个条件(如 OP 的示例),np.select()比嵌套多个级别要干净得多np.where()(并且速度一样快)。

  • 将条件/选择定义为两个列表(按元素配对),并带有可选的默认值(“else”情况):

    conditions = [
        df.used.eq(0),
        df.used.eq(1),
    ]
    choices = [
        'Empty',
        'Full',
    ]
    df['alert'] = np.select(conditions, choices, default='Partial')
    
    Run Code Online (Sandbox Code Playgroud)
  • 或者将条件/选择定义为可维护性的字典(在进行添加/修订时更容易保持它们正确配对):

    conditions = {
        'Empty': df.used.eq(0),
        'Full': df.used.eq(1),
    }
    df['alert'] = np.select(conditions.values(), conditions.keys(), default='Partial')
    
    Run Code Online (Sandbox Code Playgroud)

np.select()非常快

具有 5 种条件的计时(满、高、中、低、空):

5个条件的计时

df = pd.DataFrame({'used': np.random.randint(10 + 1, size=10)}).div(10)