Создать столбец фрейма данных из groupby

#python-3.x #pandas #dataframe #pandas-groupby

#python-3.x #панды #фрейм данных #pandas-groupby

Вопрос:

Предположим, у меня есть фрейм данных, подобный

 import pandas as pd
df = pd.DataFrame({
    'Id'    : [1,2,3,4,5,6,7,8,9],
    'Group' : [1,1,2,2,2,2,3,3,3],
    'Value_to_compare' : [2,1,5,8,2,3,10,23,17],
    'Other_value' : [0,3,2,6,3,4,2,7,1]
})
  

Я хотел бы создать новый столбец, скажем Value_of_Highest , отображающий для каждой строки Other_value элемента, имеющего наивысший Value_to_compare из своих Group . Например, здесь:

  • Группа 1 содержит 2 элемента, ее наивысшее Value_to_compare значение равно 2, для Id = 1, для которого Other_value равно 0
  • Группа 2 имеет 4 элемента, самый высокий Value_to_compare — 8, for Id = 4, для которого Other_value равно 6
  • Группа 3 состоит из 3 элементов, наибольшее Value_to_compare значение равно 23, for Id = 8, для которого Other_value равно 7

Итак, я хотел бы добавить столбец, чтобы df стал

Это лучший известный мне способ сделать это:

 def my_func(x):
    x = x.sort_values('Value_to_compare',ascending = False)
    Value_of_Highest = x.head(1)['Other_value'].values[0]
    return pd.Series([Value_of_Highest], index=['Value_of_Highest']) 

grouped = df.groupby('Group').apply(my_func).reset_index()

df = df.merge(grouped)
  

Я уверен, что есть гораздо более элегантный и эффективный способ сделать это в Python / Pandas.

Редактировать: после первого ответа от @CameronRiddell я понял, что мой пример был ошибочным. Я исправил это, и @CameronRiddell отредактировал свой ответ, который работает хорошо.

Ответ №1:

Это отличное приложение groupby и transform , по сути, с помощью преобразования из объекта groupby применяет функцию к каждой группе, но затем возвращает серию или фрейм данных того же размера, что и эта группа. В результате получается DataFrame / Series, форма которого совпадает с исходной формой вдоль оси groupby. (например, в вашем случае результат groupby / transform будет иметь то же количество строк, что и ваш исходный фрейм данных).

 df["Value_of_Highest"] = df.groupby("Group")["Value_to_compare"].transform("max")

print(df)

   Id  Group  Value_to_compare  Other_value  Value_of_Highest
0   1      1                 2            0                 2
1   2      1                 1            3                 2
2   3      2                 5            2                 8
3   4      2                 8            6                 8
4   5      2                 2            3                 8
5   6      2                 3            4                 8
6   7      3                10            2                23
7   8      3                23            7                23
8   9      3                17            1                23
  
  • df.groupby("Group") : сгруппируйте фрейм данных по нашему столбцу «Group»
  • ["Value_to_compare"] : В каждой из этих групп выберите столбец «Value_to_compare»
  • .transform("max") : Получить максимальное значение выбранного столбца для каждой группы. Затем верните ряд, который имеет такое же количество строк, что и группа

Редактировать: Чтобы получить значение, основанное на местоположении максимума, мы используем idxmax() . Это возвращает позицию, в которой происходит max / min . Итак, для нашего варианта использования:

  • мы сгруппируем «Group» и выберем столбец «Value_to_compare»
  • Затем мы получаем индекс максимальных значений «Value_to_compare»
 highest_vtc_indices = df.groupby("Group")["Value_to_compare"].idxmax()

print(highest_vtc_indices)
Group
1    0
2    3
3    7
Name: Value_to_compare, dtype: int64
  

0, 3, 7 соответствует идентификатору строки, в которой в каждой группе встречаются максимальные значения «Value_to_compare».

Теперь, когда мы знаем строку, в которой произошли эти максимумы:

  • Нам нужно будет подмножество нашего исходного фрейма данных, чтобы получить «Other_value» в каждой из этих строк
  • Нам также нужно будет получить столбец «Group», связанный с этими строками, чтобы позже мы могли правильно выровнять эти значения
 # Obtain "Group" amp; "Other_value" at rows 0, 3, 7
  # which were the rows for each highest Value_to_compare per group
highest_other_values = df.loc[highest_vtc_indices, ["Group", "Other_value"]]

# Rename Other_value to Value_of_Highest
highest_other_values = highest_other_values.rename(columns={"Other_value": "Value_of_Highest"})

print(highest_other_values)
   Group  Value_of_Highest
0      1                 0
3      2                 6
7      3                 7
  

Теперь, когда у нас есть соответствующее «Other_value» для максимального «Value_to_compare» для каждой группы, мы будем использовать a merge для выравнивания нашего нового меньшего фрейма данных обратно к нашему исходному фрейму данных. Это приведет к трансляции «Value_of_Highest» через столбец «Group» из исходного фрейма данных.

 # Merge this new dataframe back to our old one to broadcast "Value_of_Highest" across each group
final = df.merge(highest_other_values, on="Group")

print(final)
   Id  Group  Value_to_compare  Other_value  Value_of_Highest
0   1      1                 2            0                 0
1   2      1                 1            3                 0
2   3      2                 5            2                 6
3   4      2                 8            6                 6
4   5      2                 2            3                 6
5   6      2                 3            4                 6
6   7      3                10            2                 7
7   8      3                23            7                 7
8   9      3                17            1                 7
  

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

1. Вау! Я думаю, ты спас моего помощника по коду!!! Большое вам спасибо!

2. однако это не совсем так, поскольку вы дублировали Value_to_compare вместо Other_value .

3. CameronRiddell Я понимаю, что мой пример не совсем отражает то, что я спрашивал. Я отредактировал так, чтобы он отображал значения из Other_value вместо Value_to_compare . Я все еще потерян, не могли бы вы любезно помочь?

4. Я обновил свой ответ, чтобы исправить это редактирование! (сохранил мой первоначальный ответ и поместил новый под ним)

5. Замечательно, большое вам спасибо! Я подумаю о idmax() следующем случае, когда мне понадобятся подобные вещи. 🙂