首页 > 解决方案 > 2列上的Groupby加上String列上的过滤器

问题描述

样本 DF:

ID   Name        Price     Condition   Fit_Test
1    Apple         10      Good        Super_Fit
2    Apple         10      OK          Super_Fit
3    Apple         10      Bad         Super_Fit
4    Orange        12      Good        Not_Fit
5    Orange        12      OK          Not_Fit
6    Banana        15      OK          Medium_Fit
7    Banana        15      Bad         Medium_Fit
8    Pineapple     25      OK          Medium_Fit
9    Pineapple     25      OK          Medium_Fit
10   Cherry        30      Bad         Medium_Fit

预期的DF:

ID   Name        Price     Condition   Fit_Test
1    Apple         10      Good        Super_Fit
2    Apple         10      OK          Super_Fit
3    Apple         10      Bad         Super_Fit

4    Orange        12      Good        Not_Fit

6    Banana        15      OK          Medium_Fit

8    Pineapple     25      OK          Medium_Fit
9    Pineapple     25      OK          Medium_Fit
10   Cherry        30      Bad         Medium_Fit

问题陈述:

我想group-by通过Name然后Price过滤基于Condition.

  1. 如果存在 Good、BadNamePriceOK 的所有 3 个条件,则只保留 Good 一个,Fit_Test 不存在Super_Fit

  2. 如果存在 Good 和 OK 的 Name 和 Price 条件,则只保留 Good 一个(Id 4,5 只是预期的 ID 4)并且 Fit_Test 不是Super_Fit

  3. 如果存在 Bad 和 OK 的一个NamePrice条件,则只保留 OK 一个(Id 6,7 只是预期的 ID 6)并且 Fit_Test 不是Super_Fit

  4. 如果在 OK 和 OK 的一个NamePrice条件内存在,Good 和 Good Exist 或只是 Bad 存在,那么不要做任何事情,然后只保留 OK 一个(Id 8,9,10 是 ID 8,9,10 在预期中)并且 Fit_Test 是不是Super_Fit

答案更新

  1. 测试的第一个答案和编辑适用于所有df没有Fit_Test列条件的地方。在这个答案中,预期的 DF将没有第 2 行和第 3 行,如答案中所示
  2. 当您需要获取另一个列时, Edit for UpdateFit_Test答案有效,并且仅当值不是时才有效Super_Fit

在这两种解决方案中,基于Condition列的行过滤和 2 列的分组是相同的。

我在数字列上找到了带有 filter + group by 的东西,但在 String 列上没有找到。

标签: pythonpandas

解决方案


想法是 createset用于比较:

a = df.join(df.groupby(['Price','Name'])['Condition'].apply(set).rename('m'),
             on=['Price','Name'])['m']
print (a)
0    {Bad, Good, OK}
1    {Bad, Good, OK}
2    {Bad, Good, OK}
3         {Good, OK}
4         {Good, OK}
5          {Bad, OK}
6          {Bad, OK}
7               {OK}
8               {OK}
9              {Bad}
Name: m, dtype: object

m1 = (a == set({'Bad', 'Good', 'OK'})) | (a == set({'Good', 'OK'}))
m2 = a == set({'Bad', 'OK'})
#check if unique value - length of set is 1
m3 = a.str.len() == 1
m4 = df['Condition'] == 'Good'
m5 = df['Condition'] == 'OK'

df = df[(m1 & m4) | (m2 & m5) | m3]
print (df)
   ID       Name  Price Condition
0   1      Apple     10      Good
3   4     Orange     12      Good
5   6     Banana     15        OK
7   8  Pineapple     25        OK
8   9  Pineapple     25        OK
9  10     Cherry     30       Bad

编辑测试:

对于测试是可能的使用assign

print (df.assign(sets=a, m1 = m1, m2=m2, m3=m3, m4=m4, m5=m5, m=m))
   ID       Name  Price Condition             sets     m1     m2     m3  \
0   1      Apple     10      Good  {Bad, Good, OK}   True  False  False   
1   2      Apple     10        OK  {Bad, Good, OK}   True  False  False   
2   3      Apple     10       Bad  {Bad, Good, OK}   True  False  False   
3   4     Orange     12      Good       {Good, OK}   True  False  False   
4   5     Orange     12        OK       {Good, OK}   True  False  False   
5   6     Banana     15        OK        {Bad, OK}  False   True  False   
6   7     Banana     15       Bad        {Bad, OK}  False   True  False   
7   8  Pineapple     25        OK             {OK}  False  False   True   
8   9  Pineapple     25        OK             {OK}  False  False   True   
9  10     Cherry     30       Bad            {Bad}  False  False   True   

      m4     m5      m  
0   True  False   True  
1  False   True  False  
2  False  False  False  
3   True  False   True  
4  False   True  False  
5  False   True   True  
6  False  False  False  
7  False   True   True  
8  False   True   True  
9  False  False   True  

编辑更新:

对于新条件使用:

    m6 = df['Fit_Test'] == 'Super_Fit'
    df = df[((m1 & m4) | (m2 & m5) | m3) | m6]
    print (df)
       ID       Name  Price Condition    Fit_Test
    0   1      Apple     10      Good   Super_Fit
    1   2      Apple     10        OK   Super_Fit
    2   3      Apple     10       Bad   Super_Fit
    3   4     Orange     12      Good     Not_Fit
    5   6     Banana     15        OK  Medium_Fit
    7   8  Pineapple     25        OK  Medium_Fit
    8   9  Pineapple     25        OK  Medium_Fit
    9  10     Cherry     30       Bad  Medium_Fit

推荐阅读