【问题标题】:How to apply a function to a column in Pandas depending on the value in another column?如何根据另一列中的值将函数应用于 Pandas 中的列?
【发布时间】:2017-06-17 12:47:00
【问题描述】:

提前感谢您的阅读。

我有一个数据框:

df = pd.DataFrame({'Words':[{'Sec': ['level']},{'Sec': ['levels']},{'Sec': ['level']},{'Und': ['ba ']},{'Pro': ['conf'],'ProAbb': ['cth']}],'Conflict':[None,None,None,None,'Match Conflict']})


         Conflict                                     Words
0            None                      {u'Sec': [u'level']}
1            None                     {u'Sec': [u'levels']}
2            None                      {u'Sec': [u'level']}
3            None                        {u'Und': [u'ba ']}
4  Match Conflict  {u'ProAbb': [u'cth'], u'Pro': [u'conf']}

我想应用一个例程,对于'Words' 中的每个元素,检查是否Conflict = 'Match Conflict',如果是,则对'Words' 中的值应用一些函数。

例如,使用以下占位符函数:

def func(x):
    x = x.clear()
    return x

我写:

df['Words'] = df[df['Conflict'] == 'Match Conflict']['Words'].apply(lambda x: func(x))

我的预期输出是:

         Conflict                                     Words
0            None                      {u'Sec': [u'level']}
1            None                     {u'Sec': [u'levels']}
2            None                      {u'Sec': [u'level']}
3            None                        {u'Und': [u'ba ']}
4  Match Conflict                                        None

相反,我得到:

         Conflict Words
0            None   NaN
1            None   NaN
2            None   NaN
3            None   NaN
4  Match Conflict  None

该函数仅应用于具有Conflict = 'Match Conflict' 的行,但以其他行为代价(全部变为None。我假设其他行将保持不变;显然情况并非如此。

您能解释一下如何在不删除Words 列中的所有信息的情况下实现我想要的输出吗?我相信答案可能在于np.where,但我无法完成这项工作,这是我能想到的最好的。

非常感谢任何帮助。谢谢。

【问题讨论】:

  • df['Words'] = #anything 覆盖words 列。所以它的行为完全符合你的要求。
  • @PaulH 感谢您的反馈。我试图应用我所知道的很少的东西,这就是我所知道的。我很高兴得到您和 Psidom 的帮助。

标签: python pandas numpy apply


【解决方案1】:

您应该重写该函数以处理所有行:

def func(x, match):
    if x['Conflict'] == match:
        return None
    return x['Words']

df['Words'] = df.apply(lambda row: func(row, 'Match Conflict'), axis=1)

【讨论】:

  • 非常感谢您的帮助 Paul :) 这非常有用。我整天都在拉头发。
【解决方案2】:

您可以尝试使用.loc 仅更新符合条件的行:

df.loc[df['Conflict'] == 'Match Conflict', 'Words'] = df.loc[df['Conflict'] == 'Match Conflict', 'Words'].apply(lambda x: func(x))

【讨论】:

  • 非常感谢您的帮助。我可以调整这个和@Paul H 的回答来做我需要的一切。真的很感激。
  • 只是想再回来说声谢谢。我今天在生产中实现了这一点,它解决了整个下午的麻烦。谢谢
【解决方案3】:

您也可以按照您的描述使用where

condition = df.Conflict != 'Match Conflict'
df['Words'] = df.Words.where(condition, None)

         Conflict                  Words
0            None   {u'Sec': [u'level']}
1            None  {u'Sec': [u'levels']}
2            None   {u'Sec': [u'level']}
3            None     {u'Und': [u'ba ']}
4  Match Conflict                   None

【讨论】:

  • 非常感谢您的回答和投入!用函数实现where 怎么样,而不仅仅是None a la:df['Words'] = df.Words.where(condition, #func()) 这个语法会是什么样子? (我问这个,因为这个函数只是一个占位符,真正的要充实得多)
  • 这个函数可能需要修改,这取决于它是什么。
【解决方案4】:

假设一个占位符

def func(x):
    x = x.clear()
    return x

然后我们可以使用布尔索引并应用来获得所需的输出。

df.ix[df['Conflict']=='Match Conflict', 'Words'].apply(func)

我想提供一个简洁的单行但我太晚了:,(

【讨论】:

  • 天哪,我学到了很多东西。谢谢您的意见。你的回答让我想到了这个问题stackoverflow.com/questions/27667759/… 等等。谢谢。
  • 如果您想将您的标准扩展到更严格的标准,您是否也可以使用一个函数来代替=='Match Conflict'
  • 我相信是的。布尔和可调用索引在documentation 中有详细说明。我想您可以编写一个返回布尔值的函数并像df.ix[bool_func(df.A), 'B'] 一样使用它。不过,我自己从未尝试过。
猜你喜欢
  • 1970-01-01
  • 2016-12-30
  • 2021-04-28
  • 1970-01-01
  • 2018-04-15
  • 2018-01-18
  • 1970-01-01
  • 2023-03-25
  • 2019-04-04
相关资源
最近更新 更多