使用条件在熊猫数据框中生成新列

Posted

技术标签:

【中文标题】使用条件在熊猫数据框中生成新列【英文标题】:Using conditional to generate new column in pandas dataframe 【发布时间】:2015-01-18 10:33:20 【问题描述】:

我有一个看起来像这样的熊猫数据框:

   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

最好的方法是什么?

【问题讨论】:

Pandas conditional creation of a series/dataframe column 的可能重复项 【参考方案1】:

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

import pandas as pd

def alert(row):
  if row['used'] == 1.0:
    return 'Full'
  elif row['used'] == 0.0:
    return 'Empty'
  elif 0.0 < row['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

【讨论】:

很好的例子。为了使代码更清晰一点(并且由于您使用的是axis=1),您可以将参数c 重命名为row,这样很明显您可以访问行中的所有值函数。【参考方案2】:

或者你可以这样做:

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

然后使用应用:

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

1 loops, best of 3: 287 ms per loop

我想选择取决于您的数据框有多大。

【讨论】:

关于 %timeit 的问题:如果第一个循环 100 次 @2.91 秒,这是否意味着总时间为 291 毫秒,略长于警报功能完成 1 次循环的 287 毫秒时间? 本例中的 1 个循环在 %%timeit 之后运行 3 行代码。 timeit 程序会自动选择循环数(在这种情况下为 100),以便在一些合理的“超时”内提供更稳健的测量(即,如果运行 1 个循环比此“超时”长,则只有 1 个循环,例如在“使用应用”的情况下)。 timeit 的结果应该在“每 1 个循环”的基础上进行比较。这就是为什么有“运行速度大约快 100 倍”短语的原因:耗时 2.91 毫秒的 1 个循环比耗时 287 毫秒的 1 个循环快大约 100 倍。【参考方案3】:

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

【讨论】:

如果您的情况不太复杂,这应该是公认的答案。【参考方案4】:

无法发表评论,因此提出新的答案:改进 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)

根据用例,您可能还想在函数定义之外定义字典。

【讨论】:

【参考方案5】:
df['TaxStatus'] = np.where(df.Public == 1, True, np.where(df.Public == 2, False))

这似乎可行,但 ValueError 除外:应给出 x 和 y 两者或都不给出

【讨论】:

【参考方案6】:

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

鉴于像 OP 的示例这样的 >2 个条件,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() 非常快

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

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

【讨论】:

您是否有代码或示例说明您如何为此答案创建此图表?我很想把这个展示给一些人。 那是perfplot @scarebear

以上是关于使用条件在熊猫数据框中生成新列的主要内容,如果未能解决你的问题,请参考以下文章

根据熊猫数据框中其他列的条件和值创建新列[重复]

如何有条件地将子字符串复制到熊猫数据框的新列中?

熊猫:将新列添加到作为索引列副本的数据框

根据其他数据框向熊猫数据框添加新列

如何在遍历熊猫数据框时创建新列并插入行值

在熊猫数据框中添加指示计数的新列