Получение результатов на основе диапазона и комбинации столбцов

#python #pandas

#python #pandas

Вопрос:

Пример DF:

 ID   Name        Price     Sum       
1    Apple         10      180        
2    Apple         10      100        
3    Apple         10      80         
4    Orange        12      180        
5    Orange        12      190         
6    Banana        15      50       
7    Banana        15      30   
  

Ожидаемый DF:

 ID   Name        Price     Sum     Result  
1    Apple         10      180      Full Match       
2    Orange        12      180      Match - High Confidence  
3    Orange        12      190      Match - High Confidence   
4    Banana        15      50       Match - Low Confidence
5    Banana        15      30       Match - Low Confidence
  

Постановка задачи:

Мне нужны Result столбцы, которые работают при следующих условиях:

  1. Для группы Name и Price , т.е. Название — Apple, а цена — 10, если наибольшее значение не находится в диапазоне — 30 для других, тогда сохраните строку с наибольшим значением со столбцом результата как Full Match и удалите другие (пример Df — ID 1,2,3, а ожидаемый DF — только идентификатор 1)

  2. Внутри группы Name и Price если она находится в диапазоне — 30, а также больше 100, то столбцы результатов будут Match - High Confidence , и никакие строки не будут удалены (пример Df — ID 4,5, а ожидаемый DF — ID 2,3)

  3. Внутри группы Name и Price если она находится в диапазоне — 30 и меньше 60, то столбцы результатов будут Match - Low Confidence , и никакие строки не будут удалены (примерный Df — ID 6,7, а ожидаемый DF — ID 4,5)

Я не могу найти ничего о том, как решить эту проблему, когда задействована комбинация групп плюс диапазон. Любая помощь?

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

1. @jezrael: Любая помощь здесь!!!

2. Извините, меня здесь не было, время обеда 😉

Ответ №1:

Вот что я придумал, вы можете попробовать:

 #get absolute difference from max value
df['diff_abs']=abs(df.Sum-df.groupby(['Name','Price'])['Sum'].transform('max')) 
#check if diff less than 30 remove them
m=df.loc[df.duplicated(['Name','Price'],keep=False)amp;df.diff_abs.lt(30)].reset_index()
print(m)

   index  ID    Name  Price  Sum  diff_abs
0      0   1   Apple     10  180         0
1      3   4  Orange     12  180        10
2      4   5  Orange     12  190         0
3      5   6  Banana     15   50         0
4      6   7  Banana     15   30        20

c1=~m.duplicated(['Name','Price'],keep=False) #check if entry is just 1 and no dups
c2=m.duplicated(['Name','Price'],keep=False)amp;m.Sum.lt(60) #if dups check for less than 60
m['result']=np.select([c1,c2],
   ['Full Match','Match - Low Confidence'],'Match - High Confidence')
print(m)

   index  ID    Name  Price  Sum  diff_abs                   result
0      0   1   Apple     10  180         0               Full Match
1      3   4  Orange     12  180        10  Match - High Confidence
2      4   5  Orange     12  190         0  Match - High Confidence
3      5   6  Banana     15   50         0   Match - Low Confidence
4      6   7  Banana     15   30        20   Match - Low Confidence
  

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

1. Получение этой ошибки TypeError: unsupported operand type(s) for -: 'method' and 'int' в df['diff_abs']=abs(df.Sum-df.groupby(['Name','Price'])['Sum'].transform('max')) строке

2. Это minus операция, которая выдает эту ошибку

3. @RahulAgarwal я думаю, что проблема, связанная с данными, работает для примера, есть ли пробелы в столбцах, если да, - не работает. вы можете проверить их, иначе @jez-offer будет лучшим. 🙂 !!

4. На самом деле я заменил df.sum на df["sum"] , и это сработало 🙂

5. @RahulAgarwal да, это потому, что sum это метод, вам следует избегать использования методов в качестве переменных. 🙂 Я думал, что имя столбца Sum , рад, что это сработало

Ответ №2:

Я думаю, вам нужно:

 #get Series for maximal value of group
maxpergroup = df.groupby(['Name','Price'])['Sum'].transform('max')
#subtract values, get absolute values and compare by greater 30
m1 = df['Sum'].sub(maxpergroup).abs().gt(30)
#get all groups where at least one True
m11 = m1.groupby([df['Name'],df['Price']]).transform('any')
#print (m11)

#compare by another values and test if all values matching per groups
m2 = df['Sum'].gt(100)
m22 = (m2 amp; ~m1).groupby([df['Name'],df['Price']]).transform('all')
#print (m22)

m3 = df['Sum'].lt(60)
m33 = (m3 amp; ~m1).groupby([df['Name'],df['Price']]).transform('all')
#print (m33)

#create new column
masks = [m11,m22, m33]
vals = ['Full Match','Match - Low Confidence','Match - High Confidence']
df['result'] = np.select(masks, vals)

#remove unnecessary rows
df = df[~m11 | df['Sum'].eq(maxpergroup)]
print (df)
   ID    Name  Price  Sum                   result
0  1   Apple   10     180  Full Match             
3  4   Orange  12     180  Match - Low Confidence 
4  5   Orange  12     190  Match - Low Confidence 
5  6   Banana  15     50   Match - High Confidence
6  7   Banana  15     30   Match - High Confidence
  

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

1. Я получаю эту ошибку ValueError: invalid entry 0 in condlist: should be boolean ndarray в этой строке df['result'] = np.select(masks, vals)

2. @RahulAgarwal — Похоже, ошибка, связанная с данными, являются ли данные конфиденциальными?

3. Не так много.. Я могу маскировать!!

4. @RahulAgarwal — Таким образом, вы можете поделиться ссылкой на данные через dropbox, gdocs или аналогичные или отправить данные на мою электронную почту из моего профиля.

5. @anky_91 — Спасибо, я проверяю ваше решение и, кажется, вы проверяете значения по группам? Кажется, нет.