筛选指定特征的曲线段二——筛选曲线段

筛选指定特征的曲线段二——筛选曲线段

算法背景

算法背景已经在《筛选指定特征的曲线段一——计算曲线特征》中介绍过了,这里不再赘述。

文章链接:

筛选指定特征的曲线段一——计算曲线特征

算法思路

《筛选指定特征的曲线段一——计算曲线特征》的算法思路,本篇介绍筛选曲线时的思路

1.      投射特征

计算特征时,各个特征的量纲并不相同,在筛选这些特征时,不容易设置他们的取值范围。因此想办法把特征投射到一个统一的范围内。(比如投射到[-1,1],因为有些特征的正负是有意义的,如升降特征,正的表示上升,负的表示下降)。设置参数时只要设置[-1,1]范围内的数即可,-1表示最小,1表示最大。

2.      连续多特征曲线段

投射特征后可以方便的设置参数筛选出某种特征的曲线段,如上升或震荡发散等,但想选出连续不同特征的曲线段(如先上升后下降、先平稳后下降等)时会比较复杂。

(1)    将几种特征曲线段全筛选出来;

(2)    按序排列这些曲线段;

(3)    选出顺序正确且距离不远的曲线段即可。

算法过程

1.      投射特征

具有正负取值的特征(如升降指数):

假设特征的最大值是fmax,最小值是fmin。将[fmin0]投射到[-1,0][0,fmax]投射到[0,1],特征f与筛选参数a的函数关系为:

..

取值只有正数的特征:

..

特征被投射到[-1,1]后,参数就更容易设置了。

2.      筛选特征

(1)      设置筛选参数

筛选曲线段的特征组合称为指数特征名,记为index_name

index_name =[f1,f2,…,fm]

其中fi是第i个特征指数名。

特征组合对应的取值范围称为指数取值参数,记为index_arg

index_arg=[[a(1)1, a(1)2], [a(2)1, a(2)2],…, [a(m)1, a(m)2]]

其中a(i)1是第i个特征指数的取值下限,a(i)2是第i个特征指数的取值上限,。

(2)      投射参数

将指数取值参数投射到指数的取值上,称为指数取值,记为index_value

index_value=[[ v(1)1, v(1)2], [[v(2)1, v(2)2],…, [[v(m)1, v(m)2]]

其中F(…)是投射函数,v(i)1= F(a(i)1)v(i)2= F(a(i)2)

(3)      记录满足条件的特征索引feature_idx

feature_idx=[i, v(1)1f(1)v(1)2,…, v(m)1f(m)v(m)2,i[1,m]]

其中f(i)是第i个指数的取值。

(4)      筛选曲线段长度

将曲线段长度范围记为duration

duration=[d1,d2]

feature_idx中每段数值连续的索引都是一段满足条件的曲线段,筛选出曲线段的持续时间在duration内的段,也就是找出连续索引的个数在[d1,d2]范围内的曲线段。

3.      分段曲线

当要筛选多种不同特征曲线时(如下降——平稳——上升),按如下步骤进行:

(1)      按筛选特征的方法筛选出各种特征的曲线索引。

curve_idx1=H(arg1)

curve_idx2=H(arg2)

curve_idxk=H(argk)

其中curve_idxi是第i段特征曲线的索引集合,H(…)2中介绍的筛选特征曲线段函数,argi是第i段特征曲线的参数。

(2)      合并这些曲线段并按照曲线段的先后顺序排序。

curve_id=curve_idx1|curve_idx2|curve_idxk

curve_id_sort=[c1,c2,…,ch]

其中curve_id_sort是按曲线段的先后顺序排序后的曲线段集合,cicurve_id_sort的第i个元素,表示某个特征曲线的某一段,h是各种特征曲线的曲线段数量之和。

(3)      找出curve_id_sort中与所需特征顺序相同且间隔不远的连续曲线段。

seg_curve_id=[[ci,ci+1,…,ci+k-1],[ cj,cj+1,…,cj+k-1],…]

其中seg_curve_id是分段曲线的索引集合,其中ci,ci+1,…,ci+k-1分别属于curve_idx1, curve_idx2,…,curve_idxk,且相邻两段曲线相隔不远。

(4)      按索引取数

seg_curve=X(seg_curve_id)

其中X是时间序列。

写出代码


A

B

C

D

1

=json(args)

/筛选参数


2

=X

/时间序列


3

=T

/时间



4

=func(A37,A1.ob_level)

/主线参数 k


5

=A1.ob_level\20


/指数区间


6

=fit_main(A2,A4)


/主线


7

=clac_feature(A6,A5,"lift")

/升降指数


8

=clac_feature(A6,A5,"lift_speed")

/升降速度指数


9

=A2--A6


/波动曲线


10

=clac_feature(A9,A5,"range")

/振幅


11

=fit_main(A10,A4)

/振幅主线


12

=clac_feature(A11,A5,"lift")

/振幅升降指数


13

=clac_feature(A9,A5,"fre")

/振频


14

=fit_main(A13,A4)


/振频主线


15

=clac_feature(A14,A5,"lift")

/振频升降指数


16

[time,value,main,lift,lift_speed,range,range_lift,frequency,frequency_lift]

17

=create(${A16.concat@c()})

/建立特征序表


18

=[A3,A2,A6,A7,A8,A10,A12,A13,A15]



19

=transpose(A18).conj()



20

=A17.record(A19)




21

=func(A42,A20)


/特征最大最小值


22

for A1

=A22.index_name_seq

/指数名称

23


=A22.index_value_seq

/指数参数值

24


=A21.align(B22,feature)

/需要的指数

25


=B23.((idx=#,if(B24(idx).feature=="value",~,~.(func(A52,~,B24(idx).ma,B24(idx).mi)))))

/指数实际值

26


=B22.(~/">="/"number("/$[B25(]/#/$[)(1)]/")"/"&&"/~/"<="/"number("/$[B25(]/#/$[)(2)]/")").concat("&&")

/筛选表达式

27


=A20.pselect@a(eval(B26))

/曲线段索引

28


=B27.group@u(~-#)

/连续索引段

29


=A22.duration

/持续时间

30


=if(!B29,B28,B28.select(~.len()>=B29(1)&&~.len()<=B29(2)))

/按持续时间筛选

31


=@|[B30]



32

=func(A60,B31,A1.(space))

/分段筛选


33

=A32.(A20(~))


/按索引取数


34

=if(A33.len()<1,"No satisfactory working condition was found",A33.new(#:index,~.(time):time,~.(value):value))

/返回结果

35

return A34




36

/计算移动窗口与拟合参数 k 的关系,参数:移动窗口

37

func




38


=A37/15



39


=lg(B38,2)


40


=2*power(4,B39-1)


41

/计算特征最大最小值,参数:特征序表


42

func




43


=A42.fname()

/特征名


44


=create(feature,ma,mi)

45


for B43

=A42.(${B45})

46



=C45.max()

/最大值

47



=C45.min()

/最小值

48



=[B45,C46,C47]

49



=B44.record(C48)

50


return B44


51

/投射特征,参数:[-1,1] 范围内的数,最大值,最小值

52

func




53


if B52*C52<0

if A52<=0

=(A52+1)*(-C52)+C52

54




return D53

55



else

=A52*B52

56




return D55

57


else if B52*C52>=0

=(A52*(B52-C52)+B52+C52)/2

58



return C57

59

/归并分段,参数:序列的序列



60

func




61


=A60.conj((idx=#,~.new(~:seq,idx:seq_idx)))

/不同特征的曲线段索引

62


=B61.sort(seq)

/排序


63


=B62.group@u(seq_idx-#)

/特征相邻的分组

64


=if(A60.len()==1,B63,B63.select(~.len()==A60.len()&&(~.(~.seq.m(1)-~[-1].seq.m(-1)).m(2:)--B60.m(:-2)).id(~<=0)==[true]))

/筛选间隔足够小的分组

65


=B64.((sq=~.(seq).conj(),to(sq.~,sq.m(-1))))

/满足要求的曲线段







参数说明:

args:是筛选曲线段的参数,是个json串。形式如下:

[{"ob_level":600,

"index_name_seq":["lift"],

"index_value_seq":[[-1,-0.1]],

"duration":[100,1000],

"space":180},

{"ob_level":600,

"index_name_seq":["lift"],

"index_value_seq":[[-0.1,0.1]],

"duration":[100,1000],

"space":180}]

ob_level:观察级别,用于计算拟合主线的参数k,可以理解为移动均线的移动窗口。

index_name_seq:指数特征名,值是字符串构成的序列,如:[“lift”]

index_value_seq:指数参数值,值是数字构成的序列的序列,如:[[-1,-0.1]]

duration:曲线段长度范围,值是数字构成的序列,可以为空,如:[100,1000]

space:与下一种工况的间隔,当筛选分段工况时,该参数才有用,如:180

说明:代码是简单的实现代码,每次都会计算所有特征,在实际应用时只需要计算参数中设置的特征即可,也可以把计算特征模块单独出来,将特征存储下来,这样筛选时就会快很多。

应用举例

时间序列X

..

图中横轴是时间(dd hh:mm),纵轴是序列中的值。

1.      取值在[90,95]之间的曲线段

args

[{"ob_level":600,

"index_name_seq":["value"],

"index_value_seq":[[90,95]],

"duration":[100,10000],

"space":180}]

筛选结果:

..

..

图中蓝色的曲线段为筛选到曲线段。

2.      上升的曲线段

args:

[{"ob_level":600,

"index_name_seq":["lift"],

"index_value_seq":[[0.1,1]],

"duration":[100,10000],

"space":180}]

筛选结果:

..

3.      振频很高的曲线段

args

[{"ob_level":600,

"index_name_seq":["frequency"],

"index_value_seq":[[0,1]],

"duration":[100,10000],

"space":180}]

筛选结果:

..

..

4.      震荡发散的曲线段

args

[{"ob_level":600,

"index_name_seq":["range_lift","frequency_lift"],

"index_value_seq":[[0,1],[-0.5,1]],

"duration":[100,3000],

"space":180}]

筛选结果:

..

..

..

5.      先下降后平稳的曲线段

args

[{"ob_level":600,

"index_name_seq":["lift"],

"index_value_seq":[[-1,-0.1]],

"duration":[100,1000],

"space":180},

{"ob_level":600,

"index_name_seq":["lift"],

"index_value_seq":[[-0.1,0.1]],

"duration":[100,1000],

"space":180}]

..