根据不同列的多个过滤器聚合 pandas df 中一列的值 - python2.7

Aggregate values of a column in a pandas df based on multiple filters of a different column - python2.7

起始 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 这样的重复案例。这些应该聚合。

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

最后的 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]:

在检查 caller 时使用 cumsum 来识别会话和分组依据:

(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
  1. 与 Quang 的方法类似,您可以使用 cumsum() 分成 'caller' 个部分。 cumsumcumcount 对分类很有用。
  2. 然后,使用 mask 有条件地 join 分组 value 如果等于 x -- 否则什么都不做。
  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