#python #pandas #dataframe #pandas-groupby #aggregate
Вопрос:
Уважаемые эксперты по фреймам данных pandas,
Я использовал фреймы данных pandas, чтобы помочь с переписыванием кода построения диаграмм в проекте с открытым исходным кодом (https://openrem.org/, https://bitbucket.org/openrem/openrem).
Я группировал и агрегировал данные по таким полям, как study_name и x_ray_system_name.
Пример фрейма данных может содержать следующие данные:
study_name request_name total_dlp x_ray_system_name
head head 50.0 All systems
head head 100.0 All systems
head NaN 200.0 All systems
blank NaN 75.0 All systems
blank NaN 125.0 All systems
blank head 400.0 All systems
В следующей строке вычисляется количество и среднее значение данных total_dlp, сгруппированных по x_ray_system_name и study_name:
df.groupby(["x_ray_system_name", "study_name"]).agg({"total_dlp": ["count", "mean"]})
со следующим результатом:
total_dlp
count mean
x_ray_system_name study_name
All systems blank 3 200.000000
head 3 116.666667
Теперь мне нужно уметь вычислять среднее значение данных total_dlp, сгруппированных по записям в study_name или request_name. Поэтому в приведенном выше примере я хотел бы, чтобы «head» означало включение трех записей «head» с именем study_name, а также одной записи «head» с именем запроса.
Я бы хотел, чтобы результаты выглядели примерно так:
total_dlp
count mean
x_ray_system_name name
All systems blank 3 200.000000
head 4 187.500000
Кто-нибудь знает, как я могу провести группировку на основе категорий в той или иной области?
Любая помощь, которую вы можете предложить, будет очень признательна.
С уважением,
Дэвид
Ответ №1:
Ваши данные (groupby) по сути являются объединением:
- извлеките те, с
study_name == request_name
- дублируйте те , с
study_name != request_name
которыми, один дляstudy_name
, один дляrequest_name
Мы можем дублировать данные с помощью melt
(pd.concat([df.query('study_name==request_name') # equal part
.drop('request_name', axis=1), # remove so `melt` doesn't duplicate this data
df.query('study_name!=request_name')]) # not equal part
.melt(['x_ray_system_name','total_dlp']) # melt to duplicate
.groupby(['x_ray_system_name','value'])
['total_dlp'].mean()
)
Обновление: редактирование приведенного выше кода помогает мне понять, что мы могли бы упростить выполнение:
# mask `request_name` with `NaN` where they equal `study_name`
# so they are ignored when duplicate/mean
(df.assign(request_name=df.request_name.mask(df.study_name==df.request_name))
.melt(['x_ray_system_name','total_dlp'])
.groupby(['x_ray_system_name','value'])
['total_dlp'].mean()
)
Выход:
x_ray_system_name value
All systems blank 200.0
head 187.5
Name: total_dlp, dtype: float64
Комментарии:
1. Хорошо, у меня была похожая логика с другим порядком
Ответ №2:
У меня такой же подход, как и у @QuangHoang, но с другим порядком операций.
Я использую здесь исходный индекс (диапазон), чтобы выбрать, как удалить дубликаты данных.
Ты можешь melt
, drop_duplicates
и dropna
и groupby
:
(df.reset_index()
.melt(id_vars=['index', 'total_dlp', 'x_ray_system_name'])
.drop_duplicates(['index', 'value'])
.dropna(subset=['value'])
.groupby(["x_ray_system_name", 'value'])
.agg({"total_dlp": ["count", "mean"]})
)
выход:
total_dlp
count mean
x_ray_system_name value
All systems blank 3 200.0
head 4 187.5
Комментарии:
1. Большое спасибо за ваше предложение — я использовал эту версию в проекте, над которым работаю ( bitbucket.org/openrem/openrem/commits/62f7244c634c )
2. @David вам следует использовать вторую версию Quang , она должна быть немного более эффективной 😉
3. Спасибо. Моя реальная ситуация немного сложнее, чем в моем примере. У меня есть три поля, из которых мне нужно объединить имена. Ваш код работает в этой ситуации, в то время как Куанг приводит к дубликатам в определенных ситуациях.
4. Хорошо, спасибо за отзыв @David