【问题标题】:Aggregate values of a column in a pandas df based on multiple filters of a different column - python2.7基于不同列的多个过滤器聚合pandas df中列的值 - python2.7
【发布时间】:2020-11-10 19:57:24
【问题描述】:

开始 pandas df 是:

df = pd.DataFrame({
    'event':['caller',  'X',  'y',   'X', 'caller', 'caller', 'z', 'z', 'X',  'X',  'w',  'X',  'y',  'X',  'z',  'caller'],
    'value':['c1',      'x1', 'yy', 'x2', 'c2',     'c3',     'zz', 'zz', 'x1', 'x2', 'ww', 'x3', 'yy', 'x4', 'z1', 'c4']
})
df
Out[24]: 
     event value
0   caller    c1
1        X    x1
2        y    yy
3        X    x2
4   caller    c2
5   caller    c3
6        z    zz
7        z    zz
8        X    x1
9        X    x2
10       w    ww
11       X    x3
12       y    yy
13       X    x4
14       z    z1
15  caller    c4

目标是将event==X 所在的所有值汇总到一个value 中,这可能是(或不是!)每个部分其中event==caller

注意*:

  1. event == Xcaller 部分中可能是连续的,也可能不是连续的。
  2. 在某些情况下,event == X 可能根本不在 caller 部分的某些部分中。
  3. 可能存在重复的情况,例如event == z。这些应该汇总。

因此,为简单起见,仅应聚合可能出现在 caller 部分中任何位置的 event==X 的值。

最终的 df (`df_aggr) 应该如下所示:

df_aggr = pd.DataFrame({
    'event':['caller',  'X',     'y',    'caller', 'caller', 'z', 'z', 'X',           'w',  'y',  'z',  'caller'],
    'value':['c1',      'x1 x2', 'yy',   'c2',     'c3',     'zz', 'zz', 'x1 x2 x3 x4', 'ww', 'yy', 'z1',  'c4']
})
df_aggr
Out[28]: 
     event        value
0   caller           c1
1        X        x1 x2
2        y           yy
3   caller           c2
4   caller           c3
5        z           zz
6        z           zz
7        X  x1 x2 x3 x4
8        w           ww
9        y           yy
10       z           z1
11  caller           c4

它必须在 python2.7 和 pandas=0.15.2 上工作。

更新:

-----pandas=0.15.2的解决方案-----

根据 David 的回答,如果有人可能需要支持 pandas==0.15.2,则必须对其进行调整以适应版本之间的差异。

In [36]: df = pd.DataFrame({
    ...:     'event':['caller',  'X',  'y',   'X', 'caller', 'caller', 'z', 'z', 'X',  'X',  'w',  'X',  'y',  'X',  'z',  'caller'],
    ...:     'value':['c1',      'x1', 'yy', 'x2', 'c2',     'c3',     'zz', 'zz', 'x1', 'x2', 'ww', 'x3', 'yy', 'x4', 'z1', 'c4']
    ...: })
    ...:
    ...: s = (df['event'] == 'caller').cumsum()
    ...: df['value'] = df['value'].where(df['value'].mask(df['event'] == 'X'), df.groupby(['event', s])['value'].transform(' '.join))
    ...: df = df[~((df.duplicated()) & (df['event'] == 'X'))].reset_index(drop=True)
    ...:

In [37]: df
Out[37]:
     event        value
0   caller           c1
1        X        x1 x2
2        y           yy
3   caller           c2
4   caller           c3
5        z           zz
6        z           zz
7        X  x1 x2 x3 x4
8        w           ww
9        y           yy
10       z           z1
11  caller           c4

In [38]:

【问题讨论】:

    标签: python pandas python-2.7


    【解决方案1】:
    1. 与 Quang 的方法类似,您可以使用 cumsum() 将其分成“调用者”部分。 cumsumcumcount 对分类非常有用。
    2. 然后,如果等于x,则使用mask 有条件地join 分组value -- 否则什么也不做。
    3. 最后,drop_duplicates(),因为我们尚未删除已加入的额外行。

    df = pd.DataFrame({
        'event':['caller',  'X',  'y',   'X', 'caller', 'caller', 'z', 'z', 'X',  'X',  'w',  'X',  'y',  'X',  'z',  'caller'],
        'value':['c1',      'x1', 'yy', 'x2', 'c2',     'c3',     'zz', 'zz', 'x1', 'x2', 'ww', 'x3', 'yy', 'x4', 'z1', 'c4']
    })
    s = (df['event'] == 'caller').cumsum()
    df['value'] = df['value'].mask(df['event'] == 'X',
                                   df.groupby(['event', s])['value'].transform(' '.join))
    df = df[~((df.duplicated(keep='first')) & (df['event'] == 'X'))].reset_index(drop=True)
    df
    
    Out[1]: 
         event        value
    0   caller           c1
    1        X        x1 x2
    2        y           yy
    3   caller           c2
    4   caller           c3
    5        z           zz
    6        z           zz
    7        X  x1 x2 x3 x4
    8        w           ww
    9        y           yy
    10       z           z1
    11  caller           c4
    

    【讨论】:

    • 它“几乎”可以工作,但在event != X 时会丢弃其他重复的案例。例如,应保留 event == z 的值。我更新了帖子以使其更清晰。干杯!
    • 它不适用于我拥有的熊猫。我仅限于pandas==0.15.2。它会生成此错误:TypeError: mask() takes exactly 2 arguments (3 given) .
    【解决方案2】:

    在检查caller 时使用cumsum 来识别会话和groupby:

    (df.groupby([df.event.eq('caller').cumsum(),
                'event'])['value'].agg(' '.join)
       .reset_index(level=1)
       .reset_index(drop=True)
    )
    

    注意这将在一个会话中将所有value 与相同的event 连接起来,即如果您有两个z,那么这些行的两个value 将被连接起来。将df.event.ne('x').cumsum() 放入groupby 以仅对x 的块进行分组:

    (df.groupby([df.event.eq('caller').cumsum(),
                df.event.ne('x').cumsum(),
                      'event'
                     ])['value'].agg(' '.join)
       .reset_index(level=-1)
       .reset_index(drop=True)
    )
    

    输出:

        event  value
    0  caller     c1
    1       x     x1
    2       y     yy
    3  caller     c2
    4  caller     c3
    5       x  x1 x2
    6       z     z1
    7  caller     c4
    

    【讨论】:

    • 只有当event==X 是连续事件失败时,解决方案才有效,对于event==X 的非连续情况。我更新了帖子以反映更一般的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多