Pandas:聚合后加入分组键
Pandas: join on grouping keys after aggregation
我有什么
我有这样一个 pandas 框架:
df1 = pd.DataFrame({
'date': ['31-05-2017', '31-05-2017', '31-05-2017', '31-05-2017', '01-06-2017', '01-06-2017'],
'tag': ['A', 'B', 'B', 'B', 'A', 'A'],
'metric1': [0, 0, 0, 1, 1, 1],
'metric2': [0, 1, 1, 0, 1, 0]
})
df2 = pd.DataFrame({
'date': ['31-05-2017', '31-05-2017', '01-06-2017'],
'tag': ['A', 'B', 'A'],
'metric3': [25, 3, 7,]
})
我想要的
1) 我想对 date
和 tag
的每个组合求和 metric
和 metric_2
2) 计算 1
在 metric_2
中的条目百分比
3) 将分组的 df1 与 df2 合并,这样我每个 date
和 tag
都有 metric_3
date | tag | metric1_sum | metric2_sum | metric2_percentage| metric 3
-----------|-----|-------------|-------------|-------------------|---------
31-05-2017 | A | 0 | 0 | 0 | 25
31-05-2017 | B | 1 | 2 | 0.667 | 3
01-06-2017 | A | 1 | 0 | 0.5 | 7
尝试次数
(1) 分组求和
>>> g = df1.groupby(['date', 'tag']).agg(sum)
>>> g
metric1 metric2
date tag
01-06-2017 A 2 1
31-05-2017 A 0 0
B 1 2
(2) 计算百分比有效,但将其添加为列无效
我用了posted here的方法来计算百分比。
>>> g2 = df1.groupby(['date', 'tag']).agg({'metric2': 'sum'})
>>> g2.groupby(level=0).apply(lambda x: x/float(x.sum()))
metric2
date tag
01-06-2017 A 1.0
31-05-2017 A 0.0
B 1.0
但是,我现在如何将这个分组的 metric2
分配给我的组 g
或我的 df1
中的列 metric2_percentage
?
(3) 合并失败
加入小组显然行不通:
>>> pd.merge(g, df2, how='left', on=['date', 'tag'])
KeyError: 'date'
然后如何将 df1
减少到每组一行,以便我可以将其与 df2
合并?
g
有 date, tag
作为索引,而 merge
需要列,你需要 reset_index on g
:
pd.merge(g.reset_index(), df2, how='left', on=['date', 'tag'])
或指定left_index = True
:
pd.merge(g, df2, how='left', left_index=True, right_on=['date', 'tag'])
两者都给出结果(列顺序略有不同):
# date tag metric1 metric2 metric3
#0 01-06-2017 A 2 1 7
#1 31-05-2017 A 0 0 25
#2 31-05-2017 B 1 2 3
这是一种替代方法,它可以减少一次连接来完成您的工作:
(df1.groupby(['date', 'tag']).apply(
lambda g: pd.Series({'metric1_sum': g.metric1.sum(),
'metric2_sum': g.metric2.sum(),
'metric2_percentage': g.metric2.mean()})
# assumed here you have only 1 and 0 in metric 2 column if not use your own lambda function
).reset_index().merge(df2, how='left', on=['date', 'tag']))
# date tag metric1_sum metric2_percentage metric2_sum metric3
#0 01-06-2017 A 2.0 0.500000 1.0 7
#1 31-05-2017 A 0.0 0.000000 0.0 25
#2 31-05-2017 B 1.0 0.666667 2.0 3
使用agg
。 mean
的 1 和 0 将与百分比相同。
cols = ['date', 'tag']
d1 = df1.groupby(cols).agg(
dict(metric1='sum', metric2=['sum', 'mean'])
)
d1.columns = d1.columns.map('_'.join)
d1.join(df2.set_index(cols))
date tag metric1_sum metric2_sum metric2_mean metric3
0 01-06-2017 A 2 1 0.500000 7
1 31-05-2017 A 0 0 0.000000 25
2 31-05-2017 B 1 2 0.666667 3
为了单行而过度设计
from collections import OrderedDict
df1.groupby(['date', 'tag']).agg(
dict(metric1='sum', metric2=['sum', 'mean'])
).pipe(
lambda d: pd.DataFrame(OrderedDict({'_'.join(k): v for k, v in d.iteritems()}))
).join(df2.set_index(['date', 'tag'])).reset_index()
date tag metric1_sum metric2_sum metric2_mean metric3
0 01-06-2017 A 2 1 0.500000 7
1 31-05-2017 A 0 0 0.000000 25
2 31-05-2017 B 1 2 0.666667 3
我有什么
我有这样一个 pandas 框架:
df1 = pd.DataFrame({
'date': ['31-05-2017', '31-05-2017', '31-05-2017', '31-05-2017', '01-06-2017', '01-06-2017'],
'tag': ['A', 'B', 'B', 'B', 'A', 'A'],
'metric1': [0, 0, 0, 1, 1, 1],
'metric2': [0, 1, 1, 0, 1, 0]
})
df2 = pd.DataFrame({
'date': ['31-05-2017', '31-05-2017', '01-06-2017'],
'tag': ['A', 'B', 'A'],
'metric3': [25, 3, 7,]
})
我想要的
1) 我想对 date
和 tag
metric
和 metric_2
2) 计算 1
在 metric_2
3) 将分组的 df1 与 df2 合并,这样我每个 date
和 tag
metric_3
date | tag | metric1_sum | metric2_sum | metric2_percentage| metric 3
-----------|-----|-------------|-------------|-------------------|---------
31-05-2017 | A | 0 | 0 | 0 | 25
31-05-2017 | B | 1 | 2 | 0.667 | 3
01-06-2017 | A | 1 | 0 | 0.5 | 7
尝试次数
(1) 分组求和
>>> g = df1.groupby(['date', 'tag']).agg(sum)
>>> g
metric1 metric2
date tag
01-06-2017 A 2 1
31-05-2017 A 0 0
B 1 2
(2) 计算百分比有效,但将其添加为列无效
我用了posted here的方法来计算百分比。
>>> g2 = df1.groupby(['date', 'tag']).agg({'metric2': 'sum'})
>>> g2.groupby(level=0).apply(lambda x: x/float(x.sum()))
metric2
date tag
01-06-2017 A 1.0
31-05-2017 A 0.0
B 1.0
但是,我现在如何将这个分组的 metric2
分配给我的组 g
或我的 df1
中的列 metric2_percentage
?
(3) 合并失败
加入小组显然行不通:
>>> pd.merge(g, df2, how='left', on=['date', 'tag'])
KeyError: 'date'
然后如何将 df1
减少到每组一行,以便我可以将其与 df2
合并?
g
有 date, tag
作为索引,而 merge
需要列,你需要 reset_index on g
:
pd.merge(g.reset_index(), df2, how='left', on=['date', 'tag'])
或指定left_index = True
:
pd.merge(g, df2, how='left', left_index=True, right_on=['date', 'tag'])
两者都给出结果(列顺序略有不同):
# date tag metric1 metric2 metric3
#0 01-06-2017 A 2 1 7
#1 31-05-2017 A 0 0 25
#2 31-05-2017 B 1 2 3
这是一种替代方法,它可以减少一次连接来完成您的工作:
(df1.groupby(['date', 'tag']).apply(
lambda g: pd.Series({'metric1_sum': g.metric1.sum(),
'metric2_sum': g.metric2.sum(),
'metric2_percentage': g.metric2.mean()})
# assumed here you have only 1 and 0 in metric 2 column if not use your own lambda function
).reset_index().merge(df2, how='left', on=['date', 'tag']))
# date tag metric1_sum metric2_percentage metric2_sum metric3
#0 01-06-2017 A 2.0 0.500000 1.0 7
#1 31-05-2017 A 0.0 0.000000 0.0 25
#2 31-05-2017 B 1.0 0.666667 2.0 3
使用agg
。 mean
的 1 和 0 将与百分比相同。
cols = ['date', 'tag']
d1 = df1.groupby(cols).agg(
dict(metric1='sum', metric2=['sum', 'mean'])
)
d1.columns = d1.columns.map('_'.join)
d1.join(df2.set_index(cols))
date tag metric1_sum metric2_sum metric2_mean metric3
0 01-06-2017 A 2 1 0.500000 7
1 31-05-2017 A 0 0 0.000000 25
2 31-05-2017 B 1 2 0.666667 3
为了单行而过度设计
from collections import OrderedDict
df1.groupby(['date', 'tag']).agg(
dict(metric1='sum', metric2=['sum', 'mean'])
).pipe(
lambda d: pd.DataFrame(OrderedDict({'_'.join(k): v for k, v in d.iteritems()}))
).join(df2.set_index(['date', 'tag'])).reset_index()
date tag metric1_sum metric2_sum metric2_mean metric3
0 01-06-2017 A 2 1 0.500000 7
1 31-05-2017 A 0 0 0.000000 25
2 31-05-2017 B 1 2 0.666667 3