我有以下数据框:
df = pd.DataFrame([[1, 2, True], [1, 4, False], [2, 6, False], [2, 8, True]], columns=["Group", "Value", "C"])
Group Value C
0 1 2 True
1 1 4 False
2 2 6 False
3 2 8 True
我想让每个小组都知道值的总和,其中C等于值的总和。例如,对于第1组,我们有2 /(2 + 4)
我已经进行了广泛的搜索以达到以下阶段:
df.groupby('Group').agg(lambda x: x.loc[x.C == True, 'Value'].sum() / x.Value.sum())
Value C
Group
1 0.333333 0.333333
2 0.571429 0.571429
但是(如预期的那样)我得到两列,而我只想得到一列。我理想的结果是:
Ratio
Group
1 0.333333
2 0.571429
我肯定可以在groupby之后进行一些修改并得到我想要的东西,但是由于我是Python的新手,所以我想知道我是否在这里缺少一些基本知识。
答案 0 :(得分:2)
我相信您可以对groupby.transform()
进行除法运算,并在过滤后使用.assign()
进行赋值,以便与索引对齐:
df[df['C']].assign(Ratio=df['Value']/df.groupby('Group')['Value'].transform('sum'))
如果每个组的True大于1,请使用:
m=(df.groupby(['Group','C'],as_index=False,sort=False)['Value'].sum()
.query('C==True').assign(Sum=df.groupby(['Group'])['Value'].transform('sum')))
m[['Group']].assign(Ratio=m['Value']/m['Sum'])
Group Ratio
0 1 0.333333
3 2 0.571429
答案 1 :(得分:2)
您可以按过滤后的行除以所有行,然后将Series转换为一列DataFrame
:
filt = df.loc[df['C']].groupby('Group')['Value'].sum()
tot = df.groupby('Group')['Value'].sum()
df1 = filt.div(tot, fill_value=0).to_frame('ratio')
print (df1)
ratio
Group
1 0.333333
2 0.571429
通过更改.agg
处理所有列到GroupBy.apply
以获得返回值Series
,您的解决方案是可能的,但是如果有大数据/许多唯一组,它应该很慢:
df = (df.groupby('Group')
.apply(lambda x: x.loc[x.C, 'Value'].sum() / x.Value.sum())
.to_frame('ratio'))
print (df)
ratio
Group
1 0.333333
2 0.571429
仅False
组的解决方案也能很好地工作:
df = pd.DataFrame([[0, 2, False], [1, 2, True], [1, 4, False],
[2, 6, False], [2, 8, True]], columns=["Group", "Value", "C"])
df1 = (df.groupby('Group')
.apply(lambda x: x.loc[x.C, 'Value'].sum() / x.Value.sum())
.to_frame('ratio'))
print (df1)
ratio
Group
0 0.000000
1 0.333333
2 0.571429
filt = df.loc[df['C']].groupby('Group')['Value'].sum()
tot = df.groupby('Group')['Value'].sum()
print (df1)
ratio
Group
0 0.000000
1 0.333333
2 0.571429
答案 2 :(得分:1)
您可以使用apply:
result = df.groupby('Group').apply(lambda x: pd.Series({'ratio' : (x.Value * x.C).sum() / x.Value.sum()}))
print(result)
输出
ratio
Group
1 0.333333
2 0.571429