#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, forId
= 4, для которогоOther_value
равно 6 - Группа 3 состоит из 3 элементов, наибольшее
Value_to_compare
значение равно 23, forId
= 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()
следующем случае, когда мне понадобятся подобные вещи. 🙂