Pandas透视表与条件aggfunc

时间:2017-09-02 09:30:44

标签: python pandas pivot-table

我的pandas数据框如下:

df = pd.DataFrame({"PAR NAME":['abc','def','def','def','abc'], "value":[1,2,3,4,5],"DESTCD":['E','N','E','E','S']})

我需要为PAR NAME调整df,并找出其价值的%年龄来自DESTCD为E'的地方。像这样的东西(显然没有用!)

df.pivot_table(index="PAR NAME",values=["value"],aggfunc={'value':lambda x: (x.sum() if x["DESTCD"]=="E")*100.0/x.sum()})

我目前正在通过添加条件列然后将其与“'值”相加来实现此目的。在枢轴然后划分,但我的数据库是巨大的(1gb +),并且必须有一个更简单的方法。

编辑:预期输出 abc 16.67(因为abc和E是总abc中的1,即6) def 77.78(因为def和E是总def的9中的7);

(注意:请不要建议切割多个数据帧,因为我提到的数据很大,效率很高:))

3 个答案:

答案 0 :(得分:1)

您可以使用基于PAR NAME的多个groupby方法代替数据透视表,然后应用所需的操作。即

new = df[df['DESTCD']=='E'].groupby('PAR NAME')['value'].sum()*100/df.groupby('PAR NAME')['value'].sum()

输出:

PAR NAME
abc    16.666667
def    77.777778
Name: value, dtype: float64

如果你想要时间

%%timeit

df[df['DESTCD']=='E'].groupby('PAR NAME')['value'].sum()*100/df.groupby('PAR NAME')['value'].sum()
100 loops, best of 3: 4.03 ms per loop

%%timeit
df = pd.concat([df]*10000)
df[df['DESTCD']=='E'].groupby('PAR NAME')['value'].sum()*100/df.groupby('PAR NAME')['value'].sum()

100 loops, best of 3: 15.6 ms per loop

答案 1 :(得分:1)

我试图在没有特别引用“E”的情况下解决问题,因此它可以推广到任何字母。输出是一个数据帧,然后您可以在E上索引以获得答案。我只是单独进行聚合,然后使用有效的连接方法。

df = pd.DataFrame({"PAR NAME":['abc','def','def','def','abc'], "value":[1,2,3,4,5],"DESTCD":['E','N','E','E','S']})

# First groupby 'DESTCD' and 'PAR NAME'
gb = df.groupby(['DESTCD', 'PAR NAME'], as_index=False).sum()
print(gb)
  DESTCD PAR NAME  value
0      E      abc      1
1      E      def      7
2      N      def      2
3      S      abc      5

gb_parname = gb.groupby(['PAR NAME']).sum()
out = gb.join(gb_parname, on='PAR NAME', rsuffix='Total')
print(out)
  DESTCD PAR NAME  value  valueTotal
0      E      abc      1           6
1      E      def      7           9
2      N      def      2           9
3      S      abc      5           6

out.loc[:, 'derived']= out.apply(lambda df: df.value/df.valueTotal, axis=1)

print(out)
  DESTCD PAR NAME  value  valueTotal   derived
0      E      abc      1           6  0.166667
1      E      def      7           9  0.777778
2      N      def      2           9  0.222222
3      S      abc      5           6  0.833333

这也是一项相对有效的操作

%%timeit
gb = df.groupby(['DESTCD', 'PAR NAME'], as_index=False).sum()
gb_parname = gb.groupby(['PAR NAME']).sum()
out = gb.join(gb_parname, on='PAR NAME', rsuffix='Total')
out.loc[:, 'derived']= out.apply(lambda df: df.value/df.valueTotal, axis=1)
100 loops, best of 3: 6.31 ms per loop

答案 2 :(得分:1)

我还找到了一种通过枢轴回答问题的方法,它与所选答案一样有效!为方便他人而添加:

df.pivot_table(index="PAR NAME",values=["value"],aggfunc={'value':lambda x: x[df.iloc[x.index]['DESTCD']=='E'].sum()*100.0/x.sum()})

逻辑是aggfunc只适用于有问题的系列,并且在你通过索引主df得到它们之前不能引用任何其他系列。