【问题标题】:Conditional flag based on Groupby Python基于 Groupby Python 的条件标志
【发布时间】:2020-02-18 02:24:16
【问题描述】:

我想使用条件语句根据 id 和优先顺序创建标志 -

数据框 -

    df=pd.DataFrame({'id':[1,1,1,1,2,3,3,3],
     'var':['Apple','Banana','Orange','Mango', 'Mango', 'Banana','Orange','Mango'],
      'flag':[1,1,1,1,1,1,1,1]})

优先顺序 - 苹果 > 香蕉 > 橙子

条件-

1 - 如果 Apple、Banana 和 Mango 出现在 id 中,则 Banana 和 Ornage 的标志变为 0,对 Mango 没有影响,它将为 1。

2 - 如果存在香蕉和橙子,则橙子的标志将变为 0

输出 -

     df=pd.DataFrame({'id':[1,1,1,1,2,3,3,3],
     'var':['Apple','Banana','Orange','Mango', 'Mango', 'Banana','Orange','Mango'],
      'flag':[1,0,0,1,1,1,0,1]})

方法——

我尝试过对数据进行分组,并考虑通过定义条件列表来执行交集。

我相信我把它弄复杂了,而且做错了。请指导。

group_test = df.groupby(['id'],as_index=False).var.agg(lambda x: x.unique().tolist())
list_1 = ['Apple','Banana','Orange']
list_2 = ['Banana', 'Orange']

【问题讨论】:

  • 所以“Mango”应该单独留下吗?
  • 这是一个样本数据,我有一个包含更多水果的数据集。
  • 好的。我之所以问,是因为您的 group_test 根本不包含“芒果”,但它在数据中并出现在组中
  • 是的,我选择了不好的例子,很抱歉造成混乱。

标签: python pandas numpy


【解决方案1】:

我们可以循环遍历GroupBy 对象的每个块,并使用locflag 列设置为行满足特定条件所需的值。

首先让我们提前设置所有条件。

match1 = {'Apple', 'Banana', 'Mango'}
match2 = {'Banana', 'Orange'}
p_cond = (df['var'].str.contains('Banana|Orange', regex=True))
s_cond = (df['var'] == 'Orange')

如果符合我们的条件,我们可以循环设置flag 列的分组对象。

for k, v in df.groupby('id')['var']:
    vals = set(v)
    id_cond = (df['id'] == k)

    if vals.issuperset(match1):
        df.loc[id_cond & p_cond, 'flag'] = 0
    elif vals.issuperset(match2):
        df.loc[id_cond & s_cond, 'flag'] = 0
    else:
        continue

这会产生以下结果。

   flag  id     var
0     1   1   Apple
1     0   1  Banana
2     0   1  Orange
3     1   1   Mango
4     1   2   Mango
5     1   3  Banana
6     0   3  Orange
7     1   3   Mango

【讨论】:

  • 它工作正常,我喜欢你解决问题的方式。我可以根据条件轻松操作代码。谢谢@gold_cy
【解决方案2】:

这是一种适用于给定数据的解决方案。如果您在n = 类别数量的类别中订购(n-2),我认为它不会起作用。

如果您想为每个id 确定最高类别,这是一个更通用的答案

编辑:如果您有一小组指定顺序的类别,只需将它们集中到一个other 类别中即可分配最后一个顺序。应该够了

import pandas as pd
df=pd.DataFrame({'id':[1,1,1,1,2,3,3,3],
     'var':['Apple','Banana','Orange','Mango', 'Mango', 'Banana','Orange','Mango'],
      'flag':[1,1,1,1,1,1,1,1]})

# create a categorical array with the orders set this way.
# this keeps the ordering Apple > Banana > Orange > Mango
df['category'] = pd.Categorical(df['var'], ordered=True, categories=reversed(['Apple', 'Banana', 'Orange', 'Mango']))

# group by id and just get a boolean of whether var = max category
# for each id subset, compare each var to the maximum category in that subset
df['highest_level'] = df.groupby('id').apply(lambda df_: 1 * (df_['var'] == df_['category'].max())).reset_index(drop=True)

# put mango back to 1 - since Mango was the lowest in the order
# the only times Mango would have a highest_level = 1 would be
# when the entire subset only has Mango var
df.loc[df['var'] == 'Mango', 'highest_level'] = 1

【讨论】:

  • 在我看来不太可读。你能解释一下至少不仅仅是 cmets 发生了什么吗?这将有助于初学者和其他读者。
  • 我拥有的数据包含40个不同的类别,正如你所建议的,它不适用于更高的n。
  • :) 有一个相当简单的补救措施。例如,您可以创建一个列,其中所有不适用于条件的类别都设置为“其他”。所以芒果、杏等可能是“其他”,你的分类变量可以考虑到这一点
猜你喜欢
  • 2017-04-11
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多