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

时间:2014-11-20 14:14:50

标签: python pandas conditional calculated-columns

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

   portion  used
0        1   1.0
1        2   0.3
2        3   0.0
3        4   0.8

我想根据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
  • 根据
  • 创建新的alert
  • 如果used1.0,则alert应为Full
  • 如果used0.0,则alert应为Empty
  • 否则,alert应为Partial

最好的方法是什么?

6 个答案:

答案 0 :(得分:31)

您可以定义一个函数,它返回不同的状态“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

答案 1 :(得分:24)

或者你可以这样做:

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'

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

100 loops, best of 3: 2.91 ms per loop

然后使用apply:

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

1 loops, best of 3: 287 ms per loop

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

答案 2 :(得分:6)

使用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

<子>计时

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

答案 3 :(得分:1)

使用旨在处理多个条件的 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')

或者将条件/选择定义为可维护性的字典(在添加/修改时更容易保持它们正确配对):

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

np.select() 非常快,但在某些情况下 df.loc[] 可能更快:

timing comparison

答案 4 :(得分:0)

无法发表评论所以提出一个新的答案:改进Ffisegydd的方法,你可以使用字典和dict.get()方法使函数传入.apply()更容易管理:

import pandas as pd

def alert(c):
    mapping = {1.0: 'Full', 0.0: 'Empty'}
    return mapping.get(c['used'], 'Partial')

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)

根据用例的不同,您可能也希望在函数定义之外定义dict。

答案 5 :(得分:0)

df['TaxStatus'] = np.where(df.Public == 1, True, np.where(df.Public == 2, False))

这似乎可行,除了ValueError:x和y都不应该给出