Группировка по 2 столбцам плюс фильтр по строковым столбцам

#python #pandas

#python #pandas

Вопрос:

Пример 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. Если в пределах Name и Price существуют все 3 условия Good, Bad и OK, тогда сохраняйте только Good, а Fit_Test — нет Super_Fit

  2. Если в пределах названия и цены существуют условия Good и OK, тогда оставьте только Good one (Id 4,5 — это только ожидаемый ID 4), а Fit_Test — нет Super_Fit

  3. Если в пределах Name и Price существуют условия Bad и OK, тогда оставьте только один OK (идентификатор 6,7 — это только ожидаемый идентификатор 6), а Fit_Test — нет Super_Fit

  4. Если в пределах Name и Price существуют условия OK и OK, существуют Good и Good или просто Bad, тогда ничего не делайте, тогда оставьте только OK one (Id 8,9,10 — это ожидаемый идентификатор 8,9,10), а Fit_Test — нет Super_Fit

Обновление ответов

  1. Первый ответ и редактирование для тестирования работает для всех, df где у вас нет условия для Fit_Test столбца. В этом ответе ожидаемый DF не будет иметь строк 2 и 3, как также показано в ответе
  2. Ответ Редактировать для обновления работает, когда вам нужно взять другие столбцы, которые есть Fit_Test и должны работать только тогда, когда значение не является Super_Fit .

В обоих решениях фильтрация строк на основе Condition столбца и группировка по 2 столбцам одинаковы.

Я нашел вещи с filter group by в числовых столбцах, но ничего не нашел в строковых столбцах.

Ответ №1:

Идея в том, чтобы создать set ы для сравнения:

 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 amp; m4) | (m2 amp; 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 amp; m4) | (m2 amp; 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
  

Комментарии:

1. Будет ли это также учитывать Good Good условие

2. @RahulAgarwal — да, потому что set create {Good} и m3 является True

3. Я теряю строки, где у меня есть только один OK . Я вижу, что a это правильно, но в df я вижу, что этих строк там нет.

4. @RahulAgarwal — значит, в a есть только {OK} ? И эти строки удалены?

5. @RahulAgarwal — Спасибо.

Ответ №2:

Если у вас не слишком много условий (например, здесь всего 3), ниже приведен простой обходной путь:

 df.loc[df["Condition"] == 'Good',"Condition"] = 3
df.loc[df["Condition"] == 'OK',"Condition"] = 2
df.loc[df["Condition"] == 'Bad',"Condition"] = 1

df = df.groupby(['Name','Price']).max()

df.loc[df["Condition"] == 3] = "Good"
df.loc[df["Condition"] == 2] = "OK"
df.loc[df["Condition"] == 1] = "Bad"
  

Комментарии:

1. Это удаление строк, в которых у меня есть Good Good условие?

2. Да, если все хорошо, тогда я хочу сохранить их все. Пункт 4 в моем вопросе!!

3. ОК. Прежде всего, нет причин расстраиваться.

4. Если это кажется таким, я приношу извинения. Я не расстроен или что-то в этом роде. Прежде всего, вы помогаете мне!!