Сравнение столбцов рядов данных на основе столбца, содержащего дубликаты

#python #pandas #dataframe #.loc

#питон #панды #фрейм данных #.loc

Вопрос:

У меня есть набор данных, который я создал, объединив 2 df в столбце «ИМЯ», и теперь у меня есть набор данных большего размера. Чтобы закончить DF, я хочу выполнить некоторую логику, чтобы очистить его.

Требования: я хочу выбрать уникальное «имя», но я хочу сопоставить имя с самым большим объемом продаж подряд, и если после прохождения продажи столбцов, всех строк меньше, чем 10, а затем перейти на призывы столбца и выберите самое строки с наибольшим звонка, и если все звонки в вызывает менее 10 затем перейти к целевой столбец выбрать самую высокую цель. Строки не суммируются.

Вот мой DF:

 NAME CUSTOMER_SUPPLIER_NUMBER Sales Calls Target 0 OFFICE 1 2222277 84 170 265 1 OFFICE 1 2222278 26 103 287 2 OFFICE 1 2222278 97 167 288 3 OFFICE 2 2222289 7 167 288 4 OFFICE 2 2222289 3 130 295 5 OFFICE 2 2222289 9 195 257 6 OFFICE 3 1111111 1 2 286 7 OFFICE 3 1111111 5 2 287 8 OFFICE 3 1111112 9 7 230 9 OFFICE 4 1111171 95 193 299 10 OFFICE 5 1111191 9 193 298  

Вот что я хочу показать в финальном DF:

 NAME CUSTOMER_SUPPLIER_NUMBER Sales Calls Target 0 OFFICE 1 2222277 97 167 288 5 OFFICE 2 2222289 9 195 257 7 OFFICE 3 1111111 5 2 287 9 OFFICE 4 1111171 95 193 299 10 OFFICE 5 1111191 9 193 298   

Я думал о том, чтобы решить эту проблему с помощью df.itterows()

Вот что я попробовал:

 for n, v in df.iterrows():   if int(v['Sales']) gt; 10:  calls = df.loc[(v['NAME'] == v) amp; (int(v['Calls'].max()))]  if int(calls['Calls']) gt; 10:  target = df.loc[(v['NAME'] == v) amp; (int(v['Target'].max()))]  else:  print("No match found")  else:  sales = df.loc[(v['NAME'] == v) amp; (int(v['Sales'].max())]  

Тем не менее, я продолжаю получать KeyError: False сообщения об ошибках. Есть какие-нибудь мысли о том, что я делаю не так?

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

1. Под «если «ВЫЗОВОВ» меньше 10″ вы имеете в виду, если «ВЫЗОВОВ», которые были выбраны, меньше 10, от суммы ВЫЗОВОВ для этого НОМЕРА CUSTOMER_SUPPLIER, или что…?

2. хороший вопрос, спасибо за разъяснение. Я ищу строку с наибольшим значением вызова, а не сумму значений.

3. Под «если продажи меньше 10» вы подразумеваете «если самые высокие продажи меньше 10»?

4. да, именно так! если наибольшее значение меньше 10, перейдите к следующему столбцу и проверьте вызовы и следуйте той же логике проверки, чтобы увидеть, меньше ли 10

Ответ №1:

Это не оптимизировано, но должно соответствовать вашим потребностям. Фрагмент кода отправляет каждую NAME группу туда eval_group() , где он проверяет наивысший индекс для каждого столбца, пока не будут выполнены критерии продаж, звонков и целей.

Если бы вы хотели оптимизировать, то вы могли бы применить принципы векторизации или параллелизма к eval_group так называемому методу против всех групп сразу, а не последовательно.

Несколько примечаний, это вернет первую строку, если найдено условие гонки (т. Е. Несколько записей имеют одинаковый максимум во idxmax() время вызова). Кроме того, я верю в ваш вопрос, что первая строка в желаемом ответе должна OFFICE 1 быть строкой 2, а не 0.

 df = pd.read_csv('./data.txt')  def eval_group(df, keys) :  for key in keys :   row_id = df[key].idxmax()  if df.loc[row_id][key] gt;= 10 or key == keys[-1] :  return row_id  row_ids = [] keys = ['Sales','Calls','Target'] for name in df['NAME'].unique().tolist() :  condition = df['NAME'] == name   row_ids.append( eval_group( df[condition], keys) )  df = df[ df.index.isin(row_ids) ]  df  NAME CUSTOMER_SUPPLIER_NUMBER Sales Calls Target 2 OFFICE 1 2222278 97 167 288 5 OFFICE 2 2222289 9 195 257 7 OFFICE 3 1111111 5 2 287 9 OFFICE 4 1111171 95 193 299 10 OFFICE 5 1111191 9 193 298  

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

1. эй, большое спасибо за этот ответ, я ценю это! Я не смог получить тех же результатов. В результате я получил это. Также, пожалуйста, обратите внимание, что я изменил несколько цифр, но я ожидаю тех же результатов. Я получаю, что офис 1 появляется 3 раза, а офис 2 появляется дважды. Я в точности скопировал вашу формулу и логику

2. Основываясь на логике unique (), вы не должны получать повторяющиеся имена, если у вас нет пробелов вокруг имен. Это сделало бы что-то вроде «Офис 1» и «Офис 1» одинаковыми при печати, но разными при вычислении.

3. ах да, у меня там было несколько свободных мест. вот что это сделало! Спасибо, это здорово!

Ответ №2:

Это занимает несколько шагов, в которых вам нужно построить промежуточные кадры данных, выполнить условное условие и выполнить фильтрацию на основе результата условий:

 temp = (df  .drop(columns = 'CUSTOMER_SUPPLIER_NUMBER')  .groupby('NAME', sort = False)  .idxmax()  )  # get the booleans for rows less than 10 bools = df.loc(axis=1)['Sales':'Target'].lt(10)  # groupby for each NAME bools = bools.groupby(df.NAME, sort = False).all()  # conditions buildup condlist = [~bool_check.Sales, ~bool_check.Calls, ~bool_check.Target] choicelist = [temp.Sales, temp.Calls, temp.Target] # you might have to figure out what to use for default indices = np.select(condlist, choicelist, default = temp.Sales)  # get matching rows df.loc[indices]  NAME CUSTOMER_SUPPLIER_NUMBER Sales Calls Target 2 OFFICE 1 2222278 97 167 288 5 OFFICE 2 2222289 9 195 257 7 OFFICE 3 1111111 5 2 287 9 OFFICE 4 1111171 95 193 299 10 OFFICE 5 1111191 9 193 298