Skip to content

Commit c561d1e

Browse files
committed
Added pearson correlation support for MPDist
1 parent 0938766 commit c561d1e

File tree

3 files changed

+56
-22
lines changed

3 files changed

+56
-22
lines changed

matrixprofile.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,34 @@ func applySingleAV(mp, ts []float64, w int, a av.AV) ([]float64, error) {
122122
// values must be between 0 and 1.
123123
func (mp MatrixProfile) ApplyAV() ([]float64, []float64, error) {
124124
var err error
125-
var abmp, bamp []float64
125+
abmp := make([]float64, len(mp.MP))
126+
bamp := make([]float64, len(mp.MPB))
126127

127-
abmp, err = applySingleAV(mp.MP, mp.A, mp.W, mp.AV)
128+
copy(abmp, mp.MP)
129+
copy(bamp, mp.MPB)
130+
if !mp.Opts.Euclidean {
131+
util.P2E(abmp, mp.W)
132+
util.P2E(bamp, mp.W)
133+
}
134+
135+
abmp, err = applySingleAV(abmp, mp.A, mp.W, mp.AV)
128136
if err != nil {
129137
return nil, nil, err
130138
}
131139

132140
if mp.MPB != nil {
133-
bamp, err = applySingleAV(mp.MPB, mp.B, mp.W, mp.AV)
141+
bamp, err = applySingleAV(bamp, mp.B, mp.W, mp.AV)
134142
}
135143

136144
if err != nil {
137145
return nil, nil, err
138146
}
147+
148+
if !mp.Opts.Euclidean {
149+
util.E2P(abmp, mp.W)
150+
util.E2P(bamp, mp.W)
151+
}
152+
139153
return abmp, bamp, nil
140154
}
141155

matrixprofile_test.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,41 @@ func TestNew(t *testing.T) {
4141
}
4242
}
4343

44-
func TestApplyAV(t *testing.T) {
45-
mprof := []float64{4, 6, 10, 2, 1, 0, 1, 2, 0, 0, 1, 2, 6}
46-
44+
func TestApplyAVDefault(t *testing.T) {
4745
testdata := []struct {
48-
a []float64
49-
w int
50-
av av.AV
51-
expectedMP []float64
46+
a []float64
47+
w int
5248
}{
53-
{[]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, 4, av.Default, mprof},
49+
{[]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, 4},
5450
}
5551

56-
var mp MatrixProfile
52+
var mp *MatrixProfile
5753
var err error
5854
var outab []float64
5955
for _, d := range testdata {
60-
newMP := make([]float64, len(mprof))
61-
copy(newMP, mprof)
62-
mp = MatrixProfile{A: d.a, W: d.w, MP: newMP, AV: d.av}
56+
mp, err = New(d.a, nil, d.w)
57+
if err != nil {
58+
t.Errorf("%v", err)
59+
break
60+
}
61+
if err = mp.Compute(NewMPOpts()); err != nil {
62+
t.Errorf("%v", err)
63+
break
64+
}
65+
66+
mp.AV = av.Default
6367
outab, _, err = mp.ApplyAV()
6468
if err != nil {
6569
t.Fatal(err)
6670
}
6771

68-
if len(outab) != len(d.expectedMP) {
69-
t.Errorf("Expected %d elements, but got %d, %+v", len(d.expectedMP), len(outab), d)
72+
if len(outab) != len(mp.MP) {
73+
t.Errorf("Expected %d elements, but got %d, %+v", len(mp.MP), len(outab), d)
7074
break
7175
}
7276
for i := 0; i < len(outab); i++ {
73-
if math.Abs(float64(outab[i]-d.expectedMP[i])) > 1e-7 {
74-
t.Errorf("Expected %v,\nbut got\n%v for %+v", d.expectedMP, outab, d)
77+
if math.Abs(float64(outab[i]-mp.MP[i])) > 1e-7 {
78+
t.Errorf("Expected %v,\nbut got\n%v for %+v", mp.MP, outab, d)
7579
break
7680
}
7781
}
@@ -775,7 +779,7 @@ func TestDiscoverDiscords(t *testing.T) {
775779
}
776780

777781
for _, d := range testdata {
778-
mp := MatrixProfile{A: a, B: a, W: w, MP: d.mp, AV: av.Default}
782+
mp := MatrixProfile{A: a, B: a, W: w, MP: d.mp, AV: av.Default, Opts: NewMPOpts()}
779783
discords, err := mp.DiscoverDiscords(d.k, d.exzone)
780784
if err != nil {
781785
t.Errorf("Got error %v on %v", err, d)

util/util.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,28 @@ func DiagBatchingScheme(l, p int) []Batch {
263263

264264
// P2E converts a slice of pearson correlation values to euclidean distances. This
265265
// is only valid for z-normalized time series.
266-
func P2E(mp []float64, m int) {
266+
func P2E(mp []float64, w int) {
267267
for i := 0; i < len(mp); i++ {
268268
// caps pearson correlation to 1 in case there are floating point accumulated errors
269269
if mp[i] > 1 {
270270
mp[i] = 1
271271
}
272-
mp[i] = math.Sqrt(2 * float64(m) * (1 - mp[i]))
272+
mp[i] = math.Sqrt(2 * float64(w) * (1 - mp[i]))
273+
}
274+
}
275+
276+
// E2P converts a slice of euclidean distances to pearson correlation values. This
277+
// is only valid for z-normalized time series. Negative pearson correlation values will not be
278+
// discovered
279+
func E2P(mp []float64, w int) {
280+
for i := 0; i < len(mp); i++ {
281+
mp[i] = 1 - mp[i]*mp[i]/(2*float64(w))
282+
// caps pearson correlation to 1 in case there are floating point accumulated errors
283+
if mp[i] > 1 {
284+
mp[i] = 1
285+
}
286+
if mp[i] < 0 {
287+
mp[i] = 0
288+
}
273289
}
274290
}

0 commit comments

Comments
 (0)