【问题标题】:Pandas groupby and sum while retaining other attributesPandas groupby 和 sum 同时保留其他属性
【发布时间】:2019-08-21 12:14:09
【问题描述】:

我看过 Pandas 的 aggregate 函数的示例,但这些并不能解决我的问题。因为聚合函数的示例要么对所有属性求和,要么只对少数属性求和,结果df 仅具有这些求和属性或groupby 中使用的属性。就我而言,我不想为 group by 或 sum 使用某些属性,但仍将它们保留在结果 df 中。

我正在尝试对一些属性进行分组和求和,同时保留其他未求和但面临挑战的属性,如下所述。

在我的交易数据集中,Customer_ID 对于每个客户都是唯一的,entry time 对于每笔交易都是唯一的。任何客户在一段时间内都会有多次交易。大多数交易会重复两次或更多次,具体取决于与交易相关联的标签数量(但通常是 2 到 4 个标签)。我需要将每个事务的多个条目组合到只有 1 行,1 个 customer_ID,一个 genderageentry timelocationcountry 和所有 Tag 属性。

如果我仅按 customer_IDentry time 分组并对 标签 求和,则生成的数据框具有正确数量的唯一客户:150K。但是我在结果df中丢失了genderagelocationcountryexit timevalue 1value 2的属性。

result = df.groupby(["customer_ID","entry time"])["Tag1", "Tag2","Tag3","Tag4","Tag5","Tag6","Tag7","Tag8"].sum().reset_index()

如果我按所有需要的属性分组并对 标签 求和,我只能获得 90K 的唯一客户,这是不正确的。

result = df.groupby(["customer_ID", "entry time", "gender", "age","location", "country", "exit time", "value 1", "value 2"
 ])["Tag1","Tag2","Tag3","Tag4","Tag5","Tag6","Tag7","Tag8"].sum().reset_index()

那么我如何有效地仅按customer_IDentry time 进行分组,对所有Tag 列求和,并在生成的df 中仍保留其他属性(df 大小约为 700 MB)?

【问题讨论】:

  • 我已经编辑了问题以添加更多详细信息,说明来自 pandas 聚合函数的现有示例如何无法解决我的问题
  • 您能否使用nunique() 查看每个["customer_ID","entry time”,"gender", "age","location", "country", "exit time", "value 1", "value 2"] 列中唯一值的数量?
  • 以下是每个属性中的唯一值: Customer_ID = 142973 进入时间 = 1032769 “性别” = 2 “年龄” = 5 “位置” = 23 “国家” = 6 “退出时间” = 1032615 “值 1”= 1589 “值 2” = 252
  • 添加分组字段会降低行数实际上很有趣!你确定会发生这种情况吗? Reproducible example(而不是屏幕截图)会很棒。

标签: python pandas dataframe pandas-groupby


【解决方案1】:

从技术上讲,您正在尝试聚合唯一的 customer_ID进入时间(不是唯一的客户)。为了维护其他属性,必须针对要保留哪些值做出一些综合决策。考虑扩展groupby().aggregate 调用以检索firstlastminmax 值。

agg_df = (df.groupby(['customer_ID', 'entry time'], as_index=False)
            .aggregate({'gender':'first', 'age':'first', 
                        'location':'first', 'country':'first', 
                        'exit time':'first', 'value 1':'first', 'value 2':'first',
                        'Tag1':'sum', 'Tag2':'sum', 'Tag3':'sum', 'Tag4':'sum', 
                        'Tag5':'sum', 'Tag6':'sum', 'Tag7':'sum', 'Tag8':'sum'})
         )

【讨论】:

  • 这个解决方案就像一个魅力!运行了几秒钟,我得到了想要的输出!
【解决方案2】:

好的,如果我正确理解了这个问题,那么我认为这可能有效:

tag_cols = ["Tag1", "Tag2", "Tag3", "Tag4", "Tag5", "Tag6", "Tag7", "Tag8"]
join_cols = ["customer_ID", "entry time"]

df1 = df.groupby(join_cols)[tag_cols].sum().reset_index()
df2 = pd.merge(df1, df, on=tag_cols.append(join_cols), how="left")

那么df2应该有你需要的。

【讨论】:

  • 我想知道 OP 声称通过添加 groupby 列(150K 到 90K)来减少记录数。即使 agelocation 等在每个 customer_IDentry time 内仅更改 一次 i>,行应该增加。因此,如果计数实际增加,则左连接 merge 会将行复制到更大表的级别。
  • @Parfait 谢谢,我现在注意到 OP 也有重复 Tag4。我将最初的问题理解为,在年龄、位置等发生变化时复制行是真正需要的。这种假设可能是错误的。
  • 嗨,澄清一下,我的代码中的 Tag4 重复是一个错字,修复并没有改变手头的问题。此外,对于每个唯一的客户,年龄、位置等都是唯一的,因此对于每个单独的交易,这些值不会改变,但是这些行需要这些值。我正在尝试此处给出的第一个解决方案,并且在过去 20 分钟内它仍在合并 df1、df2。稍后会更新结果。
  • 此解决方案导致 tag_cols、customer_ID 和进入时间值中的值总和正确,但所有其他列(如年龄、性别、位置、值 1,2 等)都填充了 NaN对于 df 中的所有行。我一直无法弄清楚为什么会这样。
  • @sethds 很有趣。在这种情况下,我默认 Parfait 的更优雅的解决方案。
猜你喜欢
  • 2019-04-09
  • 2018-09-21
  • 2014-06-17
  • 2013-12-15
  • 1970-01-01
  • 2019-09-29
相关资源
最近更新 更多