Padas交叉表新增二级分类小计

Padas的pivot_table做交叉表变换后支持总计功能,但是分类的小计功能需要自己动手实现。
在实现这个小计的功能时,好好研究了下交叉表的属性,写了下开发流程,当初走了点弯路,总结如下:

下图是开发前手写的流程:

按着这个流程开发到中途遇到点麻烦,又转而尝试了其它方式,因为我们的应用是把交叉表导出到html, 调用了to_html方法,所以,想直接在导出的html字符串上面插入小计,最后确认这种注入方式有三个问题:首先不通用,就算实现了注入小计到导出的html,但是支持交叉表下载到excel文件还是没有小计功能(这个是主要问题),其次对字符串操作效率太低,遇到大的交叉表,开销过大,最后实现起来很麻烦,因为交叉表的变化随着index,column,metric的参数不同而不同,相应的导出的html结构也会变化,很难保证不出异常。
所以最后还是放弃这种尝试,直接操作pandas来变换实现才是最直接,一劳永逸的方式。
直接贴代码吧:

def add_subtotal(self, pivot_table):
        indexs = pivot_table.index
        names = indexs.names
        if len(names) < 2:
            return pivot_table
        else:
            columns = pivot_table.columns
            levels = pivot_table.index.levels[0]
            table_splites = []
            for loc in levels:
                loc_rows = pivot_table.loc[loc]
                if loc_rows.shape[0] <= 1:
                    loc_rows = loc_rows.reset_index()
                    loc_rows.insert(0, names[0], loc)
                    table_splites.append(loc_rows)
                    continue
                if loc == '_Total':
                    loc_rows = loc_rows.reset_index()
                    loc_rows.insert(0, names[0], '_Total')
                    table_splites.append(loc_rows)
                    continue
                
                total_row = loc_rows[columns].sum()
                total_row = pd.DataFrame(data=total_row).T
                total_row.index = ['_Subtotal']
                loc_rows = loc_rows.reset_index()
                
                rev_names = names[::-1]
                first_name = rev_names[-1]
                second_name = rev_names[-2]
                for name in rev_names[:-1]:
                    if name != second_name:
                        _value = ''
                    else:
                        _value = '_Subtotal'
                    total_row.insert(0, name, _value)
                loc_rows = loc_rows.append(total_row)
                loc_rows.insert(0, first_name, loc)
                table_splites.append(loc_rows)
        result = pd.concat(table_splites, ignore_index=True)
        return result.pivot_table(index=names)

这段代码单独抽出来独立为PivotTable类的一个实力方法,参数为做过交叉表变换后的df(dataframe)对象,返回的也是一个添加了小计后的df。

如果只有一个Rows,则肯定是不需要分类小计的情况,只有总计_Total。

当Row大于一个后:

效果如上。

二级下多于一项才会出现_Subtotal小计行。

导出交叉表到excel,如下:

到此就实现了交叉表新增分类小计功能和导出带有小计功能。

千里之行始于足下,成长就是守护和付出的过程,人生苦短,我用Python。
原文地址:https://www.cnblogs.com/JustToNight/p/7518962.html