11/**
22 * STatistical INformation Grid-based method
3- * @deprecated Not implemented
43 */
54export default class STING {
65 // https://en.wikipedia.org/wiki/Cluster_analysis
76 // "STING : A Statistical Information Grid Approach to Spatial Data Mining"
8- constructor ( ) {
7+ /**
8+ * @param {number } c specified density
9+ */
10+ constructor ( c ) {
11+ this . _c = c
912 this . _cells = null
13+ this . _t = 0.05
1014 }
1115
1216 /**
@@ -24,14 +28,14 @@ export default class STING {
2428 ranges : ranges ,
2529 children : [ ] ,
2630 }
27- let stack = [ this . _cells ]
31+ let layer = [ this . _cells ]
2832 const spl_size = 2 ** dim
29- const average_number = 20
33+ const average_number = 5
3034 const max_depth = Math . log ( n / average_number ) / Math . log ( spl_size )
31- const cells = [ stack ]
35+ const cells = [ layer ]
3236 for ( let a = 0 ; a < max_depth ; a ++ ) {
3337 const new_stack = [ ]
34- for ( const c of stack ) {
38+ for ( const c of layer ) {
3539 const rng = c . ranges
3640 for ( let i = 0 ; i < spl_size ; i ++ ) {
3741 let p = i
@@ -53,53 +57,141 @@ export default class STING {
5357 c . children . push ( t )
5458 }
5559 }
56- stack = new_stack
57- cells . push ( stack )
60+ layer = new_stack
61+ cells . push ( layer )
62+ }
63+
64+ let bottomSpace = 1
65+ for ( let d = 0 ; d < dim ; d ++ ) {
66+ const range = layer [ 0 ] . ranges [ d ]
67+ bottomSpace *= range [ 1 ] - range [ 0 ]
5868 }
59- for ( let i = 0 ; i < stack . length ; i ++ ) {
60- const c = stack [ i ]
69+ for ( let i = 0 ; i < layer . length ; i ++ ) {
70+ const c = layer [ i ]
6171 const d = x . filter ( v => {
6272 return c . ranges . every ( ( r , i ) => r [ 0 ] <= v [ i ] && ( r [ 1 ] === maxs [ i ] ? v [ i ] <= r [ 1 ] : v [ i ] < r [ 1 ] ) )
6373 } )
64- const n = ( c . n = d . length )
65- const m = Array ( dim ) . fill ( 0 )
66- const min = ( c . min = Array ( dim ) . fill ( Infinity ) )
67- const max = ( c . max = Array ( dim ) . fill ( - Infinity ) )
68- for ( let j = 0 ; j < n ; j ++ ) {
74+ c . n = d . length
75+ c . min = Array ( dim ) . fill ( Infinity )
76+ c . max = Array ( dim ) . fill ( - Infinity )
77+ const sum = Array ( dim ) . fill ( 0 )
78+ for ( let j = 0 ; j < c . n ; j ++ ) {
6979 for ( let k = 0 ; k < dim ; k ++ ) {
70- m [ k ] += d [ j ] [ k ]
71- min [ k ] = Math . min ( min [ k ] , d [ j ] [ k ] )
72- max [ k ] = Math . max ( max [ k ] , d [ j ] [ k ] )
80+ sum [ k ] += d [ j ] [ k ]
81+ c . min [ k ] = Math . min ( c . min [ k ] , d [ j ] [ k ] )
82+ c . max [ k ] = Math . max ( c . max [ k ] , d [ j ] [ k ] )
7383 }
7484 }
75- c . m = m . map ( v => ( n > 0 ? v / n : 0 ) )
85+ c . m = sum . map ( v => ( c . n > 0 ? v / c . n : 0 ) )
7686 const s = Array ( dim ) . fill ( 0 )
77- for ( let j = 0 ; j < n ; j ++ ) {
87+ for ( let j = 0 ; j < c . n ; j ++ ) {
7888 for ( let k = 0 ; k < dim ; k ++ ) {
79- s [ k ] += ( d [ j ] [ k ] - m [ k ] ) ** 2
89+ s [ k ] += ( d [ j ] [ k ] - c . m [ k ] ) ** 2
8090 }
8191 }
82- c . s = s . map ( v => ( n > 0 ? Math . sqrt ( v / n ) : 0 ) )
92+ c . s = s . map ( v => ( c . n > 0 ? Math . sqrt ( v / c . n ) : 0 ) )
93+ c . dist = Array ( dim ) . fill ( 'normal' )
94+
95+ c . area = bottomSpace
8396 }
8497 for ( let k = cells . length - 2 ; k >= 0 ; k -- ) {
8598 for ( let i = 0 ; i < cells [ k ] . length ; i ++ ) {
86- let n = 0
87- const m = Array ( dim ) . fill ( 0 )
99+ let nki = 0
100+ let aki = 0
101+ const sum = Array ( dim ) . fill ( 0 )
88102 const min = ( cells [ k ] [ i ] . min = Array ( dim ) . fill ( Infinity ) )
89103 const max = ( cells [ k ] [ i ] . max = Array ( dim ) . fill ( - Infinity ) )
90104 const s = Array ( dim ) . fill ( 0 )
91- for ( const ccell of cells [ k + 1 ] . slice ( i * spl_size , ( i + 1 ) * spl_size ) ) {
92- n += ccell . n
105+ const ccells = cells [ k + 1 ] . slice ( i * spl_size , ( i + 1 ) * spl_size )
106+ for ( const ccell of ccells ) {
107+ nki += ccell . n
108+ aki += ccell . area
93109 for ( let p = 0 ; p < dim ; p ++ ) {
94- m [ p ] += ccell . m [ p ] * ccell . n
110+ sum [ p ] += ccell . m [ p ] * ccell . n
95111 min [ p ] = Math . min ( min [ p ] , ccell . min [ p ] )
96112 max [ p ] = Math . max ( max [ p ] , ccell . max [ p ] )
97113 s [ p ] += ( ccell . s [ p ] ** 2 + ccell . m [ p ] ** 2 ) * ccell . n
98114 }
99115 }
100- cells [ k ] [ i ] . n = n
101- cells [ k ] [ i ] . m = m . map ( v => ( n > 0 ? v / n : 0 ) )
102- cells [ k ] [ i ] . s = s . map ( ( v , p ) => ( n > 0 ? Math . sqrt ( v / n - m [ p ] ** 2 ) : 0 ) )
116+ cells [ k ] [ i ] . n = nki
117+ cells [ k ] [ i ] . m = sum . map ( v => ( nki > 0 ? v / nki : 0 ) )
118+ cells [ k ] [ i ] . s = s . map ( ( v , p ) => ( nki > 0 ? Math . sqrt ( v / nki - ( sum [ p ] / nki ) ** 2 ) : 0 ) )
119+ const eps = 0.1
120+ cells [ k ] [ i ] . dist = Array ( dim ) . fill ( 'normal' )
121+ cells [ k ] [ i ] . area = aki
122+ for ( let d = 0 ; d < dim ; d ++ ) {
123+ let confl = 0
124+ let dist = 'normal'
125+ for ( const ccell of ccells ) {
126+ let mdiff = 0
127+ let sdiff = 0
128+ if ( cells [ k ] [ i ] . m [ d ] !== 0 ) {
129+ mdiff += Math . abs ( ( cells [ k ] [ i ] . m [ d ] - ccell . m [ d ] ) / cells [ k ] [ i ] . m [ d ] )
130+ } else if ( ccell . m [ d ] !== 0 ) {
131+ mdiff += Math . abs ( ( cells [ k ] [ i ] . m [ d ] - ccell . m [ d ] ) / ccell . m [ d ] )
132+ }
133+ if ( cells [ k ] [ i ] . s [ d ] !== 0 ) {
134+ sdiff += Math . abs ( ( cells [ k ] [ i ] . s [ d ] - ccell . s [ d ] ) / cells [ k ] [ i ] . s [ d ] )
135+ } else if ( ccell . s [ d ] !== 0 ) {
136+ sdiff += Math . abs ( ( cells [ k ] [ i ] . s [ d ] - ccell . s [ d ] ) / ccell . s [ d ] )
137+ }
138+ if ( dist !== ccell . dist && mdiff < eps && sdiff < eps ) {
139+ confl += ccell . n
140+ } else if ( mdiff >= eps || sdiff >= eps ) {
141+ confl = nki
142+ }
143+ }
144+ if ( nki > 0 && confl / nki > this . _t ) {
145+ dist = 'none'
146+ }
147+ cells [ k ] [ i ] . dist [ d ] = dist
148+ }
149+ }
150+ }
151+
152+ let relevantCells = [ this . _cells ]
153+ for ( let k = 1 ; k < cells . length ; k ++ ) {
154+ const childRelevantCells = [ ]
155+ for ( let i = 0 ; i < relevantCells . length ; i ++ ) {
156+ for ( const child of relevantCells [ i ] . children ) {
157+ if ( child . n < child . area * this . _c ) {
158+ continue
159+ }
160+ childRelevantCells . push ( child )
161+ }
162+ }
163+ relevantCells = childRelevantCells
164+ }
165+
166+ this . _clusters = [ ]
167+ const stack = [ ]
168+ while ( true ) {
169+ if ( stack . length === 0 ) {
170+ if ( relevantCells . length === 0 ) {
171+ break
172+ }
173+ stack . push ( relevantCells . pop ( ) )
174+ this . _clusters . push ( [ ] )
175+ }
176+ const curcell = stack . pop ( )
177+ this . _clusters [ this . _clusters . length - 1 ] . push ( curcell )
178+
179+ for ( let k = relevantCells . length - 1 ; k >= 0 ; k -- ) {
180+ const c = relevantCells [ k ]
181+ let adjointCnt = 0
182+ for ( let d = 0 ; d < dim && adjointCnt < 2 ; d ++ ) {
183+ if ( curcell . ranges [ d ] [ 0 ] === c . ranges [ d ] [ 0 ] && curcell . ranges [ d ] [ 1 ] === c . ranges [ d ] [ 1 ] ) {
184+ continue
185+ } else if ( curcell . ranges [ d ] [ 0 ] === c . ranges [ d ] [ 1 ] || curcell . ranges [ d ] [ 1 ] === c . ranges [ d ] [ 0 ] ) {
186+ adjointCnt ++
187+ } else {
188+ adjointCnt = Infinity
189+ }
190+ }
191+ if ( adjointCnt === 1 ) {
192+ stack . push ( c )
193+ relevantCells . splice ( k , 1 )
194+ }
103195 }
104196 }
105197 }
@@ -109,5 +201,19 @@ export default class STING {
109201 * @param {Array<Array<number>> } datas Sample data
110202 * @returns {number[] } Predicted values
111203 */
112- predict ( datas ) { }
204+ predict ( datas ) {
205+ const p = [ ]
206+ for ( let i = 0 ; i < datas . length ; i ++ ) {
207+ p [ i ] = - 1
208+ for ( let k = 0 ; k < this . _clusters . length && p [ i ] < 0 ; k ++ ) {
209+ for ( const cell of this . _clusters [ k ] ) {
210+ if ( datas [ i ] . every ( ( v , d ) => cell . ranges [ d ] [ 0 ] <= v && v <= cell . ranges [ d ] [ 1 ] ) ) {
211+ p [ i ] = k
212+ break
213+ }
214+ }
215+ }
216+ }
217+ return p
218+ }
113219}
0 commit comments