根据不同列的多个过滤器聚合 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
.
注意* 即:
event == X
在 caller
部分中可能连续或不连续。
- 有些情况下
event == X
可能根本不在某些 caller
部分中。
- 可能存在像
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
- 与 Quang 的方法类似,您可以使用
cumsum()
分成 'caller' 个部分。 cumsum
和 cumcount
对分类很有用。
- 然后,使用
mask
有条件地 join
分组 value
如果等于 x
-- 否则什么都不做。
- 最后,
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
起始 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
.
注意* 即:
event == X
在caller
部分中可能连续或不连续。- 有些情况下
event == X
可能根本不在某些caller
部分中。 - 可能存在像
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
- 与 Quang 的方法类似,您可以使用
cumsum()
分成 'caller' 个部分。cumsum
和cumcount
对分类很有用。 - 然后,使用
mask
有条件地join
分组value
如果等于x
-- 否则什么都不做。 - 最后,
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