如何使用一列或另一列对 pandas DataFrame 进行分组

How do I group a pandas DataFrame using one column or another

尊敬的 pandas DataFrame 专家,

我一直在使用 pandas DataFrames 来帮助重写开源项目中的图表代码 (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

下一行计算按 x_ray_system_name 和 study_name 分组的 total_dlp 数据的计数和平均值:

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”意味着包括三个 study_name“head”条目,以及单个 request_name“head”条目。

我希望结果看起来像这样:

                                 total_dlp
                                     count         mean
x_ray_system_name   name   
All systems         blank                3   200.000000
                    head                 4   187.500000

有谁知道如何根据一个或另一个字段中的类别进行分组?

非常感谢您提供的任何帮助。

亲切的问候,

大卫

您(groupby)数据本质上是以下的并集:

  1. study_name == request_name
  2. 提取那些
  3. 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()
)

更新:编辑上面的代码帮助我意识到我们可以简化 do:

# 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

我的方法与@QuangHoang 的方法类似,但操作顺序不同。

我在这里使用原始(范围)索引来选择如何删除重复数据。

您可以 meltdrop_duplicatesdropna 以及 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