pandas+PowerBI处理帕累托(ABC)分析图表

帕累托动图.png

背景

1.笔者在搭建看板时发现一个板块涉及两个以上相似布局的柱状图,容易产生头晕的感觉,使得注意力无法集中,更别提让业务部同事能一眼看到当前业务问题。帕累托图表则很好地解决了这一点。2.当初想直接用PowerBI的DaX做,但很难查到适合自己的教程,要么太简单不满足自身场景,要么太难完全看不懂,索性用pandas处理了。3.总结一些时间处理的问题。曾有段时间比较忙,这一块没和同事解释清楚,让他慢慢啃,他最后也没懂。关键是当我坐他电脑旁想教他时,自己一时半会儿也看不懂自己写的东西,结果这一块数据处理流程就没教了,这回复盘一下流程。

基本要求

image.png

帕累托图表可有效地、快速地定位某一指标下降或上升的主要细分类别。上图黄色框标识是我们想要达到的效果,并且有以下四种要求:1.产品线(远程心电等...)的数据需要保留,以供PowerBI的数据模型产生连接。2.帕累托图表应包含减少和增加的两种类型。3.保留其他月份的数据。比如本次数据截止到2022-10-14。若进行同期对比,除了调用2021的数据,还应去除2021-10-15至2021-10-31的数据。否则,当选择其他月份时,则看不到表格中的数据。
image.png

处理基础数据

import pandas as pd
import numpy as np
df = pd.read_csv(r'alldata(随机抽15万样本).csv',low_memory=False)
df['时间戳']= pd.to_datetime(df['时间戳'])
df['年度'] = (df['时间戳'].dt.year).astype(str)
df['月度'] = df['时间戳'].dt.year.astype(str)+'/'+df['时间戳'].dt.month.astype(str)
df['月度'] = pd.to_datetime(df['月度'],format='%Y/%M').dt.strftime('%Y-%M')
df
image.png

处理时间

·首先构造每年月末的Series

DateIndex = pd.date_range('2022-01-01','2022-12-31',freq='M')
DateIndex_2021 = pd.date_range('2021-01-01','2021-12-31',freq='M')
DateIndex,DateIndex_2021
image.png

·写条件分支
当数据未更新到本月最后一天时,直接选择2021和2022年的数据。
否则,选择更新日到月底的数据。如何选择?基本思路为,df[~((df['时间']>更新日)&(df['时间]<更新日下一个月份的一号))&(df['年度']==2021)],注意加粗的为一个整体。

更新日为4.28,取它的month-1 = 3,3索引在DateIndex_2021所对应的值为2021-4-30加一天则为2021-05-01。1.为什么不直接选每月初的一号,写这教程的时候,顺便去网上看了下,依旧没有理想的资料。2.为什么用不用 ≤ 而用<。pandas处理年、月没什么问题,一旦涉及日期相关的数据,结果可能会出现错误,用 < 符号比较稳妥

DateIndex = pd.date_range('2022-01-01','2022-12-31',freq='M')
DateIndex_2021 = pd.date_range('2021-01-01','2021-12-31',freq='M')

#DateIndexString = DateIndex.astype(str)

if pd.Series(str(df['时间戳'].max())[:10]).isin(DateIndex)[0]:#如果当前月未走完
    df_recentyear = df[(df['年度']=='2021')|(df['年度']=='2022')]
    
    df_recentyear['月份'] = df_recentyear['诊断时间'].dt.month

else:
    same_2021 = (df[~((df['时间戳']>='2021-{}'.format(str(df['时间戳'].max()+pd.DateOffset(days=1))[5:10]))
                &(df['时间戳']<str(DateIndex_2021[df['时间戳'].max().month-1]+pd.DateOffset(days=1))[:10]))
                &(df['年度']=='2021')]
                )

    same_2022 = df[(df['时间戳']>='2022-01-01')
                &(df['时间戳']<str(df['时间戳'].max()+ pd.DateOffset(days=1))[:10])
                  ]

    df_recentyear = pd.concat([same_2021,same_2022])
    
    df_recentyear['月份'] = df_recentyear['时间戳'].dt.month

处理帕累托

做透视表

按【行】城市、产品、月份,【列】年度铺成透视表,然后新增列计算差值,其中差值既有大于0,也有小于0的记录。

(df_recentyear
    .pipe(lambda x:pd.crosstab([x['城市'],x['产品'],x['月份']],x['年度']))
    .reset_index()
 
    .assign(差值 = lambda x:x['2022']-x['2021'])
)
image.png

筛选小于0,即同期减少的数据,并分组求和

求和的是差值,分组的城市、产品、月份,最后还要记得排序

(df_recentyear
    .pipe(lambda x:pd.crosstab([x['城市'],x['产品'],x['月份']],x['年度']))
    .reset_index()
 
    .assign(差值 = lambda x:x['2022']-x['2021'])
    .query("差值<0")

    .groupby(['城市','产品','月份'])
    .agg(**{'城市差值':pd.NamedAgg(column='差值',aggfunc='sum'),
           }
                 )
    .reset_index()
    .sort_values(by='城市差值')
).query("月份==4 and 产品=='A'")
image.png

查看4月份产品A的数据结构

接着处理不同城市、产品、月份差值总计,并计算百分比和累计百分比

ABC_city = (df_recentyear
    .pipe(lambda x:pd.crosstab([x['城市'],x['产品'],x['月份']],x['年度']))
    .reset_index()
 
    .assign(差值 = lambda x:x['2022']-x['2021'])
    .query("差值<0")

    
    .groupby(['城市','产品','月份'])
    .agg(**{'城市差值':pd.NamedAgg(column='差值',aggfunc='sum'),
           }
                 )
    .reset_index()
    .sort_values(by='城市差值')
 
    .assign(总计 = lambda x:x.groupby(['产品','月份'])['城市差值'].transform('sum')
            ,百分比 = lambda x:x['城市差值']/x['总计'])

 
    .assign(累计百分比 = lambda x:x.groupby(['产品','月份'])['百分比'].cumsum())
)##['城市差值'].sum()
ABC_city.query("月份==4 and 产品=='A'")
image.png

到这里,2021和2022的列不见了。

最后验证数据,处理成最终想要达到的效果

再做一个透视表,并用ABC_city对它进行左连接,那最终的结果decrease_ABC就是同期减少的数据

city_sametime = pd.crosstab([df_recentyear['城市']
             ,df_recentyear['产品']
             ,df_recentyear['月份']
                ]
                ,df_recentyear['年度']
               ).reset_index()

decrease_ABC = ABC_city.merge(city_sametime).assign(类型='减少')
decrease_ABC#.query("月份==4 and 产品=='A'")
image.png

使用相同方法,构造一份差值>0的数据

image.png

剩下的步骤一摸一样,最后用concat进行拼接即可

image.png

最后PowerBI里面拖拽一下,给累计百分比增加个ABC的类型即可

image.png

总结

用pandas处理一次帕累托(ABC)图表不是那么容易,中间不少求和运算、排序操作比较绕。

不足

可以加一根柱子来表示影响本次增加或减少的用户究竟有多少个?


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容