nysol-mining 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,716 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding:utf-8
3
+
4
+ require 'fileutils'
5
+ require 'rubygems'
6
+ require 'nysol/mcmd'
7
+
8
+ $version=1.0
9
+ $revision="###VERSION###"
10
+
11
+ def help
12
+
13
+ STDERR.puts <<EOF
14
+ ----------------------------
15
+ mburst.rb version #{$version}
16
+ ----------------------------
17
+ 概要) HMMによるburst検知プログラム
18
+ 特徴) 1) 分布のパラメータの変化を検知する
19
+ 2) 確率分布としては指数分布、ポアソン分布、正規分布、二項分布に対応
20
+ 書式) mburst.rb f= dist=exp|poisson|gauss|binom [s=] [p=] i= [o=] [--help]
21
+
22
+ 例) mburst.rb f=interval dist=exp i=burstExp.csv o=output.csv
23
+
24
+ i= : 入力ファイル名【必須】
25
+ o= : 出力ファイル名【オプション:defaultは標準出力】
26
+ d= : デバッグ情報を出力するファイル【オプション】
27
+ dist= : 仮定する分布名称(exp:指数関数,poisson:ポアソン分布,gauss:正規分布,binom:二項分布)【必須】
28
+ f= : burst検知対象となる数値項目名(i=上の項目名)【必須】
29
+ param= : 定常状態における分布のパラメータ。注1参照【オプション】
30
+ pf= : 定常状態における分布のパラメータ項目名(i=上の項目名)注1参照【オプション】
31
+ s= : burstスケール(詳細は注2参照)【オプション:default=2.0】
32
+ p= : 同一状態遷移確率(この値を高くするとbusrtしにくくなる。詳細は注3参照)【オプション:default=0.6】
33
+
34
+ n= : dist=binomの場合の試行回数【n= or nf=いずれかを指定】
35
+ nf= : dist=binomの場合の試行回数の項目名
36
+ v= : dist=gaussの場合の分散値(指定がなければf=項目のデータから推定)
37
+ nv= : dist=gaussの場合の分散の項目名
38
+ --help : ヘルプの表示
39
+
40
+ 注1) 定常状態における分布のパラメータ(母数)の与え方は以下の3通り。
41
+ 1) para=で指定した値とする。
42
+ 2) pf=で指定した項目の値を用いる。時刻に依存してパラメータが異なることが仮定できる場合のため。
43
+ 3) para=,pf=の指定がなければ、f=で指定した値から自動的に計算される。
44
+
45
+ 注2) 定常状態、burst状態における分布パラメータの計算方法は以下のとおり。
46
+ S: s=で指定した値、n:データ件数、x_i: f=でしていした項目のi行目の値
47
+ exp: 確率密度関数f(x)=λ*exp(-λx)、パラメータはλ(平均イベント発生回数)
48
+ 定常(state0)状態λ0=n/Σx_i
49
+ burst(state1)状態λ1=λ0*S
50
+ poisson: 確率関数f(x)=λ^x*exp(-λ)/x!、パラメータはλ(平均イベント発生回数)
51
+ 定常(state0)状態λ0=Σx_i/n
52
+ burst(state1)状態λ1=λ0*S
53
+ gauss: 確率密度関数: f(x)= 1/√2πσ^2 exp(-(x-μ)^2/2σ^2)、パラメータはμ(平均)
54
+ m=Σx_i/n、v=Σ(x_i-m)^2/nとすると、
55
+ 下側burst(state-)状態μ- =m-sqrt(v)*S
56
+ 定常(state0)状態μ0 =m
57
+ 上側burst(state+)状態μ+ =m+sqrt(v)*S
58
+ binom: 確率関数: f(x)=(T choose x)p^x(1-p)^(T-x):パラメータはp(成功確率)
59
+ 定常(state0)状態p0=(Σx_i/n)/T (平均成功回数/試行回数)
60
+ burst(state1)状態p1=S/((1-p0)/p0+S)
61
+
62
+ 注3) 状態遷移確率の設定方法。
63
+ p: p=で指定した値
64
+ exp, poisson, binom:
65
+ prob(state0→state0)=prob(state1→state1)
66
+ prob(state0→state1)=prob(state1→state0)=1-p
67
+ gauss:
68
+ prob(state-1→state-1)=prob(state0→state0)=prob(state1→state1)=p
69
+ prob(state0→state-1)=prob(state0→state1)=prob(state2→state2)=(1-p)/2
70
+ prob(state-1→state0)=prob(state1→state0)=(1-p)/3*2
71
+ prob(state-1→state1)=prob(state1→state-1)=(1-p)/3
72
+
73
+ Copyright(c) NYSOL 2012- All Rights Reserved.
74
+ EOF
75
+ exit
76
+ end
77
+
78
+ def ver()
79
+ $revision ="0" if $revision =~ /VERSION/
80
+ STDERR.puts "version #{$version} revision #{$revision}"
81
+ exit
82
+ end
83
+
84
+
85
+
86
+
87
+ help() if ARGV.size <= 0
88
+ help() if ARGV[0]=="--help"
89
+ ver() if ARGV[0]=="--version"
90
+
91
+ # パラメータ設定
92
+ args=MCMD::Margs.new(ARGV,"i=,o=,d=,f=,dist=,s=,p=,pf=,n=,nf=,v=,vf=,param=","i=,o=,f=,dist=")
93
+
94
+ iFile = args.file("i=","r")
95
+ dFile = args.file("d=","w",nil)
96
+ oFile = args.file("o=","w")
97
+ fName = args.field("f=",iFile)
98
+ fName = fName["names"].join(",") if fName
99
+ pName = args.field("pf=",iFile)
100
+ pName = pName["names"].join(",") if pName
101
+ nName = args.field("nf=",iFile)
102
+ nName = nName["names"].join(",") if nName
103
+ vName = args.field("vf=",iFile)
104
+ vName = vName["names"].join(",") if vName
105
+
106
+ distType = args.str("dist=")
107
+ unless ["exp","poisson","gauss","binom"].index(distType)
108
+ raise "`dist=' takes `exp',`poisson',`gauss' or `binom'"
109
+ end
110
+
111
+ burstScale = args.float("s=",2.0)
112
+ iProb = args.float("p=",0.6)
113
+ trial = args.float("n=")
114
+ var = args.float("v=")
115
+ param = args.float("param=")
116
+
117
+ if distType!="binom" and (trial or nName)
118
+ raise "`n=' or `nf=' is a parameter for binom burst."
119
+ end
120
+
121
+ if distType!="gauss" and (var or vName)
122
+ raise "`v=' or `vf=' is a parameter for gauss burst."
123
+ end
124
+
125
+ if distType=="binom"
126
+ if trial==nil and nName==nil
127
+ raise "`n=' or `nf=' have to be specified in binom burst."
128
+ end
129
+ if nName!=nil and not (param or pName)
130
+ raise "`param=' or `pf=' have to be specified with `nf=' in binom burst."
131
+ end
132
+ end
133
+
134
+ if distType=="gauss"
135
+ if (param!=nil and var==nil) or (param==nil and var!=nil)
136
+ raise "`param=' and `var=' have to be specified together in gaussian burst."
137
+ end
138
+ end
139
+
140
+ ##########################
141
+ module MDM
142
+
143
+ class DistBurst
144
+ attr_reader :data
145
+ attr_reader :burstSymbol
146
+
147
+ def initialize(name)
148
+ @name=name
149
+ @data=[]
150
+ @dpar=nil
151
+ @dpar=[] if @parFld
152
+ # 入力ファイルを項目別にメモリにセット
153
+ MCMD::Mcsvin.new("i=#{@fname}"){|csv|
154
+ csv.each{|flds|
155
+ v=flds[@valFld].to_f
156
+ p=flds[@parFld].to_f if @parFld
157
+ @data << v
158
+ @dpar << p if @parFld
159
+ }
160
+ }
161
+ # burst項目の出力シンボル。
162
+ # 状態0と状態1をburst項目として0,1として出力。
163
+ # このシンボル表を変更するのであれば継承クラスで独自に定義する。
164
+ @burstSymbol=["0","1"]
165
+ end
166
+
167
+ # 初期確率
168
+ # 2状態の確率分布のみ対応。それ以外は継承クラスで独自に定義する。
169
+ def initProbLn()
170
+ initProbLn=[ln(1.0), ln(0.0)]
171
+ return initProbLn
172
+ end
173
+
174
+ # 遷移確率
175
+ # 2状態の遷移確率のみ対応。それ以外は継承クラスで独自に定義する。
176
+ # to
177
+ # 0 1
178
+ # from 0 transProbLn[0][0] transProbLn[0][1]
179
+ # 1 transProbLn[1][0] transProbLn[1][1]
180
+ def calTransProbLn(inertiaProb)
181
+ transProbLn=[]
182
+ transProbLn << [ln( inertiaProb), ln(1.0-inertiaProb)]
183
+ transProbLn << [ln(1.0-inertiaProb), ln( inertiaProb)]
184
+ return transProbLn
185
+ end
186
+
187
+ # 自然対数の計算(ln(0)=-9999.0で定義
188
+ def ln(prob)
189
+ ret=-9999.0
190
+ if prob>0
191
+ ret=Math::log(prob)
192
+ end
193
+ return ret
194
+ end
195
+
196
+ def logsum(from,to)
197
+ sum=0.0
198
+ (from.to_i..to.to_i).each{|x|
199
+ sum+=Math::log(x)
200
+ }
201
+ return sum
202
+ end
203
+
204
+ def show(fpw=STDERR)
205
+ fpw.puts "### MDM::DistBurst class"
206
+ fpw.puts " 入力: #{@fname}, 値項目名:#{@valFld}"
207
+ fpw.puts " 確率(密度)関数名:#{@name}"
208
+ fpw.puts " データ件数: #{@data.size}"
209
+ fpw.puts " @data=#{@data.join(',')}"
210
+ end
211
+ end
212
+
213
+ #-----------------------------------------------------------
214
+ # 指数分布(事象発生間隔分布)
215
+ # λ: 時間あたりの事象の平均発生回数
216
+ # x: 事象の発生間隔
217
+ # f(x)=λe^{-λx}
218
+ class ExpBurst < DistBurst
219
+ def initialize(fname,valFld,parFld,param)
220
+ @fname =fname
221
+ @valFld =valFld
222
+ @parFld =parFld
223
+ @param =param
224
+ super("exp")
225
+
226
+ # パラメータのセット
227
+ # 定常状態平均到着数
228
+ @term=0.0
229
+ @data.each{|v| @term+=v}
230
+
231
+ unless @parFld
232
+ if @param!=nil
233
+ @lamda=param
234
+ else
235
+ @lamda=@data.size.to_f/@term
236
+ end
237
+ end
238
+ end
239
+
240
+ # 指数分布の確率密度関数: f(x)=λexp(-λx)
241
+ # log f(x) = logλ - λx
242
+ def probFunc(x,lamda)
243
+ return Math::log(lamda) - lamda*x
244
+ end
245
+
246
+ def stateProbLn(burstScale)
247
+ @burstScale=burstScale
248
+ stateProbLn=[]
249
+ (0...@data.size).each{|i|
250
+ x=@data[i]
251
+ p=nil
252
+ if @dpar
253
+ p=@dpar[i]
254
+ else
255
+ p=@lamda
256
+ end
257
+ stateProbLn << [ probFunc(x,p), probFunc(x,p*@burstScale) ]
258
+ }
259
+ return stateProbLn
260
+ end
261
+
262
+ def show(fpw=STDERR)
263
+ super(fpw)
264
+ fpw.puts "### MDM::ExpBurst < DistBurst class"
265
+ fpw.puts " @lamda: #{@lamda}, @param: #{@param}"
266
+ fpw.puts " @dpar: #{@dpar}"
267
+ fpw.puts " @term : #{@term}"
268
+ end
269
+ end
270
+
271
+ #-----------------------------------------------------------
272
+ # ポアソン分布(事象発生数分布)
273
+ # λ: 時間あたりの事象の平均発生回数
274
+ # x: 事象の発生間隔
275
+ # 確率関数: f(x)=λ^x*exp(-λ)/x!
276
+ class PoissonBurst < DistBurst
277
+ def initialize(fname,valFld,parFld,param)
278
+ @fname =fname
279
+ @valFld =valFld
280
+ @parFld =parFld
281
+ @param =param
282
+ super("poisson")
283
+
284
+ # パラメータのセット
285
+ # 定常状態平均到着数
286
+ @count=0.0
287
+ @data.each{|v| @count+=v}
288
+
289
+ unless @parFld
290
+ if @param!=nil
291
+ @lamda=param
292
+ else
293
+ @lamda=@count/@data.size.to_f
294
+ end
295
+ end
296
+ end
297
+
298
+ # ポアソン分布の確率関数
299
+ # f(x)=λ^x/x!*exp(-λ)
300
+ # log f(x) = x*logλ-λ-Σ_{i=1..x}i
301
+ def probFunc(x,lamda)
302
+ if x==0 # 0!=1のため
303
+ return -lamda
304
+ else
305
+ return x*Math::log(lamda) - Math::log((1.0+x)*x/2.0) - lamda
306
+ end
307
+ end
308
+
309
+ def stateProbLn(burstScale)
310
+ @burstScale=burstScale
311
+ stateProbLn=[]
312
+ (0...@data.size).each{|i|
313
+ x=@data[i]
314
+ p=nil
315
+ if @dpar
316
+ p=@dpar[i]
317
+ else
318
+ p=@lamda
319
+ end
320
+ stateProbLn << [ probFunc(x,p), probFunc(x,p*@burstScale) ]
321
+ }
322
+ return stateProbLn
323
+ end
324
+
325
+ def show(fpw=STDERR)
326
+ super(fpw)
327
+ fpw.puts "### MDM::PoissonBurst < DistBurst class"
328
+ fpw.puts " @lamda: #{@lamda}, @param: #{@param}"
329
+ fpw.puts " @dpar: #{@dpar}"
330
+ fpw.puts " @count: #{@count}"
331
+ end
332
+ end
333
+
334
+ #-----------------------------------------------------------
335
+ # 正規分布(誤差分布)
336
+ # mean: 平均
337
+ # var: 分散
338
+ # 確率密度関数: f(x)= 1/√2πσ^2 exp(-(x-μ)^2/2σ^2
339
+ class GaussBurst < DistBurst
340
+ def initialize(fname,valFld,parFld,param,varFld,var)
341
+ @fname =fname
342
+ @valFld =valFld
343
+ @parFld =parFld
344
+ @param =param
345
+ super("gauss")
346
+
347
+ # パラメータのセット
348
+ # 定常状態平均値と不偏分散
349
+ @mean=nil
350
+ @var=nil
351
+ if @parFld
352
+ @var=[]
353
+ # 分散項目読み込み
354
+ MCMD::Mcsvin.new("i=#{@fname}"){|csv|
355
+ csv.each{|flds|
356
+ v=flds[varFld].to_f
357
+ @var << v
358
+ }
359
+ }
360
+ else
361
+ if @param!=nil
362
+ @mean=@param
363
+ @var=var
364
+ else
365
+ @mean=0.0
366
+ @var=0.0
367
+ @data.each{|v| @mean+=v}
368
+ @mean/=@data.size.to_f
369
+ @data.each{|v| @var+=(v-@mean)**2}
370
+ @var/=(@data.size-1).to_f
371
+ end
372
+ end
373
+
374
+ # gauss分布burstでは、状態0,1,2を-1,0,1で出力
375
+ @burstSymbol=["-1","0","1"]
376
+ end
377
+
378
+ # 初期確率
379
+ def initProbLn()
380
+ initProbLn=[ln(0.0), ln(1.0), ln(0.0)]
381
+ return initProbLn
382
+ end
383
+
384
+ # 遷移確率
385
+ # to
386
+ # - 0 +
387
+ # - transProbLn[0][0] transProbLn[0][1] transProbLn[0][2]
388
+ # from 0 transProbLn[1][0] transProbLn[1][1] transProbLn[1][2]
389
+ # + transProbLn[2][0] transProbLn[2][1] transProbLn[2][2]
390
+ def calTransProbLn(inertiaProb)
391
+ transProbLn=[]
392
+ transProbLn << [ln( inertiaProb ), ln((1.0-inertiaProb)/3.0*2.0), ln((1.0-inertiaProb)/3.0)]
393
+ transProbLn << [ln((1.0-inertiaProb)/2.0), ln( inertiaProb ), ln((1.0-inertiaProb)/2.0)]
394
+ transProbLn << [ln((1.0-inertiaProb)/3.0), ln((1.0-inertiaProb)/3.0*2.0), ln( inertiaProb )]
395
+ return transProbLn
396
+ end
397
+
398
+ # 正規分布の確率密度関数
399
+ # f(x)= 1/√2πσ^2 exp(-(x-μ)^2/2σ^2
400
+ # log f(x) = log1 - (1/2)log(2πσ^2) - (x-u)^2/2σ^2
401
+ def probFunc(x, mu, sigma2)
402
+ return Math.log(1.0)-Math.log(2.0*Math::PI*sigma2)/2.0-((x-mu)**2.0)/(2.0*sigma2)
403
+ end
404
+
405
+ def stateProbLn(burstScale)
406
+ @burstScale=burstScale
407
+ stateProbLn=[]
408
+ (0...@data.size).each{|i|
409
+ x=@data[i]
410
+ p=nil
411
+ if @dpar
412
+ p=@dpar[i]
413
+ v=@var[i]
414
+ else
415
+ p=@mean
416
+ v=@var
417
+ end
418
+ stateProbLn << [ probFunc(x,p-Math.sqrt(v)*burstScale,v), probFunc(x,p,v), probFunc(x,p+Math.sqrt(v)*burstScale,v)]
419
+ }
420
+ return stateProbLn
421
+ end
422
+
423
+ def show(fpw=STDERR)
424
+ super(fpw)
425
+ fpw.puts "### MDM::GaussBurst < DistBurst class"
426
+ fpw.puts " @mean: #{@mean}, @param: #{@param}"
427
+ fpw.puts " @dpar: #{@dpar}"
428
+ fpw.puts " @var: #{@var}"
429
+ end
430
+ end
431
+
432
+ #-----------------------------------------------------------
433
+ # 二項分布(成功数分布)
434
+ # p: 成功確率
435
+ # x: 成功回数
436
+ # 確率関数: f(x)=nCx*p^x*(1-p)^(n-x)
437
+ class BinomBurst < DistBurst
438
+ def initialize(fname,valFld,parFld,param,tryFld,trial)
439
+ @fname =fname
440
+ @valFld =valFld
441
+ @parFld =parFld
442
+ @param =param
443
+ super("binom")
444
+
445
+ # パラメータのセット
446
+ # 定常状態平均成功数
447
+
448
+ @trial=nil
449
+ if tryFld
450
+ @trial=[]
451
+ MCMD::Mcsvin.new("i=#{@fname}"){|csv|
452
+ csv.each{|flds|
453
+ v=flds[tryFld].to_f
454
+ @trial << v
455
+ }
456
+ }
457
+ else
458
+ @trial=trial.to_f
459
+ end
460
+
461
+ @prob =nil
462
+ unless @parFld
463
+ if @param!=nil
464
+ @prob=param
465
+ else
466
+ avg=0.0
467
+ @data.each{|v| avg+=v}
468
+ avg=avg/@data.size.to_f
469
+ @prob=avg/@trial
470
+ end
471
+ end
472
+ end
473
+
474
+ # 二項分布の確率関数
475
+ # f(x)=nCx*p^x*(1-p)^(n-x)
476
+ # log f(x) = Σ_{i=n..n-x+1}log(i) - Σ_{i=x..1}log(i) + x*log(p) + (n-x)*log(1-p)
477
+ def probFunc(x,prob,trial)
478
+ return logsum(trial-x+1,trial) - logsum(1,x) + x*Math::log(prob)+(trial-x)*Math::log(1-prob)
479
+ end
480
+
481
+ def stateProbLn(burstScale)
482
+ @burstScale=burstScale
483
+ stateProbLn=[]
484
+ (0...@data.size).each{|i|
485
+ x=@data[i]
486
+ p=nil
487
+ if @dpar
488
+ p=@dpar[i]
489
+ else
490
+ p=@prob
491
+ end
492
+ if @trial.class.name=="Array"
493
+ n=@trial[i]
494
+ else
495
+ n=@trial
496
+ end
497
+ stateProbLn << [ probFunc(x,p,n), probFunc(x,@burstScale/((1.0-p)/p+@burstScale),n) ]
498
+ }
499
+ return stateProbLn
500
+ end
501
+
502
+ def show(fpw=STDERR)
503
+ super(fpw)
504
+ fpw.puts "### MDM::BinomBurst < DistBurst class"
505
+ fpw.puts " @prob: #{@mean}, @param: #{@param}"
506
+ fpw.puts " @dpar: #{@dpar}"
507
+ fpw.puts " @trial: #{@trial}"
508
+ end
509
+ end
510
+
511
+
512
+ #########################################################
513
+ # バーストクラス
514
+ #########################################################
515
+ class Burst
516
+
517
+ private
518
+
519
+ def initialize(dist)
520
+ @time=[] # メッセージの到着時刻
521
+ @interval=[] # メッセージの到着間隔(指数分布burstでのみ利用)
522
+ @count=[] # メッセージの到着件数(ポアソン分布burstでのみ利用)
523
+ @dist=dist # 分布オブジェクト(PoissonBurst, ExpBurst, GaussBurst, BinomBurst)
524
+ @stateSize = @dist.initProbLn().size # 状態数
525
+ @dataSize = @dist.data.size # 状態数
526
+ end
527
+
528
+ # ###############################
529
+ # 二次元配列の確保
530
+ def array2dim(rowSize,colSize)
531
+ array=Array.new(rowSize)
532
+ (0...rowSize).each{|i|
533
+ array[i] = Array.new(colSize)
534
+ }
535
+ return array
536
+ end
537
+
538
+ # ###############################
539
+ # 全stateからtargetStateへの尤度を計算し、最大尤度と最大尤度を達成するfrom state番号を返す。
540
+ def getMaxLike(targetState,prevLike,trans,prob)
541
+ maxLike=-99999999.0
542
+ maxFrom=nil
543
+ (0...@stateSize).each{|from|
544
+ #puts "from=#{from} prevLike[from]=#{prevLike[from]} trans[from][targetState]=#{trans[from][targetState]} prob[targetState]=#{prob[targetState]}"
545
+ # 時刻t-1における尤度+log(遷移確率)+log(状態確率)
546
+ like=prevLike[from]+trans[from][targetState]+prob[targetState]
547
+ if maxLike<like
548
+ maxLike=like
549
+ maxFrom=from
550
+ end
551
+ }
552
+ #puts "maxLike=#{maxLike} maxFrom=#{maxFrom}"
553
+ return maxLike,maxFrom
554
+ end
555
+
556
+ # ###############################
557
+ # viterbi forwardアルゴリズム
558
+ # initProbLn : 初期状態確率
559
+ # stateProbLn: 状態確率
560
+ # transProbLn: 状態遷移確率
561
+ def viterbi_fwd(initProbLn, stateProbLn, transProbLn)
562
+
563
+ # 各stateでの最小コストtransitionの計算実行
564
+ like =array2dim(@dataSize+1,@stateSize)
565
+ from =array2dim(@dataSize ,@stateSize)
566
+
567
+ # 初期状態セット
568
+ (0...@stateSize).each{|state|
569
+ like[0][state]=initProbLn[state]
570
+ }
571
+
572
+ # 初期状態が0なので1から始まる
573
+ (1..@dataSize).each{|t|
574
+ (0...@stateSize).each{|state|
575
+ # tは1から始まるのでfromと@stateProbLnはt-1となる: likeのみ0要素を持つ
576
+ like[t][state],from[t-1][state] = getMaxLike( state, like[t-1], @transProbLn, @stateProbLn[t-1])
577
+ }
578
+ }
579
+ return like,from
580
+ end
581
+
582
+ def getMaxState(like)
583
+ maxLike=-99999999.0
584
+ maxState=nil
585
+ (0...@stateSize).each{|state|
586
+ if maxLike<like[state]
587
+ maxLike=like[state]
588
+ maxState=state
589
+ end
590
+ }
591
+ maxState
592
+ end
593
+
594
+ # ###############################
595
+ # viterbi backwordアルゴリズム
596
+ def viterbi_bwd(like,from)
597
+ state=Array.new(@dataSize)
598
+
599
+ # 最終時刻における尤度最大のstate
600
+ state[@dataSize-1]=getMaxState(like.last)
601
+ (@dataSize-1).step(1,-1){|t|
602
+ state[t-1]=from[t][state[t]]
603
+ }
604
+ return state
605
+ end
606
+
607
+ public
608
+
609
+ def detect(inertiaProb,burstScale)
610
+ @burstScale = burstScale # burst状態のパラメータのスケールリング
611
+ @inertiaProb = inertiaProb # 同じ状態への遷移確率
612
+
613
+ # 初期状態ベクトル(状態数)の取得
614
+ @initProbLn=@dist.initProbLn()
615
+
616
+ # 状態確率行列(データ数×状態数)の取得
617
+ @stateProbLn=@dist.stateProbLn(@burstScale)
618
+
619
+ # 状態遷移行列(状態数×状態数)の取得
620
+ @transProbLn=@dist.calTransProbLn(@inertiaProb)
621
+
622
+ # viterbiアルゴリズムforward実行
623
+ @lLikely,@from=viterbi_fwd(@initProbLn,@stateProbLn,@transProbLn)
624
+
625
+ # viterbiアルゴリズムbackward実行
626
+ @state=viterbi_bwd(@lLikely,@from)
627
+ end
628
+
629
+ # CSVによる出力
630
+ # 入力データの末尾にburst項目を追加して出力
631
+ def output(iFile,oFile)
632
+ MCMD::Mcsvin.new("i=#{iFile} -array"){|iCsv|
633
+ File.open(oFile,"w"){|fpw|
634
+ fpw.puts "#{iCsv.names.join(',')},burst"
635
+ i=0
636
+ iCsv.each{|flds|
637
+ fpw.puts "#{flds.join(',')},#{@dist.burstSymbol[@state[i]]}"
638
+ i+=1
639
+ }
640
+ }
641
+ }
642
+ end
643
+
644
+ # debug出力
645
+ def show(fpw=STDERR)
646
+ fpw.puts "### MDM::Burst class"
647
+ fpw.puts " @burstScale: #{@burstScale}"
648
+ fpw.puts " log(初期状態確率):"
649
+ (0...@stateSize).each{|i|
650
+ fpw.puts " @initProbLn[#{i}]: #{@initProbLn[i]}"
651
+ }
652
+ fpw.puts " log(状態遷移確率): @inertiaProb: #{@inertiaProb}"
653
+ (0...@stateSize).each{|i|
654
+ (0...@stateSize).each{|j|
655
+ fpw.puts " @transProbLn[#{i}][#{j}]: #{@transProbLn[i][j]}"
656
+ @transProbLn
657
+ }
658
+ }
659
+
660
+ # 項目名表示
661
+ fpw.print ""
662
+ fpw.print " t\t"
663
+ fpw.print " val\t"
664
+ (0...@stateSize).each{|state| fpw.print "probLn#{state}\t"}
665
+ (0...@stateSize).each{|state| fpw.print "likeLn#{state}\t"}
666
+ (0...@stateSize).each{|state| fpw.print " from#{state}\t"}
667
+ fpw.print " state\t"
668
+ fpw.puts ""
669
+
670
+ # 初期尤度表示
671
+ (0...@stateSize+2).each{|i| fpw.print "\t"}
672
+ (0...@stateSize).each{|state| fpw.print sprintf("%7.1f\t",@lLikely[0][state])}
673
+ fpw.puts ""
674
+
675
+ # 期別尤度表示
676
+ (0...@dataSize).each{|i|
677
+ data =@dist.data[i]
678
+ stateProbLN=@stateProbLn[i]
679
+ lLikely=@lLikely[i+1]
680
+ from=@from[i]
681
+
682
+ fpw.print sprintf("%4d\t",i)
683
+ fpw.print sprintf("%7.3f\t",data)
684
+ (0...@stateSize).each{|state| fpw.print sprintf("%7.3f\t",stateProbLN[state])}
685
+ (0...@stateSize).each{|state| fpw.print sprintf("%7.3f\t",lLikely[state])}
686
+ (0...@stateSize).each{|state| fpw.print sprintf("%7d\t",from[state])}
687
+ fpw.print sprintf("%7s\t",@dist.burstSymbol[@state[i]])
688
+ fpw.print "\n"
689
+ }
690
+ end
691
+
692
+ end # class end
693
+
694
+ ########################## Module end
695
+ end
696
+
697
+ if distType=="exp"
698
+ dist=MDM::ExpBurst.new(iFile, fName, pName, param)
699
+ elsif distType=="poisson"
700
+ dist=MDM::PoissonBurst.new(iFile, fName, pName, param)
701
+ elsif distType=="gauss"
702
+ dist=MDM::GaussBurst.new(iFile, fName, pName, param, vName, var)
703
+ elsif distType=="binom"
704
+ dist=MDM::BinomBurst.new(iFile, fName, pName, param, nName, trial)
705
+ end
706
+
707
+ burst=MDM::Burst.new(dist)
708
+ burst.detect(iProb, burstScale)
709
+ burst.output(iFile,oFile)
710
+ if dFile
711
+ File.open(dFile,"w"){|fpw|
712
+ dist.show(fpw)
713
+ burst.show(fpw)
714
+ }
715
+ end
716
+