前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vba新姿势,如何让vba的数据处理"超越"Python

vba新姿势,如何让vba的数据处理"超越"Python

作者头像
咋咋
发布2021-09-01 12:16:19
3.1K0
发布2021-09-01 12:16:19
举报
文章被收录于专栏:数据大宇宙

前言

上一节我们讨论了 Python 在数据处理上的优势,前后台大概收到的有用评论如下:

  1. "了解下 power query,可以很简单解决"
  2. "你文中说到vba也可以做到在固定代码中插入逻辑,具体如何做到?"
  3. "你的vba水平不行,才需要写这么复杂,比如分组可以先排序,再遍历判断边界做处理"
  4. "vba可以调用odbc等数据库驱动,使用 sql 呀"

那些不看内容不经思考的评论就不说了

真希望他们评论的同时能自己动手实践一下,后续我会逐一使用 power bi(不仅仅 pq,也用 dax),sql 实现。只要能提高工作效率,我非常乐意学习,也从不只看重某一种工具。

但是今天我要首先替 vba 说一句公道话,难道Excel数据处理任务的vba代码,真的不可能做到像 pandas 一样简洁直白吗?某些场景下,绝对可以!

实战案例是数据拆分,如果你觉得其他实现方式能比今天的代码更加简洁,欢迎给出你的答案,而非仅仅一句"xxx工具比你简单"

泰坦尼克号沉船事件中的乘客信息表:

实现几个简单的拆分需求:

  1. 按"性别",把数据拆分到不同的工作表,工作表名字使用"性别(值)"
  2. 按 "性别"、"船舱等级",把数据拆分到不同的工作表,工作表名字使用"性别(值),船舱等级(值)"
  3. 按 "性别" ,把数据拆分到不同的工作簿(文件),文件名字使用"性别值.xlsx",每个对应文件中,按 "船舱等级",拆分到不同的工作表,工作表名字使用"船舱等级(值)"

需要达到以下目标:

  1. vba 代码多余表达要接近于 python 代码
  2. 就算换另一份数据,只需要修改关键表达即可使用(比如按某字段分组,只需要修改字段名字即可),无须大范围修改代码。
  3. vba 代码执行效率与原有的"数组+字典"一致

说白了,就是要提升 vba 的开发效率(写代码的时间) 与 保持执行效率(代码执行时间)


在固定逻辑中,插入自定义逻辑

上一篇文章的后半部分已经说明了为什么 vba 中写不出来像 pandas 的数据处理库,这里不再复述。

为什么python比vba更适合自动化处理Excel数据?

但是,vba 真的就不能做到"封装固定逻辑的同时,给予使用者放入自定义逻辑" 吗?

如下数据:

  • 按 列1,列2 分组,每组数据输出也好,统计也行

vba中实现这个有许多方式,我就用最常用的一种方式,数组+字典:

  • 这里使用 "|" 连接多个 作为 key 其实是不合理的做法,要避免
  • 红框是本需求的关键逻辑
  • 注意了,他是在固定逻辑的循环里面

当然也可以先排序,遍历判断边界。怎么实现分组其实没关系。

问题是排序只能对单元格区域,很多时候需求不是直接排序,或不希望改变原数据,这就导致你需要先输出单元格,排序后再放入数组,多了一些与分组没关联的操作

关键是,与需求相关的核心逻辑,是上图红框部分,就那么一小段的代码。

如果能够把非红框部分的代码包含在一个方法中,那么以后不管啥数据啥需求,分组相关的操作只需要调用这个方法就可以!

如果你是喜欢敲代码,以敲出复杂逻辑代码自豪,那么可以跳过这些内容

看看我们要怎么做到。

首先,把关键逻辑提取出来成为方法:

  • 方法名字以及里面的2个参数名字叫啥都可以

固定逻辑中,我们需要动态调用:

  • 关键就是这个 application.run 方法
  • 其中的 "test.each_group" 是 "模块名字.方法名字"
  • 现在外部逻辑可以让使用者自定义方法,作为字符串插入

此时,固定逻辑的方法,可以单独收起来到一个通用模块(或类模块),里面的代码以后都不需要改动。以后你在新项目中要使用,只需要导入这个模块就可以

这就是 vba 中实现插入逻辑的实现方式,非常简单。

vba 中还可以通过实现接口做到插入逻辑,这是最正统的方式,但是那是 vb 为了应用开发工程而设计的,不适合我们的非专业开发者

核心原理就是这样子,我把这些固定方法定义在 vba_pd 模块下:

现在看看实际应用是怎么样?


需求1:按"性别",把数据拆分到不同的工作表,工作表名字使用"性别(值)"

先看 pandas :

vba:

  • Call vba_pd.groupby_apply(df, "4", "main.each_性别") ,就是分组+处理
  • 参数1自然是数据数组
  • 参数2是分组列,4表示第4列
  • 参数3是每个组的处理逻辑,执行时,每一组"性别"的数据就会传入自定义方法中执行
  • 红框方法中,xdf 参数实际也是一个二维数组

分组 key 实际也可以做成字段,不过为了方便讲解,这里没有制作成完整的类模块形式

虽然看起来 vba 代码多一些,但多出来的只是一些通用细节:

  • 指定工作表与单元格区域生成数组,用了2句,完全可以用一句
  • 分组关键列vba用的是列号,这只是我偷懒,实际可以改造成支持列名指定
  • 而 pandas 代码自带输出表头,vba实际也能做到

可以说,代码上的多余表达两者都非常少,这需求可以说打个平手

那么,可不可以做成多关键列分组?


需求2:按 "性别"、"船舱等级",把数据拆分到不同的工作表,工作表名字使用"性别(值),船舱等级(值)"

先看 pandas :

再看vba:

  • 与之前需求变动非常少,因为本身需求表达变动也不多。代码就不应该有很大的区别
  • groupby_apply 的参数2,使用英文逗号分隔指定列号即可多关键列分组

对比结果也与前一个需求一样,打个平手。


数据的传递

需求3:按 "性别" ,把数据拆分到不同的工作簿(文件),文件名字使用"性别值.xlsx",每个对应文件中,按 "船舱等级",拆分到不同的工作表,工作表名字使用"船舱等级(值)"

pandas 实现:

vba 实现:

  • 注意绿色框中的调用,方法 groupby_apply 参数3之后,我们可以传递无数个参数,他们会组成一个字典,在组处理方法中参数3 kws,可以获取数据
  • 看看每个方法中的处理,对照一下需求描述,多余的代码非常少!

如果你还没有理解这种代码的优点,你不妨自己动手用自己的方式实现一次。


不仅仅只是分组

"你没有超越 pandas 呢!"

额,是的,毕竟我只是用了几十分钟做的小模块,自然不能与人家整个社区做了几十年的积累相比。

有些人可能以为这玩意只能做分组,实际上这与数组、字典这些玩意一点关系都没有,核心还是那句,"固定逻辑中,允许插入自定义逻辑"。

所以,理论上vba可以做到如下实现代码:

如果你仍然偏爱于原有的写法,那么你可能是一位热爱敲代码的人。可惜(幸好)我不是

公众号回复"xlwings",获取本文源码

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据大宇宙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 在固定逻辑中,插入自定义逻辑
  • 数据的传递
  • 不仅仅只是分组
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档