如何使用两个不同的聚合创建数据透视表

时间:2019-10-03 08:10:33

标签: python pandas pivot pandas-groupby

我有一个数据集,我想在该数据集上运行多个聚合步骤。这段代码创建数据:

import pandas as pd
import numpy as np

df1 = pd.DataFrame({'Name': ['A', 'A', 'B', 'B'],
                    'S': [200, 100, 300, 400],
                    'Date': pd.to_datetime(['2019-01-01', '2019-01-01', '2019-02-01', '2019-03-01']).date,
                    'Value': [5, 10, 30, 40]})

收益:

df1: 
  Name    S        Date  Value
0    A  200  2019-01-01      5
1    A  100  2019-01-01     10
2    B  300  2019-02-01     30
3    B  400  2019-03-01     40

汇总的最终结果应如下所示:

                2019-01-01  2019-02-01  2019-03-01
A   100, 200            15      
B   300 - 400                       30          40

我要做的第一步是

df2 = df.groupby(by=['Name', 'Date']).agg({'S': lambda x: ', '
                             .join(pd.DataFrame([str(s) for s in x]).drop_duplicates()
                                                                    .sort_values(by=0)
                                                                    .iloc[:, 0]
                                                                    .map(str)),
                            'Value': np.sum,})

.join(...)部分有些复杂,但是取S中的数字,删除重复项,对其进行排序并将其连接为字符串。

结果是这样的:

df2: 
                        S  Value
Name Date                       
A    2019-01-01  100, 200     15
B    2019-02-01       300     30
     2019-03-01       400     40

现在我被困住了。我可以生成以下内容:

df3 = (df2.pivot_table('Value', index=['Name', 'S'], columns=['Date'], 
                      aggfunc={'Value': np.sum})
                    .fillna(0)
                    .reset_index()
                    )
df3: 
Date Name         S  2019-01-01  2019-02-01  2019-03-01
0       A  100, 200        15.0         0.0         0.0
1       B       300         0.0        30.0         0.0
2       B       400         0.0         0.0        40.0

但是,我希望将最后两行合并,S变成300 - 400(类似于df2的联接)。我尚未发现如何将这些聚合合并为一个步骤(混合groupbypivot_table)。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

尝试一下:

val=df1.groupby(['Name','Date'])['Value'].sum().reset_index() # get aggregate sum of values
ind=df1.groupby('Name').apply(lambda x: '-'.join([str(i) for i in x.S.values])).reset_index() # Prepare index for target dataframe
target_df=ind.merge(val, on=['Name']).pivot_table(index=['Name', 0], columns=['Date'], values='Value').fillna(0) # Merge both and pivot to get desired output

然后,print(target_df)提供所需的输出:

Date          2019-01-01  2019-02-01  2019-03-01
Name 0                                          
A    200-100        15.0         0.0         0.0
B    300-400         0.0        30.0        40.0

答案 1 :(得分:0)

@Parth给出了正确的见解,不可能同时执行两个步骤(汇总数字和pivot_table数据,并同时运行groupby),但是您必须分开创建未来索引,然后对数据进行透视。

这是我的最终代码(与@parth的代码略有不同):

import pandas as pd
import numpy as np

df1 = pd.DataFrame({'Name': ['A', 'A', 'B', 'B'],
                    'S': [200, 100, 300, 400],
                    'Date': pd.to_datetime(['2019-01-01', '2019-01-01', '2019-02-01', '2019-03-01']).date,
                    'Value': [5, 10, 30, 40]})

print('df1: \n', df1, '\n')

df2 = df.groupby(by=['Name', 'Date']).agg({'S': lambda x: ', '
                             .join(pd.DataFrame([str(s) for s in x]).drop_duplicates()
                                                                    .sort_values(by=0)
                                                                    .iloc[:, 0]
                                                                    .map(str)),
                            'Value': np.sum,})
print('df2:\n ', df2, '\n')

ind = (df2.groupby(by=['Name']).agg({'S': lambda x: ' - '.join(pd.DataFrame([str(s) for s in x])
                                                          .drop_duplicates()
                                                          .sort_values(by=0)
                                                          .iloc[:, 0]
                                                          .map(str))})
                             .reset_index())
print('ind:\n', ind, '\n')

val = df1.groupby(['Name','Date'])['Value'].sum().reset_index() # get aggregate sum of values
print('val:\n', val, '\n')

df3 = (ind.merge(val, on=['Name'])
          .pivot_table(index=['Name', 'S'], columns=['Date'], values='Value')
          .fillna(0)
          )
print('df3\n', df3)