Как мне сгруппировать фрейм данных pandas, используя тот или иной столбец

#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) по сути являются объединением:

  1. извлеките те, с study_name == request_name
  2. дублируйте те , с 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