统计大xlsx文件的速度尝试

wils
wils

创作者俱乐部成员

一直有个疑问,在批量处理大一点的xlsx文件,比如10万行的表时,哪种方法更快?

于是今天的问题是:当前目录有多个xlsx文件,每个文件内部只有一张表,表内有两列,x列是数字,y列是分类,现在要对当前目录的所有xlsx里,每一个分类对应的数字求和


先试试JS宏

let f = Dir(ThisWorkbook.Path + "\\*.xlsx")
    while (f !== "") {
        let wb = Workbooks.Open(ThisWorkbook.Path + "\\" + f)
}

代码写的很烂,主要就是上面这样用Dir遍历xlsx文件,然后用字典分类求和

可以看出,主要是打开关闭文件这个步骤浪费时间


再试试pwsh里通过sql查询方式

👋

dir *.xls? | %{Get-SQL -Excel -Connection $_.Name -SQL 'select y,sum(x) as s from [Sheet1$] group by y' -Close -Quiet;$_.Name|Out-Host} | %{$d[$_.y]+=$_.s}

用的是access database engine,只是pwsh里用起来简单

可以看出,还是逐个打开表最耗时间,但相比JS宏,似乎快了一点


然后是python

没想到openpyxl打开大一点的xlsx速度更慢

好处是什么系统都能用这个脚本,包括手机上也可以

也许用xlrd或pandas打开能快一点?但据说pandas过去也是用的openpyxl

总之,py在打开大一点的xlsx时不够快


最后来试试新玩具,nushell

📌

ls *.xlsx | par-each {open $in.name | get Sheet1 | headers | group-by --to-table y | each {{...($in.items | math sum) "y": ($in.group)}}} | flatten | group-by --to-table y | each {{...($in.items | math sum) "y": ($in.group)}}

刚开始用,写的很烂。。。

但是,居然只用1秒就全处理了?!!

nushell这东西刚出来没多久,更新非常活跃,有很多好处:

  • 用rust重写的现代化shell,rust保证了开发的速度和安全性,同时能达到c的执行速度

  • 主要用来处理结构化的数据,包括xlsx表,数据库,csv、xml等格式

  • 遍历操作用each,由于它采用了函数式编程的思想,不可变的变量、纯函数等,可以直接改用par-each并发循环!

  • 可以方便的写sql查询数据,或是使用rust里的DataFrame(类似pandas)处理数据,速度非常快


最后总结一下经验:

  • JS宏和access的sql查询速度都可以接受,需要逐个打开文件,处理后关闭,这个步骤耗时较多

  • python的库不依赖office,相当于直接解压xlsx解析xml,逐个打开大一点的表格,速度很慢。虽然可以写并发,但python有全局锁的限制,协程没有这方面的方法,所以只能用多进程。虽然写起来麻烦,但速度可以提升,加上可以跨平台,还是蛮好用的

  • nushell很惊喜,rust重写的现代化shell,噱头十足,each改成par-each直接就可以并发循环让人眼前一亮,处理结构化数据包括xlsx,且可以使用DataFrame和SQL,满足大部分需求,尤其是需要并发时,十分值得尝试👍

广东省
浏览 418
3
12
分享
12 +1
5
3 +1
全部评论 5
 
HC.旋
厉害厉害
· 福建省
1
回复
 
寻残梦
666
· 广东省
1
回复
 
懒得批爆
懒得批爆

创作者俱乐部成员

文件不大,数据结构挺简单,但方法 很创新的样子,在长期测试后可试着使用。 我遇到这种类型的一般来说是先合并文件,然后再去统计数据之类的,毕竟只有结果,那要是有某个统计位置出错或者因为原始数据的错误导致结果错误,岂不是要翻开每个文件,现实场景的数据可不是按规则随机生成的,很大可能某些数据不规范,导致统计分析出错的。
· 四川省
3
回复
wils
wils

创作者俱乐部成员

主要是10个文件已经100万行了,再多也合并不了了。 最近尝试这个nushell,它的并发循环很有意思,就尝试一下还挺好用👍
· 广东省
1
回复