结构化数据上的循环运算

【摘要】
    循环运算是指按照一定的次序对集合的成员进行计算。除了在循环中访问当前成员、对成员赋值等简单的计算,还有在循环中进行跨行计算、嵌套循环、迭代运算等复杂需求。如何简便快捷的处理循环运算,这里为你全程解析,并提供 esProc 示例代码。结构化数据上的循环运算

1.     循环比较每行记录判断文件是否相同

循环判断,每次在序列最后添加新的成员。

【例 1】 比较两个行数相同的文件中有多少行数据完全一致。文件部分数据如下:

ID

Predicted_Y

Original_Y

10

0.012388464367608093

0.0

11

0.01519899123978988

0.0

13

0.0007920238885061248

0.0

19

0.0012656367468159102

0.0

21

0.009460545997473379

0.0

23

0.024176791871681664

0.0

SPL脚本】


A

B

C

1

=file("p_old.csv").import@ct()


/读取第一次输出的文件

2

=file("p_new.csv").import@ct()


/读取第二次输出的文件

3

for A1.len()

=cmp(A1(A3),A2(A3))

/循环比较两个文件同行记录的数据

4


=@|B3

/把每次比较的结果与 B4 格值合并

5

=B4.count(~==0)


/统计有多少行数据相等

    A5的执行结果如下:

Value

11302

 

2.     循环赋值

对集合的成员进行循环计算并赋值。

【例 2】 在销售表中,将 2014 年前 10% 的销售员再给予 5% 的业绩奖励。销售表部分数据如下:

OrderID

Customer

SellerId

OrderDate

Amount

10400

EASTC

1

2014/01/01

3063.0

10401

HANAR

1

2014/01/01

3868.6

10402

ERNSH

8

2014/01/02

2713.5

10403

ERNSH

4

2014/01/03

1005.9

10404

MAGAA

2

2014/01/03

1675.0

SPL脚本】


A

B

1

=connect("db").query("select   * from sales")

/连接数据源,读取销售表

2

=A1.select(year(OrderDate)==2014)

/选出 2014 年数据

3

=A2.groups(SellerId;sum(Amount):Amount)

/按销售员分组汇总当年销售总额

4

=A3.sort@z(Amount).to(A3.len()*0.1)

/按销售额降序排列,取前百分之十

5

=A4.run(Amount*=1.05)

/使用函数 A.run(),对前百分之十循环,每人给予销售额 5% 的奖励

    A5的执行结果如下:

SellerId

Amount

4

150433.185

3

127878.04

1

102756.759

8

87965.346

 

3.     复杂跨行计算

分组统计数据后,对每组分列统计不同的结果,同时跨行计算。

【例 3】根据用户支付数据明细表,统计各个用户 2014 年每月应付金额的汇总表。用户支付数据明细表部分数据如下:

ID

customID

name

amount_payable

due_date

amount_paid

pay_date

112101

C013

CA

12800

2014-02-21

12800

2014-12-19

112102

C013

CA

3500

2014-06-15

3500

2014-12-15

112103

C013

CA

2600

2015-03-21

6900

2015-10-17

要求根据指定年份(如2014),输出每月应付金额,若无当月数据,则当月应付金额为上月该值:

name

1

2

3

4

5

6

7

8

9

10

11

12

CA


12800

12800

12800

12800

16300

16300

16300

16300

16300

16300

16300













SPL脚本】


A

B

C

1

=file("Payment.txt").import@t().select(year(due_date)==2014)


/从文件中导入 2014 年数据

2

=create(name,${12.().concat@c()})

=A1.group(customID)

/A2:生成包含 12 个月的空表。A3:按客户 ID 分组。

3

for B2

=12.(null)

/生成 12 个月的空数据

4


>A3.run(B3(month(due_date))=   amount_payable)

/设置相应月份的应付金额。

5


>B3.run(~+=~[-1])

/将空值置为前一个月的数值,新增应付款项时累加。

6


=A2.record(B2.name|B3)

/将记录插入结果表中。

    A2的执行结果如下:

name

1

2

3

4

5

6

7

8

9

10

11

12

CA


12800

12800

12800

12800

16300

16300

16300

16300

16300

16300

16300













 

4.     最大连续增长天数

在循环计算中,计算某列的连续增长次数。

【例 4】 根据上证指数记录,求 2019 年收盘价增长的最大连续天数。上证指数表部分数据如下:

Date

Open

Close

Amount

2019/12/31

3036.3858

3050.124

2.27E11

2019/12/30

2998.1689

3040.0239

2.67E11

2019/12/27

3006.8517

3005.0355

2.58E11

2019/12/26

2981.2485

3007.3546

1.96E11

2019/12/25

2980.4276

2981.8805

1.9E11

SPL脚本】


A

B

1

=file("000001.csv").import@ct()

/导入数据文件

2

=A1.select(year(Date)==2019).sort(Date)

/选出 2019 年的记录并按日期排序

3

=n=0,A2.max(if(Close>Close[-1],n+=1,n=0))

/循环收盘价,比较每天的收盘价和前日收盘价,如果当日收盘价更高,则计数加 1,最后选出计数最大值。

    A3的执行结果如下:

Value

6

 

5.     嵌套循环

嵌套使用循环函数计算。

【例 5】 百鸡问题,鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、母、雏各几?

 

【SPL 脚本】


A

B

1

=to(100/5)

/可能购买的鸡翁数量

2

=to(100/3)

/可能购买的鸡母数量

3

=33.(~*3)

/可能购买的鸡雏数量

4

=create(Cock,Hen,Chick)

/创建空表用于存放三种鸡的数量

5

>A1.run(A2.run(A3.run(if(A1.~+A2.~+A3.~==100   && A1.~*5+A2.~*3+A3.~/3==100,A4.insert(0,A1.~,A2.~,A3.~)))))

/分别循环鸡翁、鸡母、鸡雏,当满足百钱买百鸡时,将结果插入到 A4 创建的集合中。其中用到了 ~ 符号代表集合循环的当前成员

    A4的执行结果如下:

Cock

Hen

Chick

4

18

78

8

11

81

12

4

84

 

6.     循环中调用次数

循环查找文本,并按需要生成结果,循环中需要使用循环次数。

【例 6】 根据文本 1 中的关键词,在文本 2 中查找,希望整理为输出结果:

..

【SPL 脚本】


A

B

1

=file("file1.txt").read@n()

/读取文本 1

2

=file("file2.txt").read@n()

/读取文本 2

3

=A1.conj(("Q"+string(#)+"."+~)|A2.select(pos(~,A1.~)).(~.words()(1)))

/循环文本 1 中的字符串,在文本 2 中查找,并取第一个英文单词。A2.select 中用到了 ~ 代表 A2 当前成员,A1.~ 代表 A1 的当前成员。每组搜索结果前拼上 Q+A1 的序号 +A1 当前成员,其中序号通过 #取得。

    A3的执行结果如下:

Member

Q1.   like parks

I

Shelly

Harry

Q2.   went out

Shelly

Q3. go   out

I

Ben

Harry

 

7.     循环时按位置统计临近数据

循环计算,计算时按位置计算偏移区间内均值。

【例 7】 根据招商银行的股市交易表,列出 2020 年 1 月 1 日至 10 日每天的 20 日收盘均价。股市交易表部分数据如下:

Date

Open

Close

Amount

2019/12/31

3036.3858

3050.124

2.27E11

2019/12/30

2998.1689

3040.0239

2.67E11

2019/12/27

3006.8517

3005.0355

2.58E11

2019/12/26

2981.2485

3007.3546

1.96E11

2019/12/25

2980.4276

2981.8805

1.9E11

SPL脚本】


A

B

1

=connect("db")

/连接数据源

2

=A1.query("select Date, Close from   Stock where Code='600036'order by Date")

/选出招商银行数据并按日期排序

3

=A2.pselect@a(Date>=date("2020/01/01")   && Date<=date("2020/01/10"))

/使用函数 A.pselect() 获取 2020 年 1 月 1 日到 10 日对应记录的序号

4

=A2(A3).derive(A2.calc(A3(#),avg(Close[-19:0])):ma20)

/使用函数 calc() 循环计算前十日数据的 20 日均值并返回,计算时使用了 Close[-19:0 获取从过去 19 天到今天的收盘价。

    A4的执行结果如下:

Date

Close

ma20

2020/01/02

38.88

37.35

2020/01/03

39.4

37.50

2020/01/06

39.24

37.64

2020/01/07

39.15

37.79

2020/01/08

38.41

37.90

2020/01/09

38.9

38.03

2020/01/10

39.04

38.16

 

8.     迭代累加

循环时迭代累加,根据累加值筛选。

【例 8】根据销售表,统计出 2014 年每个月达到 20 笔订单所需天数。销售表部分数据如下:

OrderID

Customer

SellerId

OrderDate

Amount

10400

EASTC

1

2014/01/01

3063.0

10401

HANAR

1

2014/01/01

3868.6

10402

ERNSH

8

2014/01/02

2713.5

10403

ERNSH

4

2014/01/03

1005.9

10404

MAGAA

2

2014/01/03

1675.0

SPL脚本】


A

B

1

=connect("db").query("select   * from sales")

/连接数据源,读取销售表

2

=A1.select(year(OrderDate)==2014)

/选出 2014 年数据

3

=A2.sort(OrderDate)

/按照订单日期排序

4

=A3.select(seq(month(OrderDate))==20)

/使用函数 seq() 计算每个月份的订单序号,并选出每个月序号为 20 的记录

    A4的执行结果如下:

Month

Day

1

20

2

20

3

20

4

18

 

9.     分组计算排名

循环中计算分组中的排名。

【例 9】根据员工收入表,求员工在本部门的收入排名。员工收入表部分数据如下:

ID

NAME

DEPT

SALARY

1

Rebecca

R&D

7000

2

Ashley

Finance

11000

3

Rachel

Sales

9000

4

Emily

HR

7000

5

Ashley

R&D

16000

【SPL 脚本】


A

B

1

=connect("db")   .query("select * from Employee order by DEPT, SALARY DESC")

/连接数据源,读取员工表并按部门和收入排序

2

=A1.derive(rank(SALARY;DEPT):DeptRank)

/对有序的部门和收入利用函数 rank() 编号,计算出各部门排名

    A2的执行结果如下:

ID

NAME

DEPT

SALARY

DeptRank

2

Ashley

Finance

11000

1

32

Andrew

Finance

11000

1

230

Hannah

Finance

10000

3

24

Chloe

Finance

10000

3

 

10.   分组计算紧凑排名

循环计算分组中的紧凑排名。

【例 10】根据成绩表,求出一班学生 ID 为 8 的学生的各科成绩在本班的排名。成绩表部分数据如下:

CLASS

STUDENTID

SUBJECT

SCORE

Class   one

1

English

84

Class   one

1

Math

77

Class   one

1

PE

69

Class   one

2

English

81

Class   one

2

Math

80

【SPL 脚本】


A

B

1

=connect("db")   .query("select * from SCORES where CLASS='Class one'order by SUBJECT,   SCORE DESC")

/连接数据源,读取学生成绩表并按学科和成绩排序

2

=A1.derive(ranki(SCORE;SUBJECT):Rank)

/对有序的学科和成绩利用函数 ranki() 计算各科成绩的紧凑排名

3

=A2.select(STUDENTID==8)

/选出学生 ID 是 8 的学生信息

4

=create(${A3.(SUBJECT).concat@c()}).record(A3.(Rank))

/利用 A3 选出的结果,整理出各科紧凑排名

    A4的执行结果如下:

English

Math

PE

10

4

14

 

11.   迭代求和

循环计算迭代求和的结果。

【例 11】根据上证指数表,计算 2019 年每个交易日的全年累计成交金额。上证指数表部分数据如下:

Date

Open

Close

Amount

2019/12/31

3036.3858

3050.124

2.27E11

2019/12/30

2998.1689

3040.0239

2.67E11

2019/12/27

3006.8517

3005.0355

2.58E11

2019/12/26

2981.2485

3007.3546

1.96E11

2019/12/25

2980.4276

2981.8805

1.9E11

【SPL 脚本】


A

B

1

=file("000001.csv").import@ct()

/导入数据文件

2

=A1.select(year(Date)==2019).sort(Date)

/选出 2019 年的记录并按日期排序

3

=A2.derive(cum(Amount):CUM)

/使用 cum() 函数计算累计成交金额

    A3的执行结果如下:

Date

Open

Close

Amount

CUM

2019/01/02

2497.8805

2465.291

9.759E10

9.759E10

2019/01/03

2461.7829

2464.3628

1.07E11

2.046E11

2019/01/04

2446.0193

2514.8682

1.39E11

3.436E11

2019/01/07

2528.6987

2533.0887

1.46E11

4.896E11

2019/01/08

2530.3001

2526.4622

1.23E11

6.126E11

 

12.   自定义迭代计算

循环中使用迭代计算,自行设置迭代中的计算表达式和终止条件。

【例 12】根据销售表数据,统计 2014 年第一季度到哪一天完成了销售总额 15 万的季度目标。销售表部分数据如下:

OrderID

Customer

SellerId

OrderDate

Amount

10400

EASTC

1

2014/01/01

3063.0

10401

HANAR

1

2014/01/01

3868.6

10402

ERNSH

8

2014/01/02

2713.5

10403

ERNSH

4

2014/01/03

1005.9

10404

MAGAA

2

2014/01/03

1675.0

SPL脚本】


A

B

1

=connect("db").query("select   * from sales")

/连接数据源,读取销售表

2

=A1.select(year(OrderDate)==2014)

/选出 2014 年数据

3

=A2.iterate((@+=Amount,   ~~=OrderDate),0,@>150000)

/使用函数 iterate() 迭代计算,初始值为 0。将销售额累加到当前格,直到超过 15 万终止。函数返回订单日期。

    A3的执行结果如下:

Value

2014/03/25

 

SPL CookBook》中还有更多相关计算示例。