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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容