一场pandas与SQL的巅峰大战(五)
liuian 2025-05-14 14:51 38 浏览
本文目录:
数据准备
MySQL 计算累计百分比
1.不分组情况
2.分组情况
Hive SQL计算累计百分比
1.不分组情况
2.分组情况
pandas计算累计百分比
1.不分组情况
cumsum函数
expanding函数
rolling函数
2.分组情况
cumsum函数
expanding函数
rolling函数
小结
在之前的四篇系列文章中,我们对比了pandas和SQL在数据方面的多项操作。
具体来讲,第一篇文章一场pandas与SQL的巅峰大战涉及到数据查看,去重计数,条件选择,合并连接,分组排序等操作。
第二篇文章一场pandas与SQL的巅峰大战(二)涉及字符串处理,窗口函数,行列转换,类型转换等操作。
第三篇文章一场pandas与SQL的巅峰大战(三)围绕日期操作展开,主要讨论了日期获取,日期转换,日期计算等内容。
第四篇文章一场pandas与SQL的巅峰大战(四)学习了在MySQL,Hive SQL和pandas中用多种方式计算日环比,周同比的方法。
本篇文章一起来探讨如何在SQL和pandas中计算累计百分比。仍然分别在MySQL,Hive SQL和pandas中用多种方案来实现。
◆ ◆ ◆ ◆ ◆
数据准备
我们仍然使用前一篇的orderamt数据,数据导入方式可以参考之前的内容。需要分别在MySQL,Hive,pandas中进行数据导入,在此不作赘述。在我的公众号后台回复“对比五”,可以获取本文全部代码和数据。数据的样例为:
我们的目标是,计算累计到当天的销售额占总销售额的比例。在实现时,首先分别计算出累计到当天的销售金额和总计的金额,然后就可以很方便的求出比例了。
MySQL计算累计百分比
1.不分组情况
最直观的思路是,对每一行的金额,都累加从第一行到当前行的金额。在MySQL中,可以考虑自连接的方式,但需要使用不等值连接。代码和结果如下:
select a.id, a.dt, a.orderamt, sum(b.orderamt) as cum--对b表的金额进行求和
from t_orderamt ajoin t_orderamt bon a.dt >= b.dt--使用不等值连接
group by a.id, a.dt, a.orderamt图中的cum列即是我们想要求的累加值。而所有销售金额的总计值,我们可以直接使用sum求出。
select sum(orderamt) as total
from t_orderamt结合上面的两段SQL,就可以求得累计的百分比,注意连接条件我们使用了1=1这种恒成立的方式。代码和结果如下:
select c.id, c.orderamt, c.cum, concat(round((c.cum / d.total) * 100, 2), '%') as cum_pct
from (select a.id, a.dt, a.orderamt, sum(b.orderamt) as cum
from t_orderamt ajoin t_orderamt bon a.dt >= b.dtgroup by a.id, a.dt, a.orderamt) c
left join
(select sum(orderamt) as totalfrom t_orderamt
) d on 1 = 1 2.分组情况
需要思考:我们的原始数据是两个月的数据,目前我们的算法是把两个月的销售额累计到一起算的。但在实际中可能更多会关心每天的累计销售额分别占当月的百分比。如何能按照月份分组求每组的累计百分比呢?
首先仍然是求累计金额,但要分月累计。在上面的基础上加上月份相等条件即可,从结果中可以看到,在11月和12月cum列是分别累计的。
select substr(a.dt, 1, 7) as mon, a.dt, a.orderamt, sum(b.orderamt) as cum
from t_orderamt a
join t_orderamt bon a.dt >= b.dt and substr(a.dt, 1, 7) = substr(b.dt, 1, 7)--增加了这个条件
group by substr(a.dt, 1, 7), a.dt, a.orderamt求每月总计金额的代码比较简单:
select substr(a.dt, 1, 7) as mon, sum(orderamt) as totalfrom t_orderamt agroup by substr(a.dt, 1, 7)同样的,我们把两段代码进行合并,就得到每月的累计百分比情况:
select c.mon, c.dt, c.orderamt, c.cum, d.total,concat(round((c.cum / d.total) * 100, 2), '%') as cum_pct
from(select substr(a.dt, 1, 7) as mon, a.dt, a.orderamt, sum(b.orderamt) as cum
from t_orderamt a
join t_orderamt b
on a.dt >= b.dt and substr(a.dt, 1, 7) = substr(b.dt, 1, 7)
group by substr(a.dt, 1, 7), a.dt, a.orderamt) c
left join(select substr(a.dt, 1, 7) as mon, sum(orderamt) as total
from t_orderamt a
group by substr(a.dt, 1, 7)) d on c.mon = d.monHive 计算累计百分比
1.不分组情况
Hive SQL中我们可以沿用MySQL中的思路,但需要注意,Hive 不支持在on中写不等号的连接条件,虽然可以采用where的方式改造一下,代码如下所示。但这并不是最优的方案。我们可以使用Hive中的窗口函数,很方便的计算累计值。
--where方法
select a.id, a.dt, a.orderamt, sum(b.orderamt) as cum--对b表的金额进行求和
from t_orderamt ajoin t_orderamt bon 1=1where a.dt >= b.dt--使用不等值连接
group by a.id, a.dt, a.orderamt--窗口函数select *, sum(orderamt) over(order by dt) as cum
from t_orderamt;两段代码的执行结果都如下图所示:
接下来我们重点看窗口函数的方式。在计算总计值的时候和前面MySQL的方式类似,累计百分比的计算也是需要把两部分代码结合在一起。
select c.id, c.dt, c.orderamt, c.cum, concat(round((c.cum / d.total) * 100, 2), '%') as cum_pcfrom(select *, sum(orderamt) over(order by dt) as cum from t_orderamt) cleft join(select sum(orderamt) as totalfrom t_orderamt) d on 1 = 1--在Hive中这个条件可以不写2.分组情况
分组的情况,在窗口函数里是可以用partition by直接指定分组的,见如下代码
select id, substr(dt, 1, 7) as mon, dt, orderamt,
sum(orderamt) over(partition by substr(dt, 1, 7) order by dt) as cum
from t_orderamt;可以看到,同前面的分组情况一样,在11月和12月cum列是分别累计的。
接下来也很容易就写出分组计算累计百分比的代码,结果和上面也是一致的。
select c.mon, c.dt, c.orderamt, c.cum, d.total,concat(round((c.cum / d.total) * 100, 2), '%') as cum_pct
from(select id, substr(dt, 1, 7) as mon, dt, orderamt, sum(orderamt) over(partition by substr(dt, 1, 7) order by dt) as cum
from t_orderamt) c
left join(select substr(dt, 1, 7) as mon, sum(orderamt) as total
from t_orderamt group by substr(dt, 1, 7)) d on c.mon = d.monpandas计算累计百分比
在pandas中,提供了专门的函数来计算累计值,分别是cumsum函数,expanding函数,rolling函数。我们一起来看一下使用三种函数计算分组和不分组累计百分比的方法。
1.不分组情况
cumsum函数
cumsum是pandas中专门用于计算累计和的函数。类似的函数还有cumprod计算累计积,cummax计算前n个值的最大值,cummin计算前n个值的最小值。
import pandas as pd
orderamt = pd.read_excel('orderamt.xlsx')
orderamt['cum_amt'] = orderamt['amt'].cumsum()
orderamt.head(15)直接对amt列使用cumsum函数即可计算累计值,结果和用SQL计算得到的一致。
计算累计的百分比也很容易。
orderamt['cum_amt_pct'] = orderamt['cum_amt'] / orderamt['amt'].sum(orderamt.head(15)关于结果如何显示成百分比的形式,可以参考上一篇文章,此处略 。
expanding函数
pandas中的expanding函数是窗口函数的一种,它不固定窗口的大小,而是进行累计的计算。类似于cumsum(),但更强大。
orderamt = pd.read_excel('orderamt.xlsx')
orderamt['mon'] = orderamt['dt'].dt.strftime('%Y-%m')#得到字符串形式的月份
orderamt['cum_expand'] = orderamt.expanding(min_periods=1)['amt'].sum()
orderamt.head(15)参数min_periods表示最小的观测窗口,默认为1,可以设置为其他值,但如果窗口内记录数不足该值,则会显示NA。
有了累计值,计算累计的百分比,可以按照cumsum中的方法进行,此处省略。
rolling函数
rolling函数与expanding相比,主要是固定了窗口大小。当窗口超过dataframe的长度时,可以实现与expanding同样的效果。上面的代码使用rolling函数的方式可以改写如下,注意指定了window参数为len(orderamt):
orderamt = pd.read_excel('orderamt.xlsx')
orderamt['mon'] = orderamt['dt'].dt.strftime('%Y-%m')#得到字符串形式的月份
orderamt['cum_roll'] = orderamt.rolling(window=len(orderamt), min_periods=1)['amt'].sum()
orderamt.head(15)此处同样省略计算累计百分比的代码。
2.分组情况
cumsum函数
#添加pandas显示设置,显示所有行
pd.set_option('display.max_rows', None)
orderamt = pd.read_excel('orderamt.xlsx')
orderamt['mon'] = orderamt['dt'].dt.strftime('%Y-%m')#分组后对amt求累计和
orderamt['cum_mon'] = orderamt.groupby('mon')['amt'].cumsum()
orderamt接下来计算分组的总计值,这里用到了pandas中的transform函数,可以把分组后计算的总计值写入原dataframe。如果你不是很理解,可以参考下面这篇文章,讲的很清楚。
https://www.jianshu.com/p/509d7b97088c
orderamt['mon_total'] = orderamt.groupby('mon')["amt"].transform('sum'orderamt['grp_cum_pct'] = orderamt['cum_mon'] / orderamt['mon_total']orderamt结果和前面SQL计算的是一致的。此处同样省略了转换百分比格式的代码,可参考前一篇文章。
expanding函数
分组情况下使用expanding函数需要和groupby结合,注意得到的结果是多重索引,需要取values才能赋值给原dataframe。
orderamt = pd.read_excel('orderamt.xlsx')
orderamt['mon'] = orderamt['dt'].dt.strftime('%Y-%m')
orderamt_mon_group = orderamt.groupby('mon').expanding(min_periods=1)['amt'].sum()
#这里的orderamt_mon_group索引会有两重,我们直接取values的值就可以和原dataframe拼接在一起
orderamt['orderamt_mon_group'] = orderamt_mon_group.values
orderamt接下来就可以用前面同样的方法,计算分组的总计值,然后求得分组累计百分比了。
rolling函数
通过上文我们知道,rolling函数与expanding函数的代码几乎一样,需要加上window参数。如下所示:
orderamt = pd.read_excel('orderamt.xlsx')
orderamt['mon'] = orderamt['dt'].dt.strftime('%Y-%m')
orderamt_mon_group_roll = orderamt.groupby('mon').rolling(len(orderamt),min_periods=1)['amt'].sum()
#这里的orderamt_mon_group_roll索引会有两重,我们直接取values的值就可以和原dataframe拼接在一起
orderamt['orderamt_mon_group_roll'] = orderamt_mon_group_roll.values
orderamt结果和上面的是一致的。
至此,我们用多种方法实现了对于累计百分比的计算。
小结
本篇我们计算了分组和不分组情况的累计百分比。在MySQL中用了不等值连接的方法,在Hive SQL中使用了sum窗口函数。在pandas中学习了cumsum,expanding,rolling函数,最终都需要将累加值除以总计值得出累计百分比。本文代码较多,您可以在公众号后台回复“对比五”可以获取本文pdf版本,代码,数据等进行实战,希望对你有所帮助。
◆ ◆ ◆ ◆ ◆
推荐阅读:
1.一场pandas与SQL的巅峰大战
2.一场pandas与SQL的巅峰大战(二)
3.一场pandas与SQL的巅峰大战(三)
4.一场pandas与SQL的巅峰大战(四)
5.常用Hive函数的学习和总结
相关推荐
- win10电脑所有软件都打不开(win10任何软件都打不开)
-
具体步骤如下:萊垍頭條1、如果遇到这类情况,你先看下快捷键alt+tab键能否查看,并把鼠标放在任务栏的图标上,或者查看一下窗口的缩略图。萊垍頭條2、我们将鼠标放在任务栏上,选中打不开的软件,然后al...
- 如何创建电子邮件账号(如何创建电子邮件账号在outlook中)
-
用QQ号的一键激活邮箱几乎是最快,最简单的注册邮箱手段了,且QQ邮箱功能强大,安全方便,推荐你使用,具体注册方法如下:1、你可以点击QQ面板邮箱快捷按钮,直接激活邮箱。2、如果你没有QQ,直接申请QQ...
- 戴尔音频驱动下载(戴尔电脑声卡驱动下载)
-
1、如果是笔记本没有音频设备的话,并不是没有输出设备,而是我们没有启用或者没有安装音频驱动导致的。先打开控制面板。2、打开控制面板之后下面依次找到音频清晰管理器,并且打开。3、打开之后我们这里把主音量...
- toshiba硬盘(TOSHIBA硬盘tlc)
-
东芝移动硬盘a3好,性价比很高,传输速率高,稳定耐用,安全高效外壳是磨砂质感!USB3.0,即插即用采用NTFS格式,兼容Windwos10、Windwos8.1、Windwos7,格式化后可兼容M...
- 完整版xp系统下载(xp系统最新版本安装包)
-
2012年前的可以无压力安装XP系统,搜索:itellyou.cn这里有WINDOWS几乎所有的系统。windowsXP系统升级的具体操作步骤如下:1、首先我们将老毛桃装机工具下载到U盘,将老毛桃...
- ps下载电脑版官方下载(ps电脑版下载地址)
-
目前在电脑上免费下载PS是不太可能的。主要有以下几个原因。1.AdobePhotoshop(简称PS)是一款商业软件,它需要用户购买和激活许可证才能合法使用。从正规渠道下载并且获得合法授权需要付费...
- 迅猛兔加速器(迅猛兔加速器官网)
-
要下载迅猛兔加速器,首先需要在官网或其他可信的下载平台上搜索并找到该软件。一般情况下,官网提供的下载链接是最稳定和安全的选择。在下载之前,确保您的电脑或手机系统能够支持使用此软件,并检查下载链接的文件...
- 台式电脑怎么重做系统(台式电脑怎么重装系统)
-
你好,电脑系统重装的步骤如下:1.备份数据:在重装系统之前,需要备份电脑中的重要数据,以免数据丢失。2.准备安装介质:需要准备一个安装介质,可以是光盘、U盘或者硬盘分区镜像等。3.设置启动顺序:将电脑...
-
- 电脑无法从u盘启动怎么办(电脑无法从u盘启动解决方法)
-
电脑的进入不了u盘启动的解决方法:一、我们第一步需要确定的是你的u盘在别的电脑上检查一下U盘是否可读,如果可读的话是否成功制作了u盘启动盘了,因为想要启动进入pe的话需要u盘具备启动的功能。 二、如果你检查好自己的u盘已经成功制作了启动盘...
-
2026-01-13 10:05 liuian
- cpu频率越高越好吗(cpu频率越高速度越快吗)
-
高好。CPU的频率是影响CPU的一个重要因素,直观上来说,频率的高低影响了CPU的性能。频率越高,CPU性能越好;不过需要注意的是,CPU的主频表示在CPU内数字脉冲信号震荡的速度,与CPU实际的运算...
- 注册表清理软件(注册表清理软件残留软件)
-
你好!关于注册表清理工具的推荐,以下是几个值得推荐的工具:1.CCleaner:这是一款功能强大的免费清理工具,可以有效地清理注册表、垃圾文件等,使用简单方便。2.WiseRegistryCl...
- 显卡驱动升级有好处吗(显卡驱动升级有什么坏处)
-
显卡的新版本驱动能修改一些游戏,图形显示的BUG,所以新版本的显卡驱动能有效的利用显卡的资源,提高游戏性能。不仅可以修正旧版本中的BUG,而且可以进一步挖掘显卡硬件的功能,使得部分硬件功能得以充分发挥...
- w7旗舰版系统安装无线网卡(win7系统安装无线网卡)
-
要在Windows7中安装无线网卡,请按照以下步骤进行操作:1.检查您的计算机是否已安装无线网卡。您可以通过右键单击“我的电脑”并选择“属性”来查看计算机的硬件设置。如果计算机没有内置无线网卡,则...
- 腾达路由器管理员密码是什么
-
1、旧版本的腾达路由器,默认的用户名和密码都是:admin。?旧版腾达路由器的初始密码是:admin2、目前腾达新推出的无线路由器,在出厂状态下,是没有初始管理员密码的。?新版腾达路由器没有初始密码新...
- 一周热门
-
-
飞牛OS入门安装遇到问题,如何解决?
-
如何在 iPhone 和 Android 上恢复已删除的抖音消息
-
Boost高性能并发无锁队列指南:boost::lockfree::queue
-
大模型手册: 保姆级用CherryStudio知识库
-
用什么工具在Win中查看8G大的log文件?
-
如何在 Windows 10 或 11 上通过命令行安装 Node.js 和 NPM
-
威联通NAS安装阿里云盘WebDAV服务并添加到Infuse
-
Trae IDE 如何与 GitHub 无缝对接?
-
idea插件之maven search(工欲善其事,必先利其器)
-
如何修改图片拍摄日期?快速修改图片拍摄日期的6种方法
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
