【问题标题】:Filter groups after GroupBy in pandas while keeping the groups在 Pandas 中的 GroupBy 之后过滤组,同时保留组
【发布时间】:2018-09-24 16:28:26
【问题描述】:

在熊猫中我想做: df.groupby('A').filter(lambda x: x.name > 0) - 按列分组 A 然后过滤名称值为非正数的组。但是,这会取消分组,因为 GroupBy.filter 返回 DataFrame 并因此丢失分组。我想按此顺序执行此操作,因为它对计算的要求应该较低,因为 filter 后跟 groupby 将不会遍历 DataFrame 两次(首先过滤然后分组)?此外,从分组中克隆组(到 dict 或其他内容)会使我失去无缝返回数据帧的功能(例如在 .filter 的示例中,您可以直接获得 DataFrame

谢谢

例子:

   A  B
1 -1  1
2 -1  2
3  0  2
4  1  1
5  1  2

df.groupby('A'):

GroupBy object
-1 : [1, 2]
 0 : [3]
 1 : [4,5]

GroupBy.filter(lambda x: x.name >= 0):

GroupBy object
 0 : [3]
 1 : [4,5]

【问题讨论】:

  • 你能在这里放一个数据框数据的示例吗? :)
  • 为什么不简单地按df而不是df[df['A'] > 0]进行分组?
  • 因为我希望这将花费两倍于第一次分组然后过滤组的时间,因为我会过滤假设 10 个组而不是 100 万行
  • 好吧有道理:)

标签: python pandas pandas-groupby


【解决方案1】:

使用groupby 实际上不会以任何方式聚合这些值。它只是创建分组,因此filter 本质上是在原始数据帧上进行过滤。我认为您不会通过先分组来节省时间或计算量,除非 name 是通过将函数应用于组来实现的价值。

所以我会推荐类似的东西

df.where(df.name > 0).groupby('A')  # now apply some transformation to the groups

【讨论】:

  • 但是为了创建你需要遍历整个数据框的组,不是吗?我的意思是,如果你groupby 你必须检查每一行,如果你过滤数据框,那么它也需要对整个数据框进行两次迭代,但是如果我只过滤我在整个数据框上遍历一次的组,但是然后只在组上
【解决方案2】:

让我们运行一些计时。

df = pd.DataFrame({'A':np.random.randint(-10,10,1000000),'B':np.random.random(1000000)})

测试两个返回是否相等

df1 = df.groupby('A').filter(lambda x: x.name >= 0)
df2 = df[df.A >= 0]

all(df1 == df2)
True

时间安排:

%timeit df1 = df.groupby('A').filter(lambda x: x.name >= 0)

每个循环 607 毫秒 ± 10.2 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

%timeit df2 = df[df.A >= 0]

每个循环 59.7 ms ± 724 µs(7 次运行的平均值 ± 标准偏差,每次 10 个循环)

@jacquot 解决方案看起来比分组然后过滤快 10 倍。

【讨论】:

  • 这不是我所说的。我说过按组名过滤 10 个组比过滤整个数据集然后将整个数据集分组为过滤和分组(我假设)都是线性时间操作更快。但是,如果我尝试您的示例,那么 df[df.A >= 0].groupby('A'){name:group for name,group in df.groupby('A').groups.items() if name >= 0} 之类的要快,所以我想我不必担心这个速度。
【解决方案3】:

我认为以前的答案提出了解决方法,这可能对您的情况有用,但不能回答问题。

您创建了组,并且您想根据组统计信息丢弃或保留一些组,然后对组执行一些您真正关心的组统计信息。这应该是可能的,并且在许多情况下很有用,但是,只有当您因此使用两个相同的 groupby 时,现在才可能作为链接命令(据我所知)。

让我们举个例子:Groupby 揭示了一些不可在项目级别基础上过滤的功能(因此以前的过滤不是一个选项)。例如一组总和。过滤器的烦恼是,它返回一个数据帧而不是保留分组并允许您对组执行进一步的计算。

这是一个例子:

假设您要按“C”分组并过滤组中“A”的总和(

df.groupby(['C']).filter(lambda x:x['A'].sum()<700, combine=False).std()

这不起作用(注意过滤器上不存在的combine=False 选项),这是做什么的:

df.groupby(['C']).filter(lambda x:x['A'].sum()<700).groupby(['C']).std()

filter做的其实就是filter&combine,它遵循split-apply-combine的逻辑。

【讨论】:

    【解决方案4】:

    我像 petsol 一样理解这个问题,而不是 Scott, 所以斯科特给出的例子的等价物应该是:

    df = d.DataFrame({'A':np.random.randint(-10,10,1000000),'B':np.random.random(1000000)})
    df1 = df.groupby('A').filter(lambda x: x['A'].mean()>0).groupby('A').count()
    

    而第二种方法显然行不通。

    但是,在我在这里找到这个解决方案之前,我认为它只是: Groupby 对象是否具有类似于 .iloc 的 DataFrames 方法?

    这样,当您创建一个 Groupby 对象时,您可以通过使用一些聚合函数应用条件来创建一个过滤器(并将其存储为一个布尔值,其中索引对应于每个组),然后仅在请求的组。

    不幸的是,我没有找到任何与 iloc 等效的有用方法或函数(我检查了“nth”、“take”和“get_group”,但没有一个有效)。

    【讨论】:

      猜你喜欢
      • 2018-06-25
      • 2019-09-11
      • 1970-01-01
      • 2015-02-13
      • 2022-11-04
      • 1970-01-01
      • 2013-05-30
      • 1970-01-01
      • 2018-07-01
      相关资源
      最近更新 更多