SPL:按序号对齐的分组和排序
有时候我们会按照序号顺序将数据进行分组和排序,把序号相同的成员分到同一组。比如按 1 到 12 月的顺序统计上一年每个月的销售总额,按照周一到周日的顺序统计某网站的访问人次等等。
这种按指定基准对齐的分组运算,我们统称为对齐分组。按序号对齐分组是对齐分组的一种特例,其基准集合是从 1 开始的整数列。对齐分组可能会有空组,也可能有成员未分配到任何一个组中。
1. 按序号顺序排序
按指定的序号顺序将数据排序,每组保留最多一个匹配成员。适用于我们希望按照指定顺序查看或者使用数据的情况。
【例 1】 根据每日销售表,按每周一到周日的顺序查询销售记录。部分数据如下:
Week | Day | Amount |
5 | Sunday | 1101.2 |
5 | Saturday | 538.6 |
5 | Friday | 2142.4 |
5 | Thursday | 1456.0 |
5 | Wednesday | 48.0 |
5 | Tuesday | 1376.0 |
5 | Monday | 676.0 |
4 | Sunday | 448.0 |
4 | Saturday | 4031.0 |
4 | Friday | 364.8 |
… | … | … |
在 SPL 中函数 A.align(n,y) 用于对齐分组 ,直接划分为 n 个组(从 1 到 n),并根据分组表达式 y 直接计算出每个成员对应的组号。默认每组保留最多一个匹配成员。
SPL脚本如下:
A | |
1 | =T("DailySales.csv") |
2 | ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"] |
3 | =A1.group(Week; ~.align(7,A2.pos(Day)):WeekSales) |
4 | =A3.conj(WeekSales) |
5 | =A4.select(~) |
A1:查询每日销售表。
A2:定义从周一到周日的序列。
A3:销售数据按周分组时,使用函数 A.align(n,y) 将每周的销售记录,按照A2定义好的顺序进行对齐。这里值得注意的是,对齐分组可能会有空组。例如当第二周的周五和周六没有销售记录时,仍然会产生每周 7 个小组:
Week |
[2,Monday,1194.0] |
[2,Tuesday,1622.4] |
[2,Wednesday,319.2] |
[2,Thursday,802.0] |
(null) |
(null) |
[2,Sunday,2123.2] |
A4:将每周排序后的销售记录合并。
A5:从结果集中选出非空的记录。
其中A5的执行结果如下:
Week | Day | Amount |
1 | Monday | 3063.0 |
1 | Tuesday | 3868.6 |
1 | Wednesday | 2713.5 |
1 | Thursday | 1005.9 |
1 | Friday | 1675.0 |
1 | Saturday | 400.0 |
1 | Sunday | 2018.2 |
2 | Monday | 1194.0 |
2 | Tuesday | 1622.4 |
2 | Wednesday | 319.2 |
… | … | … |
2. 每组保留所有匹配成员
按指定的序号顺序将数据分组,每组保留所有匹配成员。适用于关心每组的成员信息,或者需要用这些成员记录继续进行统计的场景。
【例 2】 根据销售表,顺序列出 2014 年每个月的销售总额。销售表部分数据如下:
ID | CustomerID | OrderDate | Amount |
10248 | VINET | 2013/07/04 | 2440 |
10249 | TOMSP | 2013/07/05 | 1863.4 |
10250 | HANAR | 2013/07/08 | 1813.0 |
10251 | VICTE | 2013/07/08 | 670.8 |
10252 | SUPRD | 2013/07/09 | 3730.0 |
… | … | … | … |
在 SPL 中函数 A.align(n,y) 的选项 @a,用于在对齐分组时每组保留所有匹配成员。
SPL脚本如下:
A | |
1 | =T("Sales.csv") |
2 | =A1.select(year(ORDERDATE)==2014) |
3 | =A2.align@a(12,month(ORDERDATE)) |
4 | =A3.new(#:Month,~.sum(AMOUNT):AMOUNT) |
A1:查询销售表。
A2:从销售表中选出 2014 年的记录。
A3:使用函数 A.align@a(n,y),将订单表的月份按照 1 到 12 的顺序分为 12 组,选项 @a 每组保留所有匹配成员。
A4:统计每个月的销售总额。
其中A4的执行结果如下:
Month | Amount |
1 | 66692.8 |
2 | 52207.2 |
3 | 39979.9 |
4 | 60699.39 |
… | … |
3. 按序号重复性分组
有时候每条记录计算出的分组序号是多个,我们希望将记录按照序号数列重复性的分配到多个组中。
【例 3】 根据发帖记录表,按标签将帖子分组,并统计各个标签出现频数。发帖记录表部分数据如下:
ID | Title | Author | Label |
1 | Easy analysis of Excel | 2 | Excel,ETL,Import,Export |
2 | Early commute: Easy to pivot excel | 3 | Excel,Pivot,Python |
3 | Initial experience of SPL | 1 | Basics,Introduction |
4 | Talking about set and reference | 4 | Set,Reference,Dispersed,SQL |
5 | Early commute: Better weapon than Python | 4 | Python,Contrast,Install |
… | … | … | … |
在 SPL 中函数 A.align(n,y) 的选项 @r,用于在对齐分组时按序号重复性分组。
SPL脚本如下:
A | |
1 | =T("PostRecord.txt") |
2 | =A1.conj(Label.split(",")).id() |
3 | =A1.align@ar(A2.len(),A2.pos(Label.split(","))) |
4 | =A3.new(A2(#):Label,~.count():Count).sort@z(Count) |
A1:查询发帖记录表。
A2:将标签按逗号分隔后合并到一个序列,获得没有重复值的全部标签。
A3:使用函数 A.align@r(n,y) 的,按照每个帖子的标签在全部标签中的定位分组,选项 @r。
A4:统计每个标签的帖子数量,按降序排列。
其中A4的执行结果如下:
Label | Count |
SPL | 7 |
Excel | 6 |
Basics | 5 |
… | … |